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 / class-wpsc-ticket-conditions.php

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

595 lines 18.5 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_Ticket_Conditions' ) ) :
7
8 final class WPSC_Ticket_Conditions {
9
10 /**
11 * Ticket conditions
12 *
13 * @var array
14 */
15 public static $conditions = array();
16
17 /**
18 * Ignore custom field types to match for email piping rules
19 *
20 * @var array
21 */
22 public static $ignore_cft = array();
23
24 /**
25 * Initialize the class
26 *
27 * @return void
28 */
29 public static function init() {
30
31 add_action( 'init', array( __CLASS__, 'load_ticket_conditions' ) );
32
33 add_action( 'wp_ajax_wpsc_tc_get_operators', array( __CLASS__, 'get_operators' ) );
34 add_action( 'wp_ajax_nopriv_wpsc_tc_get_operators', array( __CLASS__, 'get_operators' ) );
35
36 add_action( 'wp_ajax_wpsc_tc_get_operand', array( __CLASS__, 'get_operands' ) );
37 add_action( 'wp_ajax_nopriv_wpsc_tc_get_operand', array( __CLASS__, 'get_operands' ) );
38
39 // ignore custom field types.
40 add_action( 'init', array( __CLASS__, 'set_ignore_cft_list' ) );
41 }
42
43 /**
44 * Set ignore custom field types for pipe rules
45 *
46 * @return void
47 */
48 public static function set_ignore_cft_list() {
49
50 self::$ignore_cft = apply_filters(
51 'wpsc_ticket_condition_ignore_cft',
52 array(
53 'cf_woo_order',
54 'cf_woo_subscription',
55 'cf_edd_order',
56 'cf_tutor_order',
57 'cf_learnpress_order',
58 'cf_lifter_order',
59 )
60 );
61 }
62
63 /**
64 * Load ticket conditions along with user permitted to utilize them
65 *
66 * @return void
67 */
68 public static function load_ticket_conditions() {
69
70 $agent_filters = get_option( 'wpsc-atl-filter-items', array() );
71 $customer_filters = get_option( 'wpsc-ctl-filter-items', array() );
72
73 // custom fields.
74 foreach ( WPSC_Custom_Field::$custom_fields as $cf ) {
75
76 if ( ! (
77 class_exists( $cf->type ) &&
78 $cf->type::$is_filter &&
79 in_array( $cf->field, array( 'ticket', 'agentonly', 'customer' ) )
80 ) ) {
81 continue;
82 }
83
84 $levels = array( 'admin' );
85
86 if ( in_array( $cf->slug, $agent_filters ) ) {
87 $levels[] = 'agent';
88 }
89
90 if ( in_array( $cf->slug, $customer_filters ) ) {
91 $levels[] = 'customer';
92 }
93
94 self::$conditions[ $cf->slug ] = array(
95 'name' => $cf->name,
96 'type' => 'cf',
97 'levels' => $levels,
98 );
99 }
100
101 // custom conditions.
102 $other_conditions = apply_filters(
103 'wpsc_ticket_conditions',
104 array(
105 'submitted_by' => esc_attr__( 'Ticket submitted by', 'supportcandy' ),
106 'user_role' => esc_attr__( 'WP user role', 'supportcandy' ),
107 )
108 );
109
110 foreach ( $other_conditions as $slug => $name ) {
111 self::$conditions[ $slug ] = array(
112 'name' => $name,
113 'type' => 'other',
114 'levels' => array( 'admin' ),
115 );
116 }
117 }
118
119 /**
120 * Print condition input in the form
121 *
122 * @param string $name - form element name. Helpful to identify if multiple conditions need to be added.
123 * @param string $hook - filter hook for conditions. Uniquely identify and filter conditions available in the form.
124 * @param string $set_conditions - pre-defined conditions to print within input.
125 * @param boolean $is_required - whether or not to print required character for label.
126 * @param string $label - whether or not to print required character for label.
127 * @return void
128 */
129 public static function print( $name, $hook, $set_conditions = '', $is_required = false, $label = '' ) {
130
131 $label = $label ? $label : __( 'Conditions', 'supportcandy' );
132 $conditions = apply_filters( $hook, self::$conditions );
133 $set_conditions = $set_conditions ? json_decode( html_entity_decode( $set_conditions ), true ) : array();
134 $unique_id = wp_unique_id( 'wpsc_' );
135 ?>
136 <div class="wpsc-input-group">
137 <div class="label-container">
138 <label for="">
139 <?php
140 echo esc_attr( $label );
141 if ( $is_required ) {
142 ?>
143 <span class="required-char">*</span>
144 <?php
145 }
146 ?>
147 </label>
148 </div>
149 <div class="wpsc-form-filter-container <?php echo esc_attr( $name ); ?>">
150 <div class="and-container">
151 <?php
152 if ( $set_conditions ) {
153 foreach ( $set_conditions as $and_condition ) {
154 ?>
155 <div class="and-item">
156 <div class="or-container">
157 <?php
158 foreach ( $and_condition as $or_condition ) {
159 if ( ! isset( $conditions[ $or_condition['slug'] ] ) ) {
160 continue;
161 }
162 ?>
163 <div class="wpsc-form-filter-item">
164 <div class="content">
165 <div class="item">
166 <select class="filter" onchange="wpsc_tc_get_operators(this, '<?php echo esc_attr( wp_create_nonce( 'wpsc_tc_get_operators' ) ); ?>');">
167 <option value=""><?php esc_attr_e( 'Select field', 'supportcandy' ); ?></option>
168 <?php
169 foreach ( $conditions as $slug => $item ) {
170 ?>
171 <option value="<?php echo esc_attr( $slug ); ?>" <?php selected( $or_condition['slug'], $slug, true ); ?>><?php echo esc_attr( $item['name'] ); ?></option>
172 <?php
173 }
174 ?>
175 </select>
176 </div>
177 <?php
178 if ( $conditions[ $or_condition['slug'] ]['type'] == 'cf' ) {
179 $cf = WPSC_Custom_Field::get_cf_by_slug( $or_condition['slug'] );
180 $cf->type::get_operators( $cf, $or_condition );
181 $cf->type::get_operands( $or_condition['operator'], $cf, $or_condition );
182 } else {
183 self::print_operators( $or_condition['slug'], $or_condition );
184 self::print_operands( $or_condition['slug'], $or_condition['operator'], $or_condition );
185 }
186 ?>
187 </div>
188 <div class="remove-container">
189 <span onclick="wpsc_remove_condition_item(this)"><?php WPSC_Icons::get( 'times-circle' ); ?></span>
190 </div>
191 </div>
192 <?php
193 }
194 ?>
195 </div>
196 <button class="wpsc-button small secondary" onclick="wpsc_add_or_condition( this, '<?php echo esc_attr( $unique_id ); ?>' );"><?php esc_html_e( '+ OR', 'supportcandy' ); ?></button>
197 </div>
198 <?php
199 }
200 }
201 ?>
202 </div>
203 <button class="wpsc-button small secondary" onclick="wpsc_add_and_condition( this, '<?php echo esc_attr( $unique_id ); ?>' );"><?php esc_html_e( '+ AND', 'supportcandy' ); ?></button>
204 </div>
205 <script>jQuery( '.wpsc-form-filter-container select.filter' ).selectWoo();</script>
206 <div style="display: none;">
207 <div class="and-template <?php echo esc_attr( $unique_id ); ?>">
208 <div class="and-item">
209 <div class="or-container"></div>
210 <button class="wpsc-button small secondary" onclick="wpsc_add_or_condition( this, '<?php echo esc_attr( $unique_id ); ?>' );"><?php esc_html_e( '+ OR', 'supportcandy' ); ?></button>
211 </div>
212 </div>
213 <div class="or-template <?php echo esc_attr( $unique_id ); ?>">
214 <div class="wpsc-form-filter-item">
215 <div class="content">
216 <div class="item">
217 <select class="filter" onchange="wpsc_tc_get_operators(this, '<?php echo esc_attr( wp_create_nonce( 'wpsc_tc_get_operators' ) ); ?>');">
218 <option value=""><?php esc_attr_e( 'Select field', 'supportcandy' ); ?></option>
219 <?php
220 foreach ( $conditions as $slug => $item ) {
221 ?>
222 <option value="<?php echo esc_attr( $slug ); ?>"><?php echo esc_attr( $item['name'] ); ?></option>
223 <?php
224 }
225 ?>
226 </select>
227 </div>
228 </div>
229 <div class="remove-container">
230 <span onclick="wpsc_remove_condition_item(this)"><?php WPSC_Icons::get( 'times-circle' ); ?></span>
231 </div>
232 </div>
233 </div>
234 </div>
235 </div>
236 <?php
237 }
238
239 /**
240 * Check whether or not conditions submitted by client are valid or not before inserting into the database or any further use
241 *
242 * @param string $hook - filter hook for conditions. Uniquely identify and filter conditions available in the form.
243 * @param string $conditions - conditions received from the client.
244 * @return boolean
245 */
246 public static function is_valid_input_conditions( $hook, $conditions ) {
247
248 // No conditions.
249 if ( ! $conditions || $conditions == '[]' ) {
250 return true;
251 }
252
253 $allowed_conditions = apply_filters( $hook, self::$conditions );
254 $conditions = json_decode( html_entity_decode( $conditions ), true );
255
256 foreach ( $conditions as $and_condition ) {
257 foreach ( $and_condition as $or_condition ) {
258 if ( ! isset( $allowed_conditions[ $or_condition['slug'] ] ) ) {
259 return false;
260 }
261 }
262 }
263
264 return true;
265 }
266
267 /**
268 * Get condition operators ajax callback.
269 *
270 * @return void
271 */
272 public static function get_operators() {
273
274 $current_user = WPSC_Current_User::$current_user;
275
276 if ( check_ajax_referer( 'wpsc_tc_get_operators', '_ajax_nonce', false ) != 1 ) {
277 wp_send_json_error( 'Unauthorized request!', 401 );
278 }
279
280 $slug = isset( $_POST['slug'] ) ? sanitize_text_field( wp_unslash( $_POST['slug'] ) ) : '';
281 if ( ! $slug || ! array_key_exists( $slug, self::$conditions ) ) {
282 wp_send_json_error( __( 'Bad request!', 'supportcandy' ), 400 );
283 }
284
285 if ( ! in_array( $current_user->level, self::$conditions[ $slug ]['levels'] ) ) {
286 wp_send_json_error( 'Unauthorized request!', 401 );
287 }
288
289 if ( self::$conditions[ $slug ]['type'] == 'cf' ) {
290
291 $cf = WPSC_Custom_Field::get_cf_by_slug( $slug );
292 $cf->type::get_operators( $cf );
293
294 } else {
295
296 self::print_operators( $slug );
297 }
298
299 wp_die();
300 }
301
302 /**
303 * Print condition operators
304 *
305 * @param string $slug - condition slug.
306 * @param array $filter - predefined condition to set operator.
307 * @return void
308 */
309 public static function print_operators( $slug, $filter = array() ) {
310
311 switch ( $slug ) {
312
313 case 'submitted_by':
314 ?>
315 <div class="item conditional">
316 <select class="operator" onchange="wpsc_tc_get_operand(this, '<?php echo esc_attr( $slug ); ?>', '<?php echo esc_attr( wp_create_nonce( 'wpsc_tc_get_operand' ) ); ?>');">
317 <option value=""><?php esc_attr_e( 'Compare As', 'supportcandy' ); ?></option>
318 <option <?php isset( $filter['operator'] ) && selected( $filter['operator'], '=' ); ?> value="="><?php esc_attr_e( 'Equals', 'supportcandy' ); ?></option>
319 </select>
320 </div>
321 <?php
322 break;
323
324 case 'user_role':
325 ?>
326 <div class="item conditional">
327 <select class="operator" onchange="wpsc_tc_get_operand(this, '<?php echo esc_attr( $slug ); ?>', '<?php echo esc_attr( wp_create_nonce( 'wpsc_tc_get_operand' ) ); ?>');">
328 <option value=""><?php esc_attr_e( 'Compare As', 'supportcandy' ); ?></option>
329 <option <?php isset( $filter['operator'] ) && selected( $filter['operator'], '=' ); ?> value="="><?php esc_attr_e( 'Equals', 'supportcandy' ); ?></option>
330 <option <?php isset( $filter['operator'] ) && selected( $filter['operator'], 'IN' ); ?> value="IN"><?php esc_attr_e( 'Matches', 'supportcandy' ); ?></option>
331 <option <?php isset( $filter['operator'] ) && selected( $filter['operator'], 'NOT IN' ); ?> value="NOT IN"><?php esc_attr_e( 'Not Matches', 'supportcandy' ); ?></option>
332 </select>
333 </div>
334 <?php
335 break;
336
337 default:
338 do_action( 'wpsc_tc_print_operators', $slug, $filter );
339 }
340 }
341
342 /**
343 * Get condition operands ajax callback.
344 *
345 * @return void
346 */
347 public static function get_operands() {
348
349 $current_user = WPSC_Current_User::$current_user;
350
351 if ( check_ajax_referer( 'wpsc_tc_get_operand', '_ajax_nonce', false ) != 1 ) {
352 wp_send_json_error( 'Unauthorized request!', 401 );
353 }
354
355 $slug = isset( $_POST['slug'] ) ? sanitize_text_field( wp_unslash( $_POST['slug'] ) ) : '';
356 if ( ! $slug || ! array_key_exists( $slug, self::$conditions ) ) {
357 wp_send_json_error( __( 'Bad request!', 'supportcandy' ), 400 );
358 }
359
360 if ( ! in_array( $current_user->level, self::$conditions[ $slug ]['levels'] ) ) {
361 wp_send_json_error( 'Unauthorized request!', 401 );
362 }
363
364 $operator = isset( $_POST['operator'] ) ? sanitize_text_field( wp_unslash( $_POST['operator'] ) ) : '';
365 if ( ! $operator ) {
366 wp_send_json_error( __( 'Bad request!', 'supportcandy' ), 400 );
367 }
368
369 if ( self::$conditions[ $slug ]['type'] == 'cf' ) {
370
371 $cf = WPSC_Custom_Field::get_cf_by_slug( $slug );
372 $cf->type::get_operands( $operator, $cf );
373
374 } else {
375
376 self::print_operands( $slug, $operator );
377 }
378
379 wp_die();
380 }
381
382 /**
383 * Print condition operands
384 *
385 * @param string $slug - condition slug.
386 * @param string $operator - operator string.
387 * @param array $filter - predefined condition to set operand.
388 * @return void
389 */
390 public static function print_operands( $slug, $operator, $filter = array() ) {
391
392 global $wp_roles;
393
394 switch ( $slug ) {
395
396 case 'submitted_by':
397 ?>
398 <div class="item conditional operand single">
399 <select
400 class="operand_val_1">
401 <option <?php isset( $filter['operand_val_1'] ) && selected( $filter['operand_val_1'], 'user' ); ?> value="user"><?php esc_attr_e( 'User', 'supportcandy' ); ?></option>
402 <option <?php isset( $filter['operand_val_1'] ) && selected( $filter['operand_val_1'], 'agent' ); ?> value="agent"><?php esc_attr_e( 'Agent', 'supportcandy' ); ?></option>
403 </select>
404 </div>
405 <?php
406 break;
407
408 case 'user_role':
409 $is_multiple = $operator !== '=' ? true : false;
410 $unique_id = uniqid( 'wpsc_' );
411 ?>
412 <div class="item conditional operand single">
413 <select
414 class="operand_val_1 <?php echo esc_attr( $unique_id ); ?>" <?php echo $is_multiple ? 'multiple' : ''; ?>>
415 <?php
416 foreach ( $wp_roles->roles as $key => $role ) {
417 $selected = '';
418 if ( isset( $filter['operand_val_1'] ) && ( ( $is_multiple && in_array( $key, $filter['operand_val_1'] ) ) || ( ! $is_multiple && $key == $filter['operand_val_1'] ) ) ) {
419 $selected = 'selected="selected"';
420 }
421 ?>
422 <option <?php echo esc_attr( $selected ); ?> value="<?php echo esc_attr( $key ); ?>"><?php echo esc_attr( $role['name'] ); ?></option>
423 <?php
424 }
425 ?>
426 </select>
427 </div>
428 <script>jQuery('.operand_val_1.<?php echo esc_attr( $unique_id ); ?>').selectWoo();</script>
429 <?php
430 break;
431
432 default:
433 do_action( 'wpsc_tc_print_operand', $slug, $operator, $filter );
434 }
435 }
436
437 /**
438 * Get meta query for the given conditions
439 *
440 * @param string $conditions - conditions json from database.
441 * @param string $is_user_query - check if it needs to check the permission of the filter of current user. e.g. custom filters, saved filters need to check permissions but default filters need not.
442 * @return array
443 */
444 public static function get_meta_query( $conditions, $is_user_query = false ) {
445
446 $current_user = WPSC_Current_User::$current_user;
447
448 $meta_query = array();
449 $conditions = $conditions ? json_decode( html_entity_decode( $conditions ), true ) : array();
450 if ( ! $conditions ) {
451 return $meta_query;
452 }
453
454 foreach ( $conditions as $and_condition ) {
455
456 $temp = array();
457 foreach ( $and_condition as $or_condition ) {
458
459 if (
460 ! isset( self::$conditions[ $or_condition['slug'] ] ) ||
461 ( $is_user_query && ! in_array( $current_user->level, self::$conditions[ $or_condition['slug'] ]['levels'] ) )
462 ) {
463 continue;
464 }
465
466 $cf = WPSC_Custom_Field::get_cf_by_slug( $or_condition['slug'] );
467 $val = $cf->type::get_meta_value( $or_condition );
468 if ( $val === false ) {
469 continue;
470 }
471
472 $temp[] = array(
473 'slug' => $or_condition['slug'],
474 'compare' => $or_condition['operator'],
475 'val' => $val,
476 );
477 }
478
479 if ( $temp ) {
480 $meta_query[] = array_merge( array( 'relation' => 'OR' ), $temp );
481 }
482 }
483
484 return $meta_query;
485 }
486
487 /**
488 * Return whether or not given conditions are satisfied by the given ticket
489 *
490 * @param string $conditions - conditions json from database.
491 * @param WPSC_Ticket $ticket - ticket object.
492 * @return boolean
493 */
494 public static function is_valid( $conditions, $ticket ) {
495
496 $conditions = $conditions ? json_decode( html_entity_decode( $conditions ), true ) : array();
497 if ( ! $conditions ) {
498 return true;
499 }
500
501 foreach ( $conditions as $and_condition ) {
502
503 $flag = false;
504 foreach ( $and_condition as $or_condition ) {
505
506 if ( ! isset( $or_condition['slug'] ) || ! isset( self::$conditions[ $or_condition['slug'] ] ) ) {
507 continue;
508 }
509
510 if ( self::$conditions[ $or_condition['slug'] ]['type'] == 'cf' ) {
511
512 $cf = WPSC_Custom_Field::get_cf_by_slug( $or_condition['slug'] );
513 if ( in_array( $cf->type::$slug, self::$ignore_cft ) ) {
514 continue;
515 }
516 if ( $cf->field == 'customer' ) {
517 $flag = $cf->type::is_valid_customer_condition( $or_condition, $cf, $ticket->customer );
518 } else {
519 $flag = $cf->type::is_valid_ticket_condition( $or_condition, $cf, $ticket );
520 }
521 } else {
522
523 switch ( $or_condition['slug'] ) {
524
525 case 'submitted_by':
526 if (
527 (
528 $or_condition['operand_val_1'] == 'agent' &&
529 is_object( $ticket->agent_created )
530 ) ||
531 (
532 $or_condition['operand_val_1'] == 'user' &&
533 ! is_object( $ticket->agent_created )
534 )
535 ) {
536 $flag = true;
537 }
538 break;
539
540 case 'user_role':
541 $user_roles = $ticket->customer->user->roles;
542 switch ( $or_condition['operator'] ) {
543
544 case '=':
545 $flag = in_array( $or_condition['operand_val_1'], $user_roles ) ? true : false;
546 break;
547
548 case 'IN':
549 foreach ( $user_roles as $id ) {
550 if ( in_array( $id, $or_condition['operand_val_1'] ) ) {
551 $flag = true;
552 break;
553 }
554 }
555 break;
556
557 case 'NOT IN':
558 $temp = true;
559 foreach ( $user_roles as $id ) {
560 if ( in_array( $id, $or_condition['operand_val_1'] ) ) {
561 $temp = false;
562 break;
563 }
564 }
565 $flag = $temp;
566 break;
567 }
568 break;
569
570 default:
571 $flag = apply_filters( 'wpsc_tc_is_valid', $flag, $or_condition['slug'], $or_condition, $ticket );
572 break;
573 }
574 }
575
576 // no need to check further OR conditions if this condition is TRUE.
577 if ( $flag ) {
578 break;
579 }
580 }
581
582 // no need to check further AND conditions if this condition is FALSE.
583 if ( ! $flag ) {
584 return false;
585 }
586 }
587
588 // if we make upto this point, all conditions are satisfied.
589 return true;
590 }
591 }
592 endif;
593
594 WPSC_Ticket_Conditions::init();
595