PluginProbe
SupportCandy – AI Customer Support Ticket System & Live Chatbot Agent / 3.5.2
SupportCandy – AI Customer Support Ticket System & Live Chatbot Agent v3.5.2
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
supportcandy / includes / admin / tickets / class-wpsc-archive-ticket-list.php

class-wpsc-archive-ticket-list.php in SupportCandy – AI Customer Support Ticket System & Live Chatbot Agent 3.5.2, at includes/admin/tickets/class-wpsc-archive-ticket-list.php

1,231 lines 38.1 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 if ( ! defined( 'ABSPATH' ) ) {
3 exit; // Exit if accessed directly!
4 }
5
6 if ( ! class_exists( 'WPSC_Archive_Ticket_List' ) ) :
7
8 final class WPSC_Archive_Ticket_List {
9
10 /**
11 * All default and saved filters for logged-in user
12 *
13 * @var array
14 */
15 private static $at_filters;
16
17 /**
18 * Default filters based on logged-in user
19 *
20 * @var array
21 */
22 public static $default_at_filters;
23
24 /**
25 * Saved filters of logged-in user
26 *
27 * @var array
28 */
29 private static $saved_at_filters;
30
31 /**
32 * Flag to check whether current filter is saved filter or not
33 *
34 * @var integer
35 */
36 private static $saved_at_flag;
37
38 /**
39 * Numeric type flag ID for current filter
40 *
41 * @var integer
42 */
43 private static $at_filter_id = 0;
44
45 /**
46 * Set if current screen is tickets page
47 *
48 * @var boolean
49 */
50 public static $is_current_page;
51
52 /**
53 * Sections for this view
54 *
55 * @var [type]
56 */
57 private static $sections = array();
58
59 /**
60 * Current section to load
61 *
62 * @var [type]
63 */
64 public static $current_section;
65
66 /**
67 * Total number of tickets found for $filters
68 *
69 * @var integer
70 */
71 private static $total_items = 0;
72
73 /**
74 * Total number of pages
75 *
76 * @var integer
77 */
78 private static $total_pages = 0;
79
80 /**
81 * Set if there is next page is available
82 *
83 * @var integer
84 */
85 private static $has_next_page = false;
86
87 /**
88 * More settings for agent/customer view based on logged-in user
89 *
90 * @var array
91 */
92 public static $more_settings;
93
94 /**
95 * Ticket list bulk actions
96 *
97 * @var array
98 */
99 private static $bulk_actions = array();
100
101 /**
102 * Ticket found for the filter
103 *
104 * @var array
105 */
106 private static $tickets = array();
107
108 /**
109 * Flag for current view
110 *
111 * @var integer
112 */
113 private static $is_frontend = 0;
114
115 /**
116 * Flag to check whether current filter is numeric default filter or not
117 *
118 * @var integer
119 */
120 private static $default_at_flag;
121
122 /**
123 * Cookie filters to be sent to JS with tickets
124 *
125 * @var array
126 */
127 private static $cookie_filters;
128
129 /**
130 * Set whether tickets to be queried is active or deleted
131 *
132 * @var integer
133 */
134 public static $is_active = 1;
135
136 /**
137 * Initialize the class
138 *
139 * @return void
140 */
141 public static function init() {
142
143 // Load sections for this screen.
144 add_action( 'admin_init', array( __CLASS__, 'load_sections' ) );
145
146 // Add current section to admin localization data.
147 add_filter( 'wpsc_admin_localizations', array( __CLASS__, 'localizations' ) );
148
149 // Humbargar modal.
150 add_action( 'admin_footer', array( __CLASS__, 'humbargar_menu' ) );
151
152 // JS dynamic functions.
153 add_action( 'wpsc_js_ready', array( __CLASS__, 'register_js_ready_function' ) );
154
155 // Get tickets ajax request.
156 add_action( 'wp_ajax_wpsc_get_archive_tickets', array( __CLASS__, 'get_archive_tickets' ) );
157 add_action( 'wp_ajax_nopriv_wpsc_get_archive_tickets', array( __CLASS__, 'get_archive_tickets' ) );
158 add_action( 'wp_ajax_wpsc_get_atl_custom_filter', array( __CLASS__, 'get_atl_custom_filter_ui' ) );
159 add_action( 'wp_ajax_nopriv_wpsc_get_atl_custom_filter', array( __CLASS__, 'get_atl_custom_filter_ui' ) );
160
161 // Get ticket list ajax request.
162 add_action( 'wp_ajax_wpsc_get_archive_ticket_list', array( __CLASS__, 'archive_ticket_list' ) );
163 add_action( 'wp_ajax_nopriv_wpsc_get_archive_ticket_list', array( __CLASS__, 'archive_ticket_list' ) );
164
165 add_action( 'wp_ajax_wpsc_bulk_delete_archive_tickets', array( __CLASS__, 'bulk_delete_archive_tickets' ) );
166 add_action( 'wp_ajax_nopriv_wpsc_bulk_delete_archive_tickets', array( __CLASS__, 'bulk_delete_archive_tickets' ) );
167 add_action( 'wp_ajax_wpsc_bulk_restore_archive_tickets', array( __CLASS__, 'bulk_restore_archive_tickets' ) );
168 add_action( 'wp_ajax_nopriv_wpsc_bulk_restore_archive_tickets', array( __CLASS__, 'bulk_restore_archive_tickets' ) );
169 }
170
171 /**
172 * Load ticket list
173 *
174 * @return void
175 */
176 public static function archive_ticket_list() {
177 self::load_tickets();
178 self::set_bulk_actions();
179 self::get_filters();
180 self::get_ticket_list();
181 self::print_tl_snippets();
182 wp_die();
183 }
184
185 /**
186 * Ajax callback for get_archive_tickets on ticket list with filters and page
187 *
188 * @return void
189 */
190 public static function get_archive_tickets() {
191
192 if ( check_ajax_referer( 'general', '_ajax_nonce', false ) != 1 ) {
193 wp_send_json_error( 'Unauthorized request!', 401 );
194 }
195
196 self::load_tickets();
197 self::set_bulk_actions();
198 $filters = self::$cookie_filters;
199 $filters['filters'] = isset( $filters['filters'] ) ? $filters['filters'] : '[]';
200
201 $response = array(
202 'tickets' => self::print_tickets(),
203 'filter_actions' => self::get_filter_actions(),
204 'bulk_actions' => self::get_bulk_actions(),
205 'pagination_str' => self::get_pagination_str(),
206 'pagination' => array(
207 'current_page' => self::$at_filters['page_no'],
208 'has_next_page' => self::$has_next_page,
209 'total_pages' => self::$total_pages,
210 'total_items' => self::$total_items,
211 ),
212 'filters' => $filters,
213 );
214 wp_send_json( $response );
215 }
216
217 /**
218 * Print ticket filters layout
219 *
220 * @return void
221 */
222 private static function get_filters() {
223
224 $current_user = WPSC_Current_User::$current_user;
225 $custom_fields = WPSC_Custom_Field::$custom_fields;
226 $list_items = $current_user->get_tl_list_items();
227
228 ?>
229 <div class="wpsc-filter">
230 <div class="wpsc-search">
231 <div class="search-field">
232 <?php WPSC_Icons::get( 'search' ); ?>
233 <input class="wpsc-search-input" type="text" placeholder="<?php esc_attr_e( 'Search...', 'supportcandy' ); ?>" spellcheck="false" value="<?php echo esc_attr( stripslashes( self::$at_filters['search'] ) ); ?>" onkeyup="wpsc_tl_search_keyup(event, this, 'archive_ticket_list');"/>
234 </div>
235 </div>
236 <div class="wpsc-filter-container">
237 <div class="wpsc-filter-item">
238 <label for="wpsc-input-filter"><?php esc_attr_e( 'Filter', 'supportcandy' ); ?></label>
239 <select id="wpsc-input-filter" class="wpsc-input-filter" name="filter" onchange="wpsc_tl_filter_change(this, 'archive_ticket_list');">
240 <option <?php selected( self::$at_filters['filterSlug'], 'all' ); ?> value="all"><?php esc_attr_e( 'All', 'supportcandy' ); ?></option>
241 <option <?php selected( self::$at_filters['filterSlug'], 'custom' ); ?> value="custom"><?php esc_attr_e( 'Custom...', 'supportcandy' ); ?></option>
242
243 </select>
244 </div>
245 <div class="wpsc-filter-item">
246 <label for="wpsc-input-sort-by"><?php esc_attr_e( 'Sort By', 'supportcandy' ); ?></label>
247 <select id="wpsc-input-sort-by" class="wpsc-input-sort-by" name="sort-by">
248 <?php
249 foreach ( $list_items as $slug ) :
250 $cf = WPSC_Custom_Field::get_cf_by_slug( $slug );
251 if ( ! $cf || ! $cf->type::$is_sort ) {
252 continue;
253 }
254 ?>
255 <option <?php selected( $cf->slug, self::$at_filters['orderby'] ); ?> value="<?php echo esc_attr( $cf->slug ); ?>"><?php echo esc_attr( $cf->name ); ?></option>
256 <?php
257 endforeach;
258 ?>
259 </select>
260 </div>
261 <div class="wpsc-filter-item">
262 <select id="wpsc-input-sort-order" class="wpsc-input-sort-order" name="sort-order">
263 <option <?php selected( self::$at_filters['order'], 'ASC' ); ?> value="ASC"><?php esc_attr_e( 'ASC', 'supportcandy' ); ?></option>
264 <option <?php selected( self::$at_filters['order'], 'DESC' ); ?> value="DESC"><?php esc_attr_e( 'DESC', 'supportcandy' ); ?></option>
265 </select>
266 </div>
267 <div class="wpsc-filter-submit">
268 <button class="wpsc-button normal primary margin-right" onclick="wpsc_tl_apply_filter_btn_click( 'archive_ticket_list' );"><?php esc_attr_e( 'Apply', 'supportcandy' ); ?></button>
269 <div class="wpsc-filter-actions">
270 <?php echo self::get_filter_actions(); // phpcs:ignore?>
271 </div>
272 </div>
273 </div>
274 </div>
275 <?php
276 }
277
278 /**
279 * Load tickets based on current filter
280 *
281 * @return void
282 */
283 private static function load_tickets() {
284
285 if ( check_ajax_referer( 'general', '_ajax_nonce', false ) != 1 ) {
286 wp_send_json_error( 'Unauthorized request!', 401 );
287 }
288
289 $current_user = WPSC_Current_User::$current_user;
290 if ( ! $current_user->is_customer ) {
291 wp_send_json_error( new WP_Error( '001', 'Unauthorized!' ), 400 );
292 }
293
294 self::$is_frontend = isset( $_POST['is_frontend'] ) ? sanitize_text_field( wp_unslash( $_POST['is_frontend'] ) ) : '0';
295
296 $filters = null;
297
298 // check whether filters are given in post.
299 $filters = isset( $_POST['filters'] ) ? map_deep( wp_unslash( $_POST['filters'] ), 'sanitize_text_field' ) : array();
300 // get filters from cookies.
301 $tl_filters = isset( $_COOKIE['wpsc-atl-filters'] ) ? sanitize_text_field( wp_unslash( $_COOKIE['wpsc-atl-filters'] ) ) : '';
302
303 // use cookie filter if filters are not given.
304 $filters = $filters == null && $tl_filters ? json_decode( $tl_filters, true ) : $filters;
305
306 self::$more_settings = get_option( $current_user->is_agent ? 'wpsc-tl-ms-agent-view' : 'wpsc-tl-ms-customer-view' );
307
308 $current_user_filters = $current_user->get_tl_filters();
309 self::$default_at_filters = $current_user_filters['default'];
310 self::$saved_at_filters = $current_user_filters['saved'];
311
312 if ( ! $filters || ! self::has_filter_access( $filters ) ) {
313 $filters = array(
314 'filterSlug' => 'all',
315 );
316 if ( isset( self::$default_at_filters[ $filters['filterSlug'] ] ) ) {
317 $filters['orderby'] = self::$more_settings['default-sort-by'];
318 $filters['order'] = self::$more_settings['default-sort-order'];
319 }
320 }
321
322 self::$default_at_flag = preg_match( '/default-(\d*)$/', $filters['filterSlug'], $default_matches );
323 if ( self::$default_at_flag ) {
324 self::$at_filter_id = $default_matches[1];
325 }
326
327 self::$saved_at_flag = preg_match( '/saved-(\d*)$/', $filters['filterSlug'], $saved_matches );
328 if ( self::$saved_at_flag ) {
329 self::$at_filter_id = $saved_matches[1];
330 }
331
332 // Order by.
333 if ( ! isset( $filters['orderby'] ) && ! self::$default_at_flag && isset( self::$default_at_filters[ $filters['filterSlug'] ] ) ) {
334 $filters['orderby'] = self::$more_settings['default-sort-by'];
335 }
336 if ( ! isset( $filters['orderby'] ) && self::$default_at_flag ) {
337 $filters['orderby'] = self::$default_at_filters[ self::$at_filter_id ]['sort-by'];
338 }
339 if ( ! isset( $filters['orderby'] ) && self::$saved_at_flag ) {
340 $filters['orderby'] = self::$saved_at_filters[ self::$at_filter_id ]['sort-by'];
341 }
342
343 // Order.
344 if ( ! isset( $filters['order'] ) && ! self::$default_at_flag && isset( self::$default_at_filters[ $filters['filterSlug'] ] ) ) {
345 $filters['order'] = self::$more_settings['default-sort-order'];
346 }
347 if ( ! isset( $filters['order'] ) && self::$default_at_flag ) {
348 $filters['order'] = self::$default_at_filters[ self::$at_filter_id ]['sort-order'];
349 }
350 if ( ! isset( $filters['order'] ) && self::$saved_at_flag ) {
351 $filters['order'] = self::$saved_at_filters[ self::$at_filter_id ]['sort-order'];
352 }
353
354 // Search.
355 $filters['search'] = isset( $filters['search'] ) ? sanitize_text_field( $filters['search'] ) : '';
356
357 // Current page number.
358 $filters['page_no'] = isset( $filters['page_no'] ) ? intval( $filters['page_no'] ) : 1;
359
360 // Set cookie here so that front-end should have access to filters until here only.
361 setcookie( 'wpsc-atl-filters', wp_json_encode( $filters ), time() + 3600 );
362 self::$cookie_filters = $filters;
363
364 $filters['items_per_page'] = self::$more_settings['number-of-tickets'];
365
366 // System query.
367 $filters['system_query'] = $current_user->get_atl_system_query( $filters );
368
369 // Meta query.
370 $meta_query = array( 'relation' => 'AND' );
371
372 if (
373 isset( self::$default_at_filters[ $filters['filterSlug'] ] ) ||
374 ( self::$default_at_flag && isset( self::$default_at_filters[ self::$at_filter_id ] ) ) ||
375 ( self::$saved_at_flag && isset( self::$saved_at_filters[ self::$at_filter_id ] ) ) ||
376 $filters['filterSlug'] == 'custom'
377 ) {
378
379 $slug = self::$default_at_flag || self::$saved_at_flag ? self::$at_filter_id : '';
380 if ( ! $slug ) {
381 $slug = $filters['filterSlug'];
382 }
383
384 $parent_slug = is_numeric( $slug ) && self::$default_at_flag ? self::$default_at_filters[ $slug ]['parent-filter'] : '';
385 if ( ! $parent_slug && is_numeric( $slug ) && self::$saved_at_flag ) {
386 $parent_slug = self::$saved_at_filters[ $slug ]['parent-filter'];
387 }
388 if ( ! $parent_slug && $slug == 'custom' ) {
389 $parent_slug = $filters['parent-filter'];
390 }
391 if ( ! $parent_slug ) {
392 $parent_slug = $slug;
393 }
394
395 if ( self::$default_at_flag ) {
396 $meta_query = array_merge( $meta_query, WPSC_Ticket_Conditions::get_meta_query( self::$default_at_filters[ $slug ]['filters'] ) );
397 }
398
399 if ( self::$saved_at_flag ) {
400 $json_str = str_replace( PHP_EOL, '\n', self::$saved_at_filters[ $slug ]['filters'] );
401 $meta_query = array_merge( $meta_query, WPSC_Ticket_Conditions::get_meta_query( $json_str, true ) );
402 }
403
404 if ( $filters['filterSlug'] == 'custom' ) {
405 $meta_query = array_merge( $meta_query, WPSC_Ticket_Conditions::get_meta_query( $filters['filters'], true ) );
406 }
407 }
408
409 $filters['meta_query'] = $meta_query;
410 self::$at_filters = apply_filters( 'wpsc_archived_ticket_list_filters', $filters );
411
412 $response = WPSC_Archive_Ticket::find( self::$at_filters );
413 self::$tickets = $response['results'];
414 self::$total_items = intval( $response['total_items'] );
415 self::$total_pages = intval( $response['total_pages'] );
416 self::$has_next_page = $response['has_next_page'];
417 }
418
419 /**
420 * Check whether current user has access to given filter
421 *
422 * @param array $filters - ticket filters.
423 * @return boolean
424 */
425 public static function has_filter_access( $filters ) {
426
427 $current_user = WPSC_Current_User::$current_user;
428
429 $filter_slug = isset( $filters['filterSlug'] ) ? $filters['filterSlug'] : '';
430
431 if ( ! $filter_slug ) {
432 return false;
433 }
434
435 if ( isset( self::$default_at_filters[ $filter_slug ] ) ) {
436 return true;
437 }
438
439 $flag = preg_match( '/default-(\d*)$/', $filter_slug, $matches );
440 if ( $flag && isset( self::$default_at_filters[ $matches[1] ] ) ) {
441 return true;
442 }
443
444 $flag = preg_match( '/saved-(\d*)$/', $filter_slug, $matches );
445 if ( $flag && isset( self::$saved_at_filters[ $matches[1] ] ) ) {
446 return true;
447 }
448
449 if ( $filter_slug == 'custom' && WPSC_Ticket_Conditions::is_valid_input_conditions( 'wpsc_custom_filter_conditions', $filters['filters'] ) ) {
450 return true;
451 }
452
453 return false;
454 }
455
456 /**
457 * Print ticket list layout along with first page tickets
458 *
459 * @return void
460 */
461 private static function get_ticket_list() {
462
463 $current_user = WPSC_Current_User::$current_user;
464 $pagination_html = self::get_pagination_html();
465 ?>
466 <div class="wpsc-tickets-container">
467 <div class="wpsc-bulk-actions">
468 <?php
469 if ( $current_user->is_agent && self::$bulk_actions ) :
470 ?>
471 <button
472 id="wpsc-bulk-actions-btn"
473 class="wpsc-button small secondary"
474 type="button"
475 data-popover="wpsc-bulk-actions">
476 <?php esc_attr_e( 'Bulk Actions', 'supportcandy' ); ?>
477 <?php WPSC_Icons::get( 'chevron-down' ); ?>
478 </button>
479 <div id="wpsc-bulk-actions" class="gpopover wpsc-popover-menu wpsc-ticket-bulk-actions" >
480 <?php
481 echo self::get_bulk_actions(); // phpcs:ignore
482 ?>
483 </div>
484 <?php
485 endif;
486 $more_actions = apply_filters( 'wpsc_admin_atl_more_actions', array() );
487 if ( is_array( $more_actions ) && ! empty( $more_actions ) ) {
488 ?>
489 <button
490 id="wpsc-more-actions-btn"
491 class="wpsc-button small secondary"
492 type="button"
493 data-popover="wpsc-more-actions">
494 <?php esc_attr_e( 'List Actions', 'supportcandy' ); ?>
495 <?php WPSC_Icons::get( 'chevron-down' ); ?>
496 </button>
497 <div id="wpsc-more-actions" class="gpopover wpsc-popover-menu">
498 <?php
499 foreach ( $more_actions as $action ) :
500 ?>
501 <div class="wpsc-popover-menu-item" onclick="<?php echo esc_attr( $action['callback'] ) . '(\'' . esc_attr( wp_create_nonce( $action['callback'] ) ) . '\');'; ?>">
502 <?php WPSC_Icons::get( $action['icon'] ); ?>
503 <span><?php echo esc_attr( $action['label'] ); ?></span>
504 </div>
505 <?php
506 endforeach;
507 ?>
508 </div>
509 <?php
510 }
511 ?>
512 <script>
513 jQuery('#wpsc-more-actions-btn, #wpsc-bulk-actions-btn').gpopover({width: 200});
514 </script>
515 <div class="wpsc-ticket-pagination-header wpsc-hidden-xs">
516 <?php echo $pagination_html; // phpcs:ignore?>
517 </div>
518 </div>
519
520 <div class="wpsc-ticket-list">
521 <?php echo self::print_tickets(); // phpcs:ignore?>
522 </div>
523
524 <div class="wpsc-ticket-pagination-footer">
525 <?php echo $pagination_html; // phpcs:ignore?>
526 </div>
527 </div>
528 <?php
529 }
530
531 /**
532 * Get tickets based on current filter
533 *
534 * @return string
535 */
536 private static function print_tickets() {
537
538 ob_start();
539 $current_user = WPSC_Current_User::$current_user;
540 $list_items = $current_user->get_tl_list_items();
541 ?>
542
543 <div style="overflow-x:auto;">
544 <table class="wpsc-ticket-list-tbl">
545
546 <thead>
547 <tr>
548 <?php
549 if ( $current_user->is_agent && self::$bulk_actions ) :
550 ?>
551 <th style="width: 45px;">
552 <div class="checkbox-container">
553 <?php $unique_id = uniqid( 'wpsc_' ); ?>
554 <input id="<?php echo esc_attr( $unique_id ); ?>" class="wpsc-bulk-selector" type="checkbox" onchange="wpsc_bulk_select_change();"/>
555 <label for="<?php echo esc_attr( $unique_id ); ?>"></label>
556 </div>
557 </th>
558 <?php
559 endif;
560 do_action( 'wpsc_print_archive_ticket_list_th' );
561 foreach ( $list_items as $slug ) :
562 $cf = WPSC_Custom_Field::get_cf_by_slug( $slug );
563 if ( ! $cf ) {
564 continue;
565 }
566 ?>
567 <th style="min-width: <?php echo esc_attr( $cf->tl_width ); ?>px;"><?php echo esc_attr( $cf->name ); ?></th>
568 <?php
569 endforeach;
570 ?>
571
572 </tr>
573 </thead>
574
575 <tbody>
576 <?php
577 if ( self::$tickets ) {
578 foreach ( self::$tickets as $ticket ) :
579 $class = apply_filters( 'wpsc_ticket_list_tr_classes', array( 'wpsc_tl_tr' ), $ticket );
580 $url = admin_url( 'admin.php?page=wpsc-archive-tickets&section=archive-ticket-list&id=' . $ticket->id );
581 ?>
582 <tr class="<?php echo esc_attr( implode( ' ', $class ) ); ?>" onclick="if(link)wpsc_tl_handle_click(event, <?php echo esc_attr( $ticket->id ); ?>, '<?php echo esc_url( $url ); ?>')">
583 <?php
584 if ( $current_user->is_agent && self::$bulk_actions ) :
585 ?>
586 <td class="bulk-selector" onmouseover="link=false;" onmouseout="link=true;">
587 <div class="wpsc-tl-item-selector">
588 <div class="checkbox-container">
589 <?php $unique_id = uniqid( 'wpsc_' ); ?>
590 <input id="<?php echo esc_attr( $unique_id ); ?>" class="wpsc-bulk-select" type="checkbox" onchange="wpsc_bulk_item_select_change();" value="<?php echo esc_attr( $ticket->id ); ?>"/>
591 <label for="<?php echo esc_attr( $unique_id ); ?>"></label>
592 </div>
593 </div>
594 </td>
595 <?php
596 endif;
597 do_action( 'wpsc_print_archive_ticket_list_td', $ticket );
598 foreach ( $list_items as $slug ) :
599 $cf = WPSC_Custom_Field::get_cf_by_slug( $slug );
600 if ( ! $cf ) {
601 continue;
602 }
603 ?>
604 <td onmouseover="link=true;">
605 <?php
606 if ( in_array( $cf->field, array( 'ticket', 'agentonly' ) ) ) {
607 $cf->type::print_tl_ticket_field_val( $cf, $ticket );
608 } else {
609 $cf->type::print_tl_customer_field_val( $cf, $ticket->customer );
610 }
611 ?>
612 </td>
613 <?php
614 endforeach;
615 ?>
616 </tr>
617 <?php
618 endforeach;
619 } else {
620 $col_span = count( $list_items );
621 if ( $current_user->is_agent && self::$bulk_actions ) {
622 ++$col_span;
623 }
624 ?>
625 <tr><td colspan="<?php echo esc_attr( $col_span ); ?>" style="text-align:left;"><?php esc_attr_e( 'No tickets found!', 'supportcandy' ); ?></td></tr>
626 <?php
627 }
628 ?>
629 </tbody>
630 </table>
631 </div>
632 <script>
633 function wpsc_tl_handle_click(event, id, url) {
634 if ( ( event.ctrlKey || event.metaKey ) && url ) {
635 window.open(url, '_blank');
636 } else {
637 wpsc_get_individual_archive_ticket(id);
638 }
639 }
640 </script>
641 <?php
642 return ob_get_clean();
643 }
644
645 /**
646 * Ticket list snippets. It may include static modal screens, JS initializers, etc.
647 *
648 * @return void
649 */
650 public static function print_tl_snippets() {
651
652 $filters = self::$cookie_filters;
653 $filter_json = isset( $filters['filters'] ) && $filters['filters'] ? $filters['filters'] : '[]';
654 $filters['filters'] = $filter_json;
655
656 $ticket_list_js_vars = array(
657 'pagination' => array(
658 'current_page' => self::$at_filters['page_no'],
659 'has_next_page' => self::$has_next_page,
660 'total_pages' => self::$total_pages,
661 'total_items' => self::$total_items,
662 ),
663 'filters' => $filters,
664 );
665 ?>
666
667 <div class="wpsc-tl_snippets" style="display:none;">
668 <script>
669 supportcandy.ticketList = <?php echo wp_json_encode( $ticket_list_js_vars ); ?>;
670 </script>
671 <?php do_action( 'wpsc_tl_snippets' ); ?>
672 </div>
673 <?php
674 }
675
676 /**
677 * Return HTML content of pagination section
678 */
679 private static function get_pagination_html() {
680
681 $pagination_str = self::get_pagination_str();
682 $btn_style = self::$total_items <= self::$more_settings['number-of-tickets'] ? 'display:none;' : '';
683 ob_start();
684 ?>
685 <span
686 class="wpsc-pagination-btn wpsc-pagination-first wpsc-link"
687 style="<?php echo esc_attr( $btn_style ); ?>"
688 onclick="wpsc_tl_set_page('first', 'archive_ticket_list');">
689 <?php esc_attr_e( 'First Page', 'supportcandy' ); ?>
690 </span>
691 <?php
692 if ( is_rtl() ) {
693 ?>
694 <span
695 class="wpsc-pagination-btn wpsc-pagination-next wpsc-link"
696 style="<?php echo esc_attr( $btn_style ); ?>"
697 onclick="wpsc_tl_set_page('next', 'archive_ticket_list');">
698 <?php WPSC_Icons::get( 'chevron-right' ); ?>
699 </span>
700 <?php
701 } else {
702 ?>
703 <span
704 class="wpsc-pagination-btn wpsc-pagination-prev wpsc-link"
705 style="<?php echo esc_attr( $btn_style ); ?>"
706 onclick="wpsc_tl_set_page('prev', 'archive_ticket_list');">
707 <?php WPSC_Icons::get( 'chevron-left' ); ?>
708 </span>
709 <?php
710 }
711 ?>
712 <span class="wpsc-pagination-txt"><?php echo esc_attr( $pagination_str ); ?></span>
713 <?php
714 if ( is_rtl() ) {
715 ?>
716 <span
717 class="wpsc-pagination-btn wpsc-pagination-prev wpsc-link"
718 style="<?php echo esc_attr( $btn_style ); ?>"
719 onclick="wpsc_tl_set_page('prev', 'archive_ticket_list');">
720 <?php WPSC_Icons::get( 'chevron-left' ); ?>
721 </span>
722 <?php
723 } else {
724 ?>
725 <span
726 class="wpsc-pagination-btn wpsc-pagination-next wpsc-link"
727 style="<?php echo esc_attr( $btn_style ); ?>"
728 onclick="wpsc_tl_set_page('next', 'archive_ticket_list');">
729 <?php WPSC_Icons::get( 'chevron-right' ); ?>
730 </span>
731 <?php
732 }
733 ?>
734 <span
735 class="wpsc-pagination-btn wpsc-pagination-last wpsc-link"
736 style="<?php echo esc_attr( $btn_style ); ?>"
737 onclick="wpsc_tl_set_page('last', 'archive_ticket_list');">
738 <?php esc_attr_e( 'Last Page', 'supportcandy' ); ?>
739 </span>
740 <?php
741 return ob_get_clean();
742 }
743
744 /**
745 * Pagination string
746 *
747 * @return string
748 */
749 private static function get_pagination_str() {
750
751 if ( self::$total_items < 1 ) {
752 return '';
753 }
754
755 if ( self::$total_items == 1 ) {
756 return esc_attr__( '1 Ticket', 'supportcandy' );
757 }
758
759 if ( self::$total_items <= self::$more_settings['number-of-tickets'] ) {
760 /* translators: %1$s: total tickets */
761 return sprintf( esc_attr__( '%1$d Tickets', 'supportcandy' ), self::$total_items );
762 }
763
764 $from = ( self::$more_settings['number-of-tickets'] * ( self::$at_filters['page_no'] - 1 ) ) + 1;
765 $to = self::$at_filters['page_no'] == self::$total_pages ?
766 self::$total_items :
767 self::$more_settings['number-of-tickets'] * self::$at_filters['page_no'];
768
769 /* translators: e.g. 1-20 of 100 Tickets */
770 return sprintf( esc_attr__( '%1$d-%2$d of %3$d Tickets', 'supportcandy' ), $from, $to, self::$total_items );
771 }
772
773 /**
774 * Set bulk actions for current user
775 */
776 public static function set_bulk_actions() {
777
778 $current_user = WPSC_Current_User::$current_user;
779 $bulk_actions = array();
780
781 if ( $current_user->is_agent && $current_user->agent->has_cap( 'at-delete-access' ) ) {
782 $bulk_actions['delete'] = array(
783 'icon' => 'trash-alt',
784 'label' => esc_attr__( 'Delete Permanently', 'supportcandy' ),
785 'callback' => 'wpsc_bulk_delete_archive_tickets',
786 );
787 }
788
789 if ( $current_user->is_agent && $current_user->agent->has_cap( 'at-access' ) ) {
790 $bulk_actions['restore'] = array(
791 'icon' => 'archive-restore',
792 'label' => esc_attr__( 'Restore', 'supportcandy' ),
793 'callback' => 'wpsc_bulk_restore_archive_tickets',
794 );
795 }
796
797 $bulk_actions = apply_filters( 'wpsc_atl_bulk_actions', $bulk_actions );
798 self::$bulk_actions = $bulk_actions;
799 }
800
801 /**
802 * Agent ticket access for cap
803 *
804 * @param string $cap - capability type.
805 * @return boolean
806 */
807 public static function has_ticket_cap( $cap ) {
808
809 $current_user = WPSC_Current_User::$current_user;
810 $flag = false;
811 if (
812 $current_user->agent->has_cap( $cap . '-unassigned' ) ||
813 $current_user->agent->has_cap( $cap . '-assigned-me' ) ||
814 $current_user->agent->has_cap( $cap . '-assigned-others' )
815 ) {
816 $flag = true;
817 }
818
819 return apply_filters( 'wpsc_bulk_has_archive_ticket_cap', $flag );
820 }
821
822 /**
823 * Get Bulk actions
824 *
825 * @return string
826 */
827 public static function get_bulk_actions() {
828
829 $current_user = WPSC_Current_User::$current_user;
830 $actions_arr = array();
831 foreach ( self::$bulk_actions as $action ) :
832 ob_start();
833 ?>
834 <div class="wpsc-popover-menu-item" onclick="<?php echo esc_attr( $action['callback'] ) . '(\'' . esc_attr( wp_create_nonce( $action['callback'] ) ) . '\');'; ?>">
835 <?php WPSC_Icons::get( $action['icon'] ); ?>
836 <span><?php echo esc_attr( $action['label'] ); ?></span>
837 </div>
838 <?php
839 $actions_arr[] = ob_get_clean();
840 endforeach;
841
842 return implode( '', $actions_arr );
843 }
844
845 /**
846 * Get filter actions based on current filter applied
847 *
848 * @return string
849 */
850 private static function get_filter_actions() {
851
852 $actions = array(
853 'reset' => array(
854 'label' => esc_attr__( 'Reset', 'supportcandy' ),
855 'callback' => 'wpsc_tl_reset_filter',
856 ),
857 );
858
859 if ( self::$saved_at_flag || self::$at_filters['filterSlug'] == 'custom' ) {
860 $actions['edit'] = array(
861 'label' => esc_attr__( 'Edit', 'supportcandy' ),
862 'callback' => 'wpsc_tl_edit_filter',
863 );
864 }
865
866 $actions_arr = array();
867 foreach ( $actions as $key => $action ) :
868 ob_start();
869 ?>
870 <span
871 class="wpsc-link"
872 onclick="<?php echo esc_attr( $action['callback'] ) . '( \'archive_ticket_list\' );'; ?>">
873 <?php echo esc_attr( $action['label'] ); ?>
874 </span>
875 <?php
876 $actions_arr[] = ob_get_clean();
877 endforeach;
878
879 return implode( '<div class="action-devider"></div>', $actions_arr );
880 }
881
882 /**
883 * UI foundation for this screen
884 *
885 * @return void
886 */
887 public static function layout() {
888
889 ?>
890 <div class="wrap">
891 <hr class="wp-header-end">
892 <div id="wpsc-container" style="display:none;">
893 <?php do_action( 'wpsc_before_tickets_page' ); ?>
894 <div class="wpsc-shortcode-container">
895 <div class="wpsc-header wpsc-hidden-xs">
896 <?php
897 foreach ( self::$sections as $key => $section ) :
898 $active = self::$current_section === $key ? 'active' : '';
899 ?>
900 <div class="wpsc-menu-list wpsc-tickets-nav <?php echo esc_attr( $key ) . ' ' . esc_attr( $active ); ?>" onclick="<?php echo esc_attr( $section['callback'] ) . '();'; ?>">
901 <?php WPSC_Icons::get( $section['icon'] ); ?>
902 <label><?php echo esc_attr( $section['label'] ); ?></label>
903 </div>
904 <?php
905 endforeach;
906 ?>
907 </div>
908 <div class="wpsc-header wpsc-visible-xs">
909 <div class="wpsc-humbargar-title">
910 <?php WPSC_Icons::get( self::$sections[ self::$current_section ]['icon'] ); ?>
911 <label><?php echo esc_attr( self::$sections[ self::$current_section ]['label'] ); ?></label>
912 </div>
913 <div class="wpsc-humbargar" onclick="wpsc_toggle_humbargar();">
914 <?php WPSC_Icons::get( 'bars' ); ?>
915 </div>
916 </div>
917 <div class="wpsc-body"></div>
918 </div>
919 </div>
920 </div>
921 <?php
922 }
923
924 /**
925 * Add localizations to local JS
926 *
927 * @param array $localizations - localization list.
928 * @return array
929 */
930 public static function localizations( $localizations ) {
931
932 if ( ! self::$is_current_page ) {
933 return $localizations;
934 }
935
936 // Humbargar Titles.
937 $localizations['humbargar_titles'] = self::get_humbargar_titles();
938
939 // Current section.
940 $localizations['current_section'] = self::$current_section;
941
942 // Current archived ticket id.
943 if ( self::$current_section === 'archive-ticket-list' && isset( $_REQUEST['id'] ) ) { // phpcs:ignore
944 $localizations['current_archived_ticket_id'] = intval( $_REQUEST['id'] ); // phpcs:ignore
945 }
946
947 return $localizations;
948 }
949
950 /**
951 * Load section (nav elements) for this screen
952 *
953 * @return void
954 */
955 public static function load_sections() {
956
957 self::$is_current_page = isset( $_REQUEST['page'] ) && $_REQUEST['page'] === 'wpsc-archive-tickets' ? true : false; // phpcs:ignore
958
959 $current_user = WPSC_Current_User::$current_user;
960 if ( ! ( $current_user->is_agent && self::$is_current_page ) ) {
961 return;
962 }
963
964 // get default tab.
965 $gs = get_option( 'wpsc-gs-general' );
966 $ms = get_option( 'wpsc-ms-advanced-settings' );
967
968 // allow create ticket.
969 $allow_create_ticket = in_array( $current_user->agent->role, $gs['allow-create-ticket'] ) ? true : false;
970
971 // archived ticket list.
972 $sections = array();
973 if ( $current_user->is_agent && $current_user->agent->has_cap( 'at-access' ) ) {
974 $sections['archive-ticket-list'] = array(
975 'slug' => 'archived_ticket_list',
976 'icon' => 'archive',
977 'label' => esc_attr__( 'Archived Tickets', 'supportcandy' ),
978 'callback' => 'wpsc_get_archive_ticket_list',
979 );
980 }
981
982 self::$sections = apply_filters( 'wpsc_archived_tickets_page_sections', $sections );
983 self::$current_section = 'archive-ticket-list';
984 }
985
986 /**
987 * Print humbargar menu in footer
988 *
989 * @return void
990 */
991 public static function humbargar_menu() {
992
993 if ( ! self::$is_current_page ) {
994 return;
995 }
996
997 ?>
998 <div class="wpsc-humbargar-overlay" onclick="wpsc_toggle_humbargar();" style="display:none"></div>
999 <div class="wpsc-humbargar-menu" style="display:none">
1000 <div class="box-inner">
1001 <div class="wpsc-humbargar-close" onclick="wpsc_toggle_humbargar();">
1002 <?php WPSC_Icons::get( 'times' ); ?>
1003 </div>
1004 <?php
1005 foreach ( self::$sections as $key => $section ) :
1006 $active = self::$current_section === $key ? 'active' : '';
1007 ?>
1008 <div
1009 class="wpsc-humbargar-menu-item <?php echo esc_attr( $key ) . ' ' . esc_attr( $active ); ?>"
1010 onclick="<?php echo esc_attr( $section['callback'] ) . '(true);'; ?>">
1011 <?php WPSC_Icons::get( $section['icon'] ); ?>
1012 <label><?php echo esc_attr( $section['label'] ); ?></label>
1013 </div>
1014 <?php endforeach; ?>
1015 </div>
1016 </div>
1017 <?php
1018 }
1019
1020 /**
1021 * Custom filter modal pop-up
1022 *
1023 * @return void
1024 */
1025 public static function get_atl_custom_filter_ui() {
1026
1027 if ( check_ajax_referer( 'general', '_ajax_nonce', false ) != 1 ) {
1028 wp_send_json_error( 'Unauthorized request!', 401 );
1029 }
1030
1031 $current_user = WPSC_Current_User::$current_user;
1032 if ( ! ( $current_user->is_agent || $current_user->is_customer ) ) {
1033 wp_send_json_error( __( 'Bad request!', 'supportcandy' ), 400 );
1034 }
1035
1036 $title = esc_attr__( 'Custom filter', 'supportcandy' );
1037 $default_filters = get_option( $current_user->is_agent ? 'wpsc-atl-default-filters' : 'wpsc-ctl-default-filters' );
1038 $list_items = $current_user->get_tl_list_items();
1039 $more_settings = get_option( $current_user->is_agent ? 'wpsc-tl-ms-agent-view' : 'wpsc-tl-ms-customer-view' );
1040
1041 // check whether filters are passed.
1042 $filters = isset( $_POST['filters'] ) ? map_deep( wp_unslash( $_POST['filters'] ), 'sanitize_text_field' ) : array();
1043 $custom_filters = isset( $filters['filters'] ) && WPSC_Ticket_Conditions::is_valid_input_conditions( 'wpsc_custom_filter_conditions', $filters['filters'] ) ? $filters['filters'] : '';
1044
1045 ob_start();
1046 ?>
1047 <form action="#" onsubmit="return false;" class="wpsc-atl-custom-filter">
1048 <div class="wpsc-input-group">
1049 <div class="label-container">
1050 <label for="">
1051 <?php esc_attr_e( 'Parent filter', 'supportcandy' ); ?>
1052 <span class="required-char">*</span>
1053 </label>
1054 </div>
1055 <select name="parent-filter">
1056 <?php
1057 foreach ( $default_filters as $slug => $filter ) :
1058 $selected = isset( $filters['parent-filter'] ) && $filters['parent-filter'] == $slug ? 'selected="selected"' : ''
1059 ?>
1060 <option <?php echo esc_attr( $selected ); ?> value="<?php echo esc_attr( $slug ); ?>"><?php echo esc_attr( $filter['label'] ); ?></option>
1061 <?php
1062 endforeach;
1063 ?>
1064 </select>
1065 </div>
1066 <?php WPSC_Ticket_Conditions::print( 'custom_filters', 'wpsc_custom_filter_conditions', $custom_filters, true, __( 'Filters', 'supportcandy' ) ); ?>
1067 <div class="wpsc-input-group">
1068 <div class="label-container">
1069 <label for="">
1070 <?php esc_attr_e( 'Sort by', 'supportcandy' ); ?>
1071 <span class="required-char">*</span>
1072 </label>
1073 </div>
1074 <select name="sort-by">
1075 <?php
1076 $orderby = isset( $filters['orderby'] ) ? $filters['orderby'] : $more_settings['default-sort-by'];
1077 foreach ( $list_items as $slug ) :
1078 $cf = WPSC_Custom_Field::get_cf_by_slug( $slug );
1079 if ( ! $cf ) {
1080 continue;
1081 }
1082 if ( $cf->type::$is_sort ) :
1083 ?>
1084 <option <?php selected( $orderby, $cf->slug ); ?> value="<?php echo esc_attr( $cf->slug ); ?>"><?php echo esc_attr( $cf->name ); ?></option>
1085 <?php
1086 endif;
1087 endforeach;
1088 ?>
1089 </select>
1090 </div>
1091 <div class="wpsc-input-group">
1092 <div class="label-container">
1093 <label for="">
1094 <?php esc_attr_e( 'Sort order', 'supportcandy' ); ?>
1095 <span class="required-char">*</span>
1096 </label>
1097 </div>
1098 <select name="sort-order">
1099 <?php
1100 $order = isset( $filters['order'] ) ? $filters['order'] : $more_settings['default-sort-order'];
1101 ?>
1102 <option <?php selected( $order, 'ASC' ); ?> value="ASC"><?php esc_attr_e( 'ASC', 'supportcandy' ); ?></option>
1103 <option <?php selected( $order, 'DESC' ); ?> value="DESC"><?php esc_attr_e( 'DESC', 'supportcandy' ); ?></option>
1104 </select>
1105 </div>
1106 </form>
1107 <?php
1108 $body = ob_get_clean();
1109
1110 ob_start();
1111 ?>
1112 <button class="wpsc-button small primary" onclick="wpsc_tl_apply_custom_filter(this, 'archive_ticket_list');">
1113 <?php esc_attr_e( 'Apply', 'supportcandy' ); ?>
1114 </button>
1115 <button class="wpsc-button small secondary" onclick="wpsc_close_modal();">
1116 <?php esc_attr_e( 'Cancel', 'supportcandy' ); ?>
1117 </button>
1118 <?php
1119 $footer = ob_get_clean();
1120
1121 $response = array(
1122 'title' => $title,
1123 'body' => $body,
1124 'footer' => $footer,
1125 );
1126 wp_send_json( $response );
1127 }
1128
1129 /**
1130 * Humbargar mobile titles to be used in localizations
1131 *
1132 * @return array
1133 */
1134 private static function get_humbargar_titles() {
1135
1136 $titles = array();
1137 foreach ( self::$sections as $section ) {
1138
1139 ob_start();
1140 WPSC_Icons::get( $section['icon'] );
1141 echo '<label>' . esc_attr( $section['label'] ) . '</label>';
1142 $titles[ $section['slug'] ] = ob_get_clean();
1143 }
1144 return $titles;
1145 }
1146
1147 /**
1148 * Register JS functions to call on document ready
1149 *
1150 * @return void
1151 */
1152 public static function register_js_ready_function() {
1153
1154 if ( ! self::$is_current_page ) {
1155 return;
1156 }
1157
1158 echo esc_attr( self::$sections[ self::$current_section ]['callback'] ) . '();' . PHP_EOL;
1159 }
1160
1161 /**
1162 * Delete ticket ajax request
1163 */
1164 public static function bulk_delete_archive_tickets() {
1165
1166 if ( check_ajax_referer( 'wpsc_bulk_delete_archive_tickets', '_ajax_nonce', false ) != 1 ) {
1167 wp_send_json_error( 'Unauthorized request!', 401 );
1168 }
1169
1170 $current_user = WPSC_Current_User::$current_user;
1171 if ( ! $current_user->is_agent || ! $current_user->agent->has_cap( 'at-delete-access' ) ) {
1172 wp_send_json_error( 'Unauthorized request!', 401 );
1173 }
1174
1175 $ticket_ids = isset( $_POST['ticket_ids'] ) ? array_filter( array_map( 'intval', $_POST['ticket_ids'] ) ) : array();
1176 if ( ! $ticket_ids ) {
1177 wp_send_json_error( 'Something went wrong!', 400 );
1178 }
1179
1180 foreach ( $ticket_ids as $ticket_id ) {
1181
1182 $ticket = new WPSC_Archive_Ticket( $ticket_id );
1183 if ( ! $ticket->id ) {
1184 continue;
1185 }
1186 WPSC_Individual_Archive_Ticket::delete_archive_ticket( $ticket );
1187 }
1188 wp_die();
1189 }
1190
1191 /**
1192 * Restore bulk tickets
1193 *
1194 * @return void
1195 */
1196 public static function bulk_restore_archive_tickets() {
1197
1198 if ( check_ajax_referer( 'wpsc_bulk_restore_archive_tickets', '_ajax_nonce', false ) != 1 ) {
1199 wp_send_json_error( 'Unauthorized request!', 401 );
1200 }
1201
1202 $current_user = WPSC_Current_User::$current_user;
1203 if ( ! $current_user->is_agent ) {
1204 wp_send_json_error( 'Unauthorized request!', 401 );
1205 }
1206
1207 $ticket_ids = isset( $_POST['ticket_ids'] ) ? array_filter( array_map( 'intval', $_POST['ticket_ids'] ) ) : array();
1208 if ( ! $ticket_ids ) {
1209 wp_send_json_error( 'Something went wrong!', 400 );
1210 }
1211
1212 foreach ( $ticket_ids as $ticket_id ) {
1213
1214 $ar_ticket = new WPSC_Archive_Ticket( $ticket_id );
1215 if ( ! $ar_ticket->id || ! self::has_ticket_cap( 'at' ) ) {
1216 continue;
1217 }
1218
1219 $success = WPSC_Archive_Ticket::restore_archive_ticket( $ar_ticket );
1220 if ( $success ) {
1221 $ticket = new WPSC_Ticket( $ar_ticket->id );
1222 do_action( 'wpsc_archive_ticket_restore', $ticket, $ar_ticket );
1223 }
1224 }
1225 wp_die();
1226 }
1227 }
1228 endif;
1229
1230 WPSC_Archive_Ticket_List::init();
1231