Changeset 2683995
- Timestamp:
- 02/23/2022 08:32:26 PM (4 years ago)
- Location:
- groups-for-membermouse
- Files:
-
- 50 added
- 5 edited
-
tags/2.1.3 (added)
-
tags/2.1.3/css (added)
-
tags/2.1.3/css/admin.css (added)
-
tags/2.1.3/css/groups-leader-dashboard.css (added)
-
tags/2.1.3/groups-for-membermouse.php (added)
-
tags/2.1.3/images (added)
-
tags/2.1.3/images/close.png (added)
-
tags/2.1.3/images/group_title_bg.png (added)
-
tags/2.1.3/images/loading.gif (added)
-
tags/2.1.3/images/pbar-animated.gif (added)
-
tags/2.1.3/includes (added)
-
tags/2.1.3/includes/activate_group.php (added)
-
tags/2.1.3/includes/add_group.php (added)
-
tags/2.1.3/includes/add_group_user.php (added)
-
tags/2.1.3/includes/cancel_group.php (added)
-
tags/2.1.3/includes/change_group_cost.php (added)
-
tags/2.1.3/includes/check_user.php (added)
-
tags/2.1.3/includes/check_username.php (added)
-
tags/2.1.3/includes/class.shortcodes.php (added)
-
tags/2.1.3/includes/config.php (added)
-
tags/2.1.3/includes/create_group.php (added)
-
tags/2.1.3/includes/create_group_leader.php (added)
-
tags/2.1.3/includes/delete_group.php (added)
-
tags/2.1.3/includes/delete_group_data.php (added)
-
tags/2.1.3/includes/delete_group_member.php (added)
-
tags/2.1.3/includes/docs.php (added)
-
tags/2.1.3/includes/edit_group.php (added)
-
tags/2.1.3/includes/edit_group_name.php (added)
-
tags/2.1.3/includes/group_leader_form.php (added)
-
tags/2.1.3/includes/import.php (added)
-
tags/2.1.3/includes/manage.php (added)
-
tags/2.1.3/includes/manage_groups.php (added)
-
tags/2.1.3/includes/manage_groups_admin.php (added)
-
tags/2.1.3/includes/purchase_link.php (added)
-
tags/2.1.3/includes/show_help_window.php (added)
-
tags/2.1.3/includes/show_purchase_link.php (added)
-
tags/2.1.3/includes/tabs.php (added)
-
tags/2.1.3/includes/templates (added)
-
tags/2.1.3/includes/templates/mm_group_template.csv (added)
-
tags/2.1.3/includes/update_group.php (added)
-
tags/2.1.3/includes/update_group_name.php (added)
-
tags/2.1.3/index.php (added)
-
tags/2.1.3/js (added)
-
tags/2.1.3/js/admin.js (added)
-
tags/2.1.3/js/checkout.js (added)
-
tags/2.1.3/js/groups-leader-dashboard.js (added)
-
tags/2.1.3/js/mm-group-import_wizard.js (added)
-
tags/2.1.3/readme.txt (added)
-
tags/2.1.3/templates (added)
-
tags/2.1.3/templates/mm_groups_import_template.csv (added)
-
trunk/css/groups-leader-dashboard.css (modified) (1 diff)
-
trunk/groups-for-membermouse.php (modified) (1 diff)
-
trunk/includes/class.shortcodes.php (modified) (6 diffs)
-
trunk/js/groups-leader-dashboard.js (modified) (2 diffs)
-
trunk/readme.txt (modified) (2 diffs)
Legend:
- Unmodified
- Added
- Removed
-
groups-for-membermouse/trunk/css/groups-leader-dashboard.css
r2642052 r2683995 44 44 margin: 0; 45 45 } 46 47 .search-input-container { 48 display: flex; 49 } 50 51 /* Styling for group leader table filters */ 52 .filter-header-wrapper.active, 53 .filter-header-wrapper.inactive { 54 display: flex; 55 justify-content: center; 56 align-items: center; 57 } 58 59 .filter-header { 60 /* display: flex; 61 justify-content: center; 62 align-items: center; */ 63 } 64 65 .filter-header-wrapper.order-asc:after, 66 .filter-header-wrapper.order-desc:after, 67 .filter-header-wrapper.order-none:after { 68 content: ' '; 69 position: relative; 70 margin-left: 13px; 71 border: 5px solid transparent; 72 } 73 74 .filter-header-wrapper.order-desc:after { 75 border-bottom-color: #333; 76 } 77 78 .filter-header-wrapper.order-asc:after { 79 border-top-color: #333; 80 } 81 82 .filter-header-wrapper.order-none:after { 83 border-bottom-color: transparent; 84 } 85 86 .filter-header-wrapper.order-none:hover:after { 87 border-top-color: #333; 88 } 89 90 .filter-header-wrapper:hover { 91 cursor: pointer; 92 } -
groups-for-membermouse/trunk/groups-for-membermouse.php
r2681090 r2683995 4 4 * Plugin Name: Groups for MemberMouse 5 5 * Description: Adds group support to MemberMouse. You can define different types of groups allowing a single customer to pay for multiple seats and members to join existing groups for free or for a price based on how you configure the group type. <strong>Requires MemberMouse to activate and use.</strong> 6 * Version: 2.1. 26 * Version: 2.1.3 7 7 * Author: Mintun Media 8 8 * Plugin URI: https://www.mintunmedia.com -
groups-for-membermouse/trunk/includes/class.shortcodes.php
r2681090 r2683995 42 42 43 43 // Ajax 44 add_action('wp_ajax_groups_load_members', array($this, 'ajax_load_members')); 44 45 add_action('wp_ajax_groups_get_signup_link', array($this, 'ajax_get_signup_link')); 45 46 add_action('wp_ajax_groups_update_group_name', array($this, 'ajax_update_group_name')); … … 81 82 public function generate_group_leader_dashboard($atts) { 82 83 global $wpdb, $current_user; 84 85 $search = $_GET["q"]; 86 $filter = $_GET["filter"]; 87 $order = $_GET["order"]; 83 88 84 89 $controls = array( … … 145 150 </div> 146 151 147 <div class="member-count"> 148 <p>Members: <?= $member_count ?>/<?= $group_size ?></p> 152 <!-- TODO create a JS action that refreshes the page & changes the query param for 'search'. --> 153 <div class="search-input-container"> 154 <input type="text" id="members-search-input" placeholder="Search Members by Email or Name" aria-placeholder="Search Members by Email or Name" value="<?php echo $search; ?>"> 155 <button id="members-search" class="btn btn-primary">Search</button> 156 <button id="clear-search" class="btn btn-primary">Clear</button> 149 157 </div> 150 158 … … 152 160 <p><em>No members found.</em></p> 153 161 <?php } else { ?> 162 <?php 163 164 $gMemResultsData = array(); 165 foreach ($gMemResults as $gMemRes) { 166 $userSql = "SELECT * FROM " . $wpdb->prefix . "users WHERE ID = '" . $gMemRes->member_id . "'"; 167 $userResult = $wpdb->get_row($userSql); 168 $registered = $userResult->user_registered; 169 $memSql = "SELECT * FROM mm_user_data WHERE wp_user_id = '" . $gMemRes->member_id . "'"; 170 $memResult = $wpdb->get_row($memSql); 171 $firstName = $memResult->first_name; 172 $lastName = $memResult->last_name; 173 $email = $userResult->user_email; 174 $phone = empty($memResult->phone) ? "—" : $memResult->phone; 175 $membershipId = $memResult->membership_level_id; 176 $levelSql = "SELECT name FROM mm_membership_levels WHERE id = '" . $membershipId . "'"; 177 $levelResult = $wpdb->get_row($levelSql); 178 $redirecturl = ""; 179 $crntMemberId = $gMemRes->member_id; 180 $member = new MM_User($crntMemberId); 181 $url = "javascript:mmjs.changeMembershipStatus('" . $crntMemberId . "', "; 182 $url .= $membershipId . ", " . MM_Status::$CANCELED . ", '" . $redirecturl . "');"; 183 $cancellationHtml = "<a title=\"Cancel Member\" style=\"cursor: pointer;display: none;\" onclick=\"" . $url . "\"/>" . MM_Utils::getIcon('stop', 'red', '1.2em', '1px') . "</a>"; 184 $statusId = (int) $gMemRes->member_status; 185 186 // Get Member's Active Subscriptions - includes overdue subscriptions 187 $activeSubscriptions = $member->getActiveMembershipSubscriptions(true); 188 189 if (empty($activeSubscriptions)) { 190 // No Subscriptions 191 $has_subscriptions = false; 192 } else { 193 $has_subscriptions = true; 194 } 195 196 switch ($statusId) { 197 case 1: 198 $status = "Active"; 199 break; 200 case 0: 201 $status = "Deactivated"; 202 break; 203 } 204 205 array_push( 206 $gMemResultsData, 207 array( 208 'member_id' => $gMemRes->member_id, 209 'membership_id' => $membershipId, 210 'name' => "$firstName $lastName", 211 'first_name' => $firstName, 212 'last_name' => $lastName, 213 'email' => $email, 214 'phone' => $phone, 215 'registered' => $registered, 216 'status' => $status, 217 'status_id' => $statusId, 218 'has_subscriptions' => $has_subscriptions, 219 'cancellation_html' => $cancellationHtml, 220 'cancel_url' => $url 221 ) 222 ); 223 } 224 225 226 // 1. Run search query if there is one. 227 // 2. Then sort all results by filter and order. 228 $filteredData = $gMemResultsData; 229 230 if (!empty($filter) && !empty($order)) { 231 $filteredData = $this->filter_member_results($gMemResultsData, $filter, $order); 232 } 233 234 if (!empty($search)) { 235 $filteredData = $this->search_member_results($filteredData, $search); 236 } 237 ?> 238 239 <div class="member-count"> 240 <p>Members: <?= sizeof($filteredData) ?>/<?= $group_size ?></p> 241 </div> 242 243 <?php if (!empty($search)) : ?> 244 <div class="search-result-notif"> 245 <h3>Search Results for <span class="query">"<?php echo $search ?>"</span></h3> 246 </div> 247 <?php endif; ?> 248 154 249 <table class="widefat" id="mm-data-grid" style="width:96%"> 155 250 <thead> 156 251 <tr> 157 <th>Name</th> 158 <th>Email</th> 252 <th> 253 <div class="<?php echo $this->filter_header_class($filter, 'name', $order); ?>" data-filter="name">Name</div> 254 </th> 255 <th> 256 <div class="<?php echo $this->filter_header_class($filter, 'email', $order); ?>" data-filter="email">Email</div> 257 </th> 159 258 <th>Phone</th> 160 <th>Registered</th> 161 <th>Status</th> 259 <th> 260 <div class="<?php echo $this->filter_header_class($filter, 'registered', $order); ?>" data-filter="registered">Registered</div> 261 </th> 262 <th> 263 <div class="<?php echo $this->filter_header_class($filter, 'status', $order); ?>" data-filter="status">Status</div> 264 </th> 162 265 <?php if ($action_control != 'hide') { 163 266 echo $action_header_content; … … 166 269 </thead> 167 270 <tbody> 168 <?php foreach ($gMemResults as $gMemRes) : 169 $userSql = "SELECT * FROM " . $wpdb->prefix . "users WHERE ID = '" . $gMemRes->member_id . "'"; 170 $userResult = $wpdb->get_row($userSql); 171 $registered = $userResult->user_registered; 172 $memSql = "SELECT * FROM mm_user_data WHERE wp_user_id = '" . $gMemRes->member_id . "'"; 173 $memResult = $wpdb->get_row($memSql); 174 $firstName = $memResult->first_name; 175 $lastName = $memResult->last_name; 176 $email = $userResult->user_email; 177 $phone = empty($memResult->phone) ? "—" : $memResult->phone; 178 $membershipId = $memResult->membership_level_id; 179 $levelSql = "SELECT name FROM mm_membership_levels WHERE id = '" . $membershipId . "'"; 180 $levelResult = $wpdb->get_row($levelSql); 271 <?php foreach ($filteredData as $member) : 181 272 $redirecturl = ""; 182 $crntMemberId = $gMemRes->member_id; 183 $member = new MM_User($crntMemberId); 184 $url = "javascript:mmjs.changeMembershipStatus('" . $crntMemberId . "', "; 185 $url .= $membershipId . ", " . MM_Status::$CANCELED . ", '" . $redirecturl . "');"; 273 $url = "javascript:mmjs.changeMembershipStatus('" . $member['member_id'] . "', "; 274 $url .= $member['membership_id'] . ", " . MM_Status::$CANCELED . ", '" . $redirecturl . "');"; 186 275 $cancellationHtml = "<a title=\"Cancel Member\" style=\"cursor: pointer;display: none;\" onclick=\"" . $url . "\"/>" . MM_Utils::getIcon('stop', 'red', '1.2em', '1px') . "</a>"; 187 $statusId = (int) $gMemRes->member_status;188 189 // Get Member's Active Subscriptions - includes overdue subscriptions190 $activeSubscriptions = $member->getActiveMembershipSubscriptions(true);191 192 if (empty($activeSubscriptions)) {193 // No Subscriptions194 $has_subscriptions = false;195 } else {196 $has_subscriptions = true;197 }198 199 switch ($statusId) {200 case 1:201 $status = "Active";202 break;203 case 0:204 $status = "Deactivated";205 break;206 }207 276 208 277 ?> 209 <tr class="<?= strtolower($ status) ?>">210 <td><?php echo $ firstName . ' ' . $lastName; ?></td>211 <td><?php echo $ email; ?></td>212 <td><?php echo $ phone; ?></td>213 <td><?php echo date('F d, Y h:m a', strtotime($ registered)); ?></td>214 <td><?= $ status; ?></td>278 <tr class="<?= strtolower($member->status) ?>"> 279 <td><?php echo $member['name']; ?></td> 280 <td><?php echo $member['email']; ?></td> 281 <td><?php echo $member['phone']; ?></td> 282 <td><?php echo date('F d, Y h:m a', strtotime($member['registered'])); ?></td> 283 <td><?= $member['status']; ?></td> 215 284 <?php if ($action_control != 'hide') { ?> 216 285 <td> 217 286 <?php 218 if ($ has_subscriptions) {287 if ($member['has_subscriptions']) { 219 288 // Member has active subscriptions. Show error 220 289 echo $cancellationHtml; 221 290 echo MM_Utils::getDeleteIcon("This member has an active paid membership which must be canceled before they can be removed from the group. Please contact support.", 'margin-left:5px;', '', true); 222 291 } else if ($statusId === 1) { 223 $deleteActionUrl = 'href="#" class="delete-member" data-member-id="' . $ gMemRes->member_id . '" data-name="' . $firstName . ' ' . $lastName. '"';292 $deleteActionUrl = 'href="#" class="delete-member" data-member-id="' . $member['member_id'] . '" data-name="' . $member['first_name'] . ' ' . $member['last_name'] . '"'; 224 293 echo MM_Utils::getDeleteIcon("Remove the member from this group", 'margin-left:5px;', $deleteActionUrl); 225 294 } … … 279 348 } 280 349 350 /** 351 * Searches through the member results for a relatable match. 352 */ 353 public function search_member_results($results, $query) { 354 return array_filter($results, function ($result) use ($query) { 355 $name_match = strpos( 356 strtolower($result['name']), 357 strtolower($query) 358 ); 359 360 $email_match = strpos( 361 strtolower($result['email']), 362 strtolower($query) 363 ); 364 365 return ($name_match !== false || $email_match !== false); 366 }); 367 } 368 369 /** 370 * Creates a class string for a Filter Header on the Leader Table. 371 * 372 * $currentFilter (optional) 373 * 374 * @return string 375 */ 376 public function filter_header_class($currentFilter, $filterHeader, $order) { 377 $class = "filter-header-wrapper"; 378 if ($currentFilter == $filterHeader) { 379 $order_lower = strtolower($order); 380 $class = "$class active order-$order_lower"; 381 } else { 382 $class = "$class inactive order-none"; 383 } 384 return $class; 385 } 386 387 /** 388 * Filter member results based on filter and order given. 389 * 390 * @return array 391 */ 392 public function filter_member_results($data, $filter, $order) { 393 $sorted_data = $data; 394 395 if ($order == 'ASC') { 396 $sort = usort($sorted_data, function ($item1, $item2) use ($filter) { 397 return $item1[$filter] <=> $item2[$filter]; 398 }); 399 } else { 400 $sort = usort($sorted_data, function ($item1, $item2) use ($filter) { 401 return $item2[$filter] <=> $item1[$filter]; 402 }); 403 } 404 405 if ($sort) { 406 return $sorted_data; 407 } else { 408 return $data; 409 } 410 } 281 411 282 412 /** -
groups-for-membermouse/trunk/js/groups-leader-dashboard.js
r2642052 r2683995 9 9 const $groupSignupLinkTrigger = $('#signup-link'); 10 10 const $addMemberTrigger = $('#add-member'); 11 const $clearSearchTrigger = $("#clear-search"); 11 12 let $deleteMemberTrigger = $('.delete-member'); 13 14 let $filterHeaderTrigger = $('.filter-header-wrapper'); 15 let $searchTrigger = $('#members-search'); 16 let $searchInput = $('#members-search-input'); 12 17 13 18 $groupSignupLinkTrigger.click(openSignUpLinkPop); … … 15 20 $addMemberTrigger.click(openAddMemberPop); 16 21 $deleteMemberTrigger.click(openDeleteMemberPop); 22 $filterHeaderTrigger.click(changeMemberFilter); 23 $searchTrigger.on('click', searchMembers); 24 $clearSearchTrigger.on('click', clearSearch); 25 26 /** 27 * Refreshes the page and changes the member filter. 28 * When pressing a filter link, the order is as follows: 29 * No filter -> ASC filter -> DESC filter -> Reset to No Filter 30 */ 31 function changeMemberFilter() { 32 let selectedFilter = $(this).data('filter'); 33 let params = (new URL(document.location)).searchParams; 34 let newOrder = null; 35 let currentFilter = null; 36 37 if (params.has('filter')) { 38 let currentFilter = params.get('filter'); 39 if (currentFilter !== selectedFilter) { 40 params.delete('order'); 41 } 42 } 43 44 if (params.has('order')) { 45 let order = params.get('order'); 46 if (order === 'ASC') { 47 newOrder = 'DESC'; 48 } 49 50 if (order === 'DESC') { 51 newOrder = null; 52 } 53 } else { 54 newOrder = 'ASC'; 55 } 56 57 params.set('filter', $(this).data('filter')); 58 59 if (newOrder != null) { 60 params.set('order', newOrder); 61 } else { 62 params.delete('order'); 63 params.delete('filter'); 64 } 65 66 location.search = params.toString(); 67 } 68 69 /** 70 * Refreshes the page to run a search query. 71 */ 72 function searchMembers() { 73 let searchQuery = $searchInput.val(); 74 let params = (new URL(document.location)).searchParams; 75 params.set('q', searchQuery); 76 location.search = params.toString(); 77 } 78 79 /** 80 * Clears the search results. 81 */ 82 function clearSearch() { 83 let params = (new URL(document.location)).searchParams; 84 if (params.has('q')) { 85 params.delete('q'); 86 location.search = params.toString(); 87 } 88 } 17 89 18 90 -
groups-for-membermouse/trunk/readme.txt
r2681090 r2683995 3 3 Tags: membermouse, member management, membership site, groups, mm groups, groups for membermouse, membermouse groups 4 4 Requires at least: 4.8 5 Tested up to: 5. 8.25 Tested up to: 5.9 6 6 Requires PHP: 5.6 7 7 Stable tag: trunk … … 69 69 70 70 == Changelog == 71 * 2.1.2 71 2.1.3 72 - ENHANCEMENT: Added Filtering and sorting functionality to Group Leader Dashboard 73 74 2.1.2 72 75 - ENHANCEMENT: Updated group leader dashboard shortcode to allow showing/hiding elements. Updated 73 76 - ENHANCEMENT: Added a View Only member dashboard shortcode visible by members
Note: See TracChangeset
for help on using the changeset viewer.