PluginProbe
SupportCandy – AI Customer Support Ticket System & Live Chatbot Agent / 3.5.4
SupportCandy – AI Customer Support Ticket System & Live Chatbot Agent v3.5.4
3.5.4 3.5.3 3.5.2 3.5.1 3.4.9 3.5.0 3.4.8 3.4.7 trunk 2.3.1 3.3.6 3.3.7 3.3.8 3.3.9 3.4.0 3.4.1 3.4.2 3.4.3 3.4.4 3.4.5 3.4.6
← 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' ) ); ?>">