← All changes
|
includes/admin/customers/class-wpsc-customers.php
+138
-56
3.4.7
→
3.5.4
View file →
| @@ -69,27 +69,40 @@ | ||
| 69 | 69 | <div id="wpsc-container"> |
| 70 | 70 | <div class="wpsc-setting-header"> |
| 71 | 71 | <h2><?php esc_attr_e( 'Customers', 'supportcandy' ); ?></h2> |
| 72 | 72 | </div> |
| 73 | - <div class="wpsc-setting-section-body"> | |
| 74 | - <div class="wpsc-feedback-filter-container"> | |
| 75 | - <div class="wpsc-filter-container"> | |
| 76 | - <div class="wpsc-filter-item" style="min-width: 200px;"> | |
| 77 | - <select name="wpsc-cust-list-filter" id="wpsc-cust-list-filter"> | |
| 78 | - <?php | |
| 79 | - foreach ( $types as $key => $type ) { | |
| 80 | - $selected = 'selected="selected"'; | |
| 81 | - ?> | |
| 82 | - <option <?php echo esc_attr( $selected ); ?> value="<?php echo esc_attr( $key ); ?>"><?php echo esc_attr( $type ); ?></option> | |
| 83 | - <?php | |
| 84 | - } | |
| 85 | - ?> | |
| 86 | - </select> | |
| 87 | - </div> | |
| 88 | - <div class="wpsc-filter-item" style="min-width: 250px;"> | |
| 89 | - <input type="text" id="wpsc-cust-filter-search" placeholder="<?php esc_attr_e( 'Search...', 'supportcandy' ); ?>"> | |
| 90 | - </div> | |
| 73 | + <div class="wpsc-setting-section-body"> | |
| 74 | + <div class="wpsc-customers-toolbar"> | |
| 75 | + | |
| 76 | + <div class="wpsc-customers-toolbar-item"> | |
| 77 | + <label><?php esc_attr_e( 'Users', 'supportcandy' ); ?></label> | |
| 78 | + <select name="wpsc-cust-list-filter" id="wpsc-cust-list-filter"> | |
| 79 | + <?php foreach ( $types as $key => $type ) : ?> | |
| 80 | + <option value="<?php echo esc_attr( $key ); ?>" <?php selected( $key, 'customer_with_tickets' ); ?>><?php echo esc_attr( $type ); ?></option> | |
| 81 | + <?php endforeach; ?> | |
| 82 | + </select> | |
| 91 | 83 | </div> |
| 84 | + | |
| 85 | + <div class="wpsc-customers-toolbar-item"> | |
| 86 | + <label><?php esc_attr_e( 'User Type', 'supportcandy' ); ?></label> | |
| 87 | + <select id="wpsc-cust-type-filter"> | |
| 88 | + <option value="all"><?php esc_attr_e( 'All types', 'supportcandy' ); ?></option> | |
| 89 | + <option value="registered"><?php esc_attr_e( 'Registered', 'supportcandy' ); ?></option> | |
| 90 | + <option value="guest"><?php esc_attr_e( 'Guest', 'supportcandy' ); ?></option> | |
| 91 | + </select> | |
| 92 | + </div> | |
| 93 | + | |
| 94 | + <div class="wpsc-customers-toolbar-item wpsc-customers-toolbar-search"> | |
| 95 | + <label><?php esc_attr_e( 'Search', 'supportcandy' ); ?></label> | |
| 96 | + <input type="text" id="wpsc-cust-filter-search" autocomplete="off" placeholder="<?php esc_attr_e( 'Search...', 'supportcandy' ); ?>"> | |
| 97 | + </div> | |
| 98 | + | |
| 99 | + <div class="wpsc-customers-toolbar-item wpsc-customers-toolbar-reset"> | |
| 100 | + <button type="button" class="wpsc-button normal secondary" id="wpsc-cust-reset-filter"> | |
| 101 | + <?php esc_attr_e( 'Reset', 'supportcandy' ); ?> | |
| 102 | + </button> | |
| 103 | + </div> | |
| 104 | + | |
| 92 | 105 | </div> |
| 93 | 106 | <?php |
| 94 | 107 | self::load_customer_list(); |
| 95 | 108 | WPSC_Tickets::load_html_snippets(); |
| @@ -121,19 +134,20 @@ | ||
| 121 | 134 | </thead> |
| 122 | 135 | </table> |
| 123 | 136 | </div> |
| 124 | 137 | <script> |
| 125 | - function load_customer_list(custType) { | |
| 138 | + function load_customer_list(custType, userType) { | |
| 126 | 139 | |
| 127 | 140 | jQuery('.wpsc_customer_list').dataTable({ |
| 128 | 141 | processing: true, |
| 129 | 142 | serverSide: true, |
| 130 | 143 | serverMethod: 'post', |
| 131 | - ajax: { | |
| 144 | + ajax: { | |
| 132 | 145 | url: supportcandy.ajax_url, |
| 133 | 146 | data: { |
| 134 | 147 | 'action': 'wpsc_get_customer_list', |
| 135 | 148 | 'cust_type': custType, |
| 149 | + 'user_type': userType, | |
| 136 | 150 | '_ajax_nonce': '<?php echo esc_attr( wp_create_nonce( 'wpsc_get_customer_list' ) ); ?>' |
| 137 | 151 | } |
| 138 | 152 | }, |
| 139 | 153 | 'columns': [ |
| @@ -144,13 +158,15 @@ | ||
| 144 | 158 | { data: 'actions' }, |
| 145 | 159 | ], |
| 146 | 160 | 'bDestroy': true, |
| 147 | 161 | 'searching': true, |
| 148 | - 'ordering': false, | |
| 162 | + 'ordering': true, | |
| 163 | + order: [[ 3, 'desc' ]], | |
| 149 | 164 | 'bLengthChange': false, |
| 150 | 165 | pageLength: 20, |
| 151 | - columnDefs: [ | |
| 166 | + columnDefs: [ | |
| 152 | 167 | { targets: '_all', className: 'dt-left' }, |
| 168 | + { targets: [ 0, 1, 2, 4 ], orderable: false }, | |
| 153 | 169 | ], |
| 154 | 170 | language: supportcandy.translations.datatables |
| 155 | 171 | }); |
| 156 | 172 | } |
| @@ -156,19 +172,28 @@ | ||
| 156 | 172 | } |
| 157 | 173 | |
| 158 | 174 | jQuery(document).ready(function() { |
| 159 | 175 | |
| 160 | - load_customer_list('customer_with_tickets'); | |
| 176 | + jQuery('#wpsc-cust-list-filter').selectWoo({ minimumResultsForSearch: 0, width: '100%' }); | |
| 177 | + jQuery('#wpsc-cust-type-filter').selectWoo({ minimumResultsForSearch: 0, width: '100%' }); | |
| 161 | 178 | |
| 179 | + load_customer_list('customer_with_tickets', 'all'); | |
| 180 | + | |
| 162 | 181 | jQuery('#wpsc-cust-filter-search').on('keyup', function() { |
| 163 | 182 | var searchTerm = jQuery(this).val(); |
| 164 | 183 | jQuery('table.wpsc_customer_list').DataTable().search(searchTerm).draw(); |
| 165 | 184 | }); |
| 166 | 185 | |
| 167 | - jQuery('#wpsc-cust-list-filter').on('change', function(){ | |
| 168 | - var custType = jQuery(this).val(); | |
| 169 | - load_customer_list(custType); | |
| 186 | + jQuery('#wpsc-cust-list-filter, #wpsc-cust-type-filter').on('change', function(){ | |
| 187 | + load_customer_list( jQuery('#wpsc-cust-list-filter').val(), jQuery('#wpsc-cust-type-filter').val() ); | |
| 170 | 188 | }); |
| 189 | + | |
| 190 | + jQuery('#wpsc-cust-reset-filter').on('click', function() { | |
| 191 | + jQuery('#wpsc-cust-list-filter').val('customer_with_tickets').trigger('change.select2'); | |
| 192 | + jQuery('#wpsc-cust-type-filter').val('all').trigger('change.select2'); | |
| 193 | + jQuery('#wpsc-cust-filter-search').val(''); | |
| 194 | + load_customer_list('customer_with_tickets', 'all'); | |
| 195 | + }); | |
| 171 | 196 | }); |
| 172 | 197 | |
| 173 | 198 | <?php do_action( 'wpsc_js_customer_list_functions' ); ?> |
| 174 | 199 | </script> |
| @@ -196,14 +221,39 @@ | ||
| 196 | 221 | $rowperpage = isset( $_POST['length'] ) ? intval( $_POST['length'] ) : 20; |
| 197 | 222 | $page_no = ( $start / $rowperpage ) + 1; |
| 198 | 223 | $cust_type = isset( $_POST['cust_type'] ) ? sanitize_text_field( wp_unslash( $_POST['cust_type'] ) ) : 'customer_with_tickets'; |
| 199 | 224 | |
| 225 | + $user_type = isset( $_POST['user_type'] ) ? sanitize_text_field( wp_unslash( $_POST['user_type'] ) ) : 'all'; | |
| 226 | + if ( ! in_array( $user_type, array( 'all', 'guest', 'registered' ), true ) ) { | |
| 227 | + $user_type = 'all'; | |
| 228 | + } | |
| 229 | + | |
| 230 | + // Whitelisted map of sortable DataTables column index to actual DB column - only | |
| 231 | + // "Number of tickets" is backed by a real, sortable query column. | |
| 232 | + $sortable_columns = array( | |
| 233 | + 3 => 'ticket_count', | |
| 234 | + ); | |
| 235 | + | |
| 236 | + $orderby = 'ticket_count'; | |
| 237 | + $order = 'DESC'; | |
| 238 | + | |
| 239 | + if ( isset( $_POST['order'][0]['column'] ) ) { | |
| 240 | + $order_column = intval( $_POST['order'][0]['column'] ); | |
| 241 | + if ( isset( $sortable_columns[ $order_column ] ) ) { | |
| 242 | + $orderby = $sortable_columns[ $order_column ]; | |
| 243 | + } | |
| 244 | + } | |
| 245 | + | |
| 246 | + if ( isset( $_POST['order'][0]['dir'] ) && 'asc' === strtolower( sanitize_text_field( wp_unslash( $_POST['order'][0]['dir'] ) ) ) ) { | |
| 247 | + $order = 'ASC'; | |
| 248 | + } | |
| 249 | + | |
| 200 | 250 | $args = array( |
| 201 | 251 | 'search' => $search, |
| 202 | 252 | 'items_per_page' => $rowperpage, |
| 203 | 253 | 'page_no' => $page_no, |
| 204 | - 'orderby' => 'ticket_count', | |
| 205 | - 'order' => 'DESC', | |
| 254 | + 'orderby' => $orderby, | |
| 255 | + 'order' => $order, | |
| 206 | 256 | 'meta_query' => array( |
| 207 | 257 | 'relation' => 'AND', |
| 208 | 258 | ), |
| 209 | 259 | ); |
| @@ -221,8 +271,22 @@ | ||
| 221 | 271 | |
| 222 | 272 | $args['meta_query'][] = array(); |
| 223 | 273 | } |
| 224 | 274 | |
| 275 | + if ( 'guest' === $user_type ) { | |
| 276 | + $args['meta_query'][] = array( | |
| 277 | + 'slug' => 'user', | |
| 278 | + 'compare' => '=', | |
| 279 | + 'val' => 0, | |
| 280 | + ); | |
| 281 | + } elseif ( 'registered' === $user_type ) { | |
| 282 | + $args['meta_query'][] = array( | |
| 283 | + 'slug' => 'user', | |
| 284 | + 'compare' => '>', | |
| 285 | + 'val' => 0, | |
| 286 | + ); | |
| 287 | + } | |
| 288 | + | |
| 225 | 289 | $args = apply_filters( 'wpsc_get_customer_list_filters', $args, $cust_type ); |
| 226 | 290 | $response = WPSC_Customer::find( $args ); |
| 227 | 291 | |
| 228 | 292 | $customers = $response['results']; |
| @@ -253,10 +317,15 @@ | ||
| 253 | 317 | ?> |
| 254 | 318 | <?php |
| 255 | 319 | $actions = ob_get_clean(); |
| 256 | 320 | |
| 321 | + $name_cell = '<div class="wpsc-cust-name-cell"> | |
| 322 | + <div class="wpsc-cust-avatar">' . get_avatar( $customer->email, 28 ) . '</div> | |
| 323 | + <span class="wpsc-link" onclick="wpsc_view_customer_detailed_info( ' . $customer->id . ', \'' . wp_create_nonce( 'wpsc_view_customer_detailed_info' ) . '\' )">' . esc_html( $customer->name ) . '</span> | |
| 324 | + </div>'; | |
| 325 | + | |
| 257 | 326 | $data[] = array( |
| 258 | - 'name' => '<span class="wpsc-link" onclick="wpsc_view_customer_detailed_info( ' . $customer->id . ', \'' . wp_create_nonce( 'wpsc_view_customer_detailed_info' ) . '\' )">' . esc_html( $customer->name ) . '</span>', | |
| 327 | + 'name' => $name_cell, | |
| 259 | 328 | 'email' => $customer->email, |
| 260 | 329 | 'type' => ! is_object( $customer->user ) ? esc_attr__( 'Guest', 'supportcandy' ) : esc_attr__( 'Registered', 'supportcandy' ), |
| 261 | 330 | 'tickets' => $customer->ticket_count, |
| 262 | 331 | 'actions' => $actions, |
| @@ -683,9 +752,9 @@ | ||
| 683 | 752 | * @return void |
| 684 | 753 | */ |
| 685 | 754 | public static function customer_ticket_count_after_ticket_merge( $prev_ticket, $new_ticket ) { |
| 686 | 755 | |
| 687 | - if ( empty( $prev_ticket->customer ) ) { | |
| 756 | + if ( ! $prev_ticket->customer ) { | |
| 688 | 757 | return; |
| 689 | 758 | } |
| 690 | 759 | |
| 691 | 760 | $customer = $prev_ticket->customer; |
| @@ -693,9 +762,9 @@ | ||
| 693 | 762 | if ( ! is_object( $customer ) ) { |
| 694 | 763 | $customer = new WPSC_Customer( $customer ); |
| 695 | 764 | } |
| 696 | 765 | |
| 697 | - if ( isset( $customer->id ) && method_exists( $customer, 'update_ticket_count' ) ) { | |
| 766 | + if ( $customer->id ) { | |
| 698 | 767 | $customer->update_ticket_count(); |
| 699 | 768 | } |
| 700 | 769 | } |
| 701 | 770 | |
| @@ -709,9 +778,9 @@ | ||
| 709 | 778 | * @return void |
| 710 | 779 | */ |
| 711 | 780 | public static function customer_ticket_count_after_change_raised_by( $ticket, $prev, $new, $customer_id ) { |
| 712 | 781 | |
| 713 | - if ( empty( $ticket->customer ) ) { | |
| 782 | + if ( ! $ticket->customer ) { | |
| 714 | 783 | return; |
| 715 | 784 | } |
| 716 | 785 | |
| 717 | 786 | $customer = $ticket->customer; |
| @@ -719,9 +788,9 @@ | ||
| 719 | 788 | if ( ! is_object( $customer ) ) { |
| 720 | 789 | $customer = new WPSC_Customer( $customer ); |
| 721 | 790 | } |
| 722 | 791 | |
| 723 | - if ( isset( $customer->id ) && method_exists( $customer, 'update_ticket_count' ) ) { | |
| 792 | + if ( $customer->id ) { | |
| 724 | 793 | $customer->update_ticket_count(); |
| 725 | 794 | } |
| 726 | 795 | } |
| 727 | 796 | |
| @@ -732,10 +801,9 @@ | ||
| 732 | 801 | * @param WPSC_Archive_Ticket $ar_ticket - archive ticket object. |
| 733 | 802 | * @return void |
| 734 | 803 | */ |
| 735 | 804 | public static function reset_customer_ticket_count( $ticket, $ar_ticket ) { |
| 736 | - | |
| 737 | - if ( empty( $ticket->customer ) ) { | |
| 805 | + if ( ! $ticket->customer ) { | |
| 738 | 806 | return; |
| 739 | 807 | } |
| 740 | 808 | |
| 741 | 809 | $customer = $ticket->customer; |
| @@ -743,9 +811,9 @@ | ||
| 743 | 811 | if ( ! is_object( $customer ) ) { |
| 744 | 812 | $customer = new WPSC_Customer( $customer ); |
| 745 | 813 | } |
| 746 | 814 | |
| 747 | - if ( isset( $customer->id ) && method_exists( $customer, 'update_ticket_count' ) ) { | |
| 815 | + if ( $customer->id ) { | |
| 748 | 816 | $customer->update_ticket_count(); |
| 749 | 817 | } |
| 750 | 818 | } |
| 751 | 819 | |
| @@ -755,10 +823,9 @@ | ||
| 755 | 823 | * @param WPSC_Ticket $ticket - ticket object. |
| 756 | 824 | * @return void |
| 757 | 825 | */ |
| 758 | 826 | public static function customer_ticket_count( $ticket ) { |
| 759 | - | |
| 760 | - if ( empty( $ticket->customer ) ) { | |
| 827 | + if ( ! $ticket->customer ) { | |
| 761 | 828 | return; |
| 762 | 829 | } |
| 763 | 830 | |
| 764 | 831 | $customer = $ticket->customer; |
| @@ -766,9 +833,9 @@ | ||
| 766 | 833 | if ( ! is_object( $customer ) ) { |
| 767 | 834 | $customer = new WPSC_Customer( $customer ); |
| 768 | 835 | } |
| 769 | 836 | |
| 770 | - if ( isset( $customer->id ) && method_exists( $customer, 'update_ticket_count' ) ) { | |
| 837 | + if ( $customer->id ) { | |
| 771 | 838 | $customer->update_ticket_count(); |
| 772 | 839 | } |
| 773 | 840 | } |
| 774 | 841 | |
| @@ -991,10 +1058,13 @@ | ||
| 991 | 1058 | ); |
| 992 | 1059 | $tickets = WPSC_Ticket::find( $filters )['results']; |
| 993 | 1060 | if ( $tickets ) { |
| 994 | 1061 | foreach ( $tickets as $ticket ) { |
| 1062 | + // Backend link (view = 0) so it opens the ticket in wp-admin, regardless | |
| 1063 | + // of how the frontend "open ticket page" is configured. | |
| 1064 | + $ticket_url = WPSC_Functions::get_ticket_url( $ticket->id, 0 ); | |
| 995 | 1065 | ?> |
| 996 | - <tr> | |
| 1066 | + <tr class="wpsc-cust-ticket-row" onclick="window.open('<?php echo esc_url( $ticket_url ); ?>', '_blank');" title="<?php esc_attr_e( 'Open ticket', 'supportcandy' ); ?>"> | |
| 997 | 1067 | <?php |
| 998 | 1068 | foreach ( $list_items as $slug ) { |
| 999 | 1069 | $cf = WPSC_Custom_Field::get_cf_by_slug( $slug ); |
| 1000 | 1070 | if ( ! $cf ) { |
| @@ -1000,9 +1070,9 @@ | ||
| 1000 | 1070 | if ( ! $cf ) { |
| 1001 | 1071 | continue; |
| 1002 | 1072 | } |
| 1003 | 1073 | ?> |
| 1004 | - <td onmouseover="link=true;"> | |
| 1074 | + <td> | |
| 1005 | 1075 | <?php |
| 1006 | 1076 | if ( in_array( $cf->field, array( 'ticket', 'agentonly' ) ) ) { |
| 1007 | 1077 | $cf->type::print_tl_ticket_field_val( $cf, $ticket ); |
| 1008 | 1078 | } else { |
| @@ -1045,25 +1115,37 @@ | ||
| 1045 | 1115 | * @param int $customer - customer id. |
| 1046 | 1116 | * @return void |
| 1047 | 1117 | */ |
| 1048 | 1118 | public static function get_customers_customer_fields( $customer ) { |
| 1119 | + | |
| 1120 | + $properties = array( | |
| 1121 | + 'is-required' => 0, | |
| 1122 | + 'width' => 'full', | |
| 1123 | + 'visibility' => '', | |
| 1124 | + ); | |
| 1125 | + | |
| 1126 | + // Render into a buffer first so we can tell whether there is anything to show at all | |
| 1127 | + // (no applicable customer fields, and nothing added via the body hook either) before | |
| 1128 | + // committing to the form + action buttons. | |
| 1129 | + ob_start(); | |
| 1130 | + foreach ( WPSC_Custom_Field::$custom_fields as $cf ) { | |
| 1131 | + if ( $cf->field !== 'customer' || in_array( $cf->slug, WPSC_DF_Customer::$ignore_customer_info_cft ) ) { | |
| 1132 | + continue; | |
| 1133 | + } | |
| 1134 | + echo $cf->type::print_edit_customer_info( $cf, $customer, $properties ); // phpcs:ignore | |
| 1135 | + } | |
| 1136 | + do_action( 'wpsc_get_edit_customer_info_body', $customer ); | |
| 1137 | + $fields_html = ob_get_clean(); | |
| 1138 | + | |
| 1139 | + if ( '' === trim( $fields_html ) ) { | |
| 1140 | + ?> | |
| 1141 | + <p class="wpsc-cust-cf-empty"><?php esc_attr_e( 'No custom fields found for this customer.', 'supportcandy' ); ?></p> | |
| 1142 | + <?php | |
| 1143 | + return; | |
| 1144 | + } | |
| 1049 | 1145 | ?> |
| 1050 | 1146 | <form action="#" onsubmit="return false;" class="frm-edit-customer-info"> |
| 1051 | - <?php | |
| 1052 | - $cf = WPSC_Custom_Field::get_cf_by_slug( 'name' ); | |
| 1053 | - foreach ( WPSC_Custom_Field::$custom_fields as $cf ) { | |
| 1054 | - if ( $cf->field !== 'customer' || in_array( $cf->slug, WPSC_DF_Customer::$ignore_customer_info_cft ) ) { | |
| 1055 | - continue; | |
| 1056 | - } | |
| 1057 | - $properties = array( | |
| 1058 | - 'is-required' => 0, | |
| 1059 | - 'width' => 'full', | |
| 1060 | - 'visibility' => '', | |
| 1061 | - ); | |
| 1062 | - echo $cf->type::print_edit_customer_info( $cf, $customer, $properties ); // phpcs:ignore | |
| 1063 | - } | |
| 1064 | - do_action( 'wpsc_get_edit_customer_info_body', $customer ); | |
| 1065 | - ?> | |
| 1147 | + <?php echo $fields_html; // phpcs:ignore ?> | |
| 1066 | 1148 | <input type="hidden" name="action" value="wpsc_set_edit_customer_info"/> |
| 1067 | 1149 | <input type="hidden" name="id" value="<?php echo esc_attr( $customer->id ); ?>"> |
| 1068 | 1150 | <input type="hidden" name="name" value="<?php echo esc_attr( $customer->name ); ?>"> |
| 1069 | 1151 | <input type="hidden" name="_ajax_nonce" value="<?php echo esc_attr( wp_create_nonce( 'wpsc_set_edit_customer_info' ) ); ?>"> |