PluginProbe
SupportCandy – AI Customer Support Ticket System & Live Chatbot Agent / 3.4.4
SupportCandy – AI Customer Support Ticket System & Live Chatbot Agent v3.4.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
supportcandy / includes / class-wpsc-functions.php

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

1,166 lines 30.7 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_Functions' ) ) :
7
8 final class WPSC_Functions {
9
10 /**
11 * Referance classes. Used to provide objects on runtime.
12 *
13 * @var string
14 */
15 public static $ref_classes;
16
17 /**
18 * Initialize class
19 */
20 public static function init() {
21
22 // Load ref classes.
23 add_action( 'init', array( __CLASS__, 'load_ref_classes' ), 1 );
24 }
25
26 /**
27 * Load ref classes
28 */
29 public static function load_ref_classes() {
30
31 self::$ref_classes = apply_filters( 'wpsc_load_ref_classes', array() );
32 }
33
34 /**
35 * Return an object for ref class
36 *
37 * @param string $ref_class - reference class.
38 * @param string $value - value.
39 * @return object
40 */
41 public static function get_object( $ref_class, $value ) {
42
43 $object = null;
44
45 switch ( $ref_class ) {
46
47 case 'wp_user':
48 $object = $value ? get_user_by( 'ID', $value ) : null;
49 break;
50
51 case 'datetime':
52 $object = $value && $value !== '0000-00-00 00:00:00' ? DateTime::createFromFormat( 'Y-m-d H:i:s', $value ) : '';
53 break;
54
55 case 'dateinterval':
56 $object = $value ? new DateInterval( $value ) : new DateInterval( 'PT0M' );
57 break;
58
59 case 'wpsc_cft':
60 $object = isset( self::$ref_classes[ $value ] ) ? self::$ref_classes[ $value ]['class'] : null;
61 break;
62
63 case 'wpsc_customer':
64 if ( $value && ! is_object( $object ) && isset( self::$ref_classes[ $ref_class ] ) ) {
65 $class = self::$ref_classes[ $ref_class ]['class'];
66 $object = new $class( $value );
67 } else {
68 $object = WPSC_Customer::get_anonymous_customer();
69 }
70 break;
71
72 default:
73 $object = apply_filters( 'wpsc_fun_get_object', $value, $ref_class );
74 if ( ! is_object( $object ) && isset( self::$ref_classes[ $ref_class ] ) ) {
75 $class = self::$ref_classes[ $ref_class ]['class'];
76 $object = new $class( $value );
77 }
78 }
79
80 return $object ? $object : $value;
81 }
82
83 /**
84 * Return value to be saved in model db for an abject
85 *
86 * @param string $ref_class - reference class.
87 * @param string $value - value.
88 * @return object
89 */
90 public static function set_object( $ref_class, $value ) {
91
92 $save_val = '';
93 switch ( $ref_class ) {
94
95 case 'wp_user':
96 $save_val = $value->ID;
97 break;
98
99 case 'datetime':
100 $save_val = $value->format( 'Y-m-d H:i:s' );
101 break;
102
103 case 'dateinterval':
104 $save_val = self::date_interval_to_string( $value );
105 break;
106
107 default:
108 if ( isset( self::$ref_classes[ $ref_class ] ) ) {
109 $key = self::$ref_classes[ $ref_class ]['save-key'];
110 $save_val = $value->$key;
111 }
112 }
113
114 return $save_val ? $save_val : $value;
115 }
116
117 /**
118 * Return search string given in model filters array
119 *
120 * @param array $filter - filter array.
121 * @return string
122 */
123 public static function get_filter_search_str( $filter ) {
124
125 return isset( $filter['search'] ) ? addslashes( trim( $filter['search'] ) ) : '';
126 }
127
128 /**
129 * Parse user filter for models which has static schema
130 *
131 * @param string $class_name - Class name of the model.
132 * @param array $filters - User filters array.
133 * @return string
134 */
135 public static function parse_user_filters( $class_name, $filters ) {
136
137 global $wpdb;
138
139 // Invalid filter.
140 if ( ! isset( $filters['relation'] ) || count( $filters ) < 2 ) {
141 return '1=1';
142 }
143
144 $relation = $filters['relation'];
145 $filter_str = array();
146
147 foreach ( $filters as $key => $filter ) {
148
149 // Skip if current element is relation indicator.
150 if ( $key === 'relation' ) {
151 continue;
152 }
153
154 // Invalid filter if it is not an array.
155 if ( ! is_array( $filter ) ) {
156 return '1=1';
157 }
158
159 // Call recursively if there is multi-layer filter detected.
160 if ( isset( $filter['relation'] ) ) {
161 $filter_str[] = self::parse_user_filters( $class_name, $filter );
162 continue;
163 }
164
165 // Invalid filter if it does not contain slug, compare and val indexes.
166 $slug = isset( $filter['slug'] ) ? self::sanitize_sql_key( $filter['slug'] ) : false;
167 $compare = isset( $filter['compare'] ) ? $filter['compare'] : false;
168 $val = isset( $filter['val'] ) || $filter['val'] == null ? $filter['val'] : false;
169 if ( ! $slug || ! $compare || $val === false ) {
170 return '1=1';
171 }
172
173 // custom filter.
174 if ( $slug === 'custom_query' ) {
175
176 $filter_str[] = $val;
177
178 } else {
179 switch ( $compare ) {
180
181 case '<':
182 case '=':
183 case '>':
184 case '<=':
185 case '>=':
186 if ( $class_name::$schema[ $slug ]['has_multiple_val'] ) {
187 $filter_str[] = '1=1';
188 break;
189 }
190 $filter_str[] = $slug . ' ' . $compare . ' \'' . esc_sql( $val ) . '\'';
191 break;
192
193 case 'BETWEEN':
194 $filter_str[] = $slug . ' BETWEEN \'' . esc_sql( $val[0] ) . '\' AND \'' . esc_sql( $val[1] ) . '\'';
195 break;
196
197 case 'IN':
198 if ( $class_name::$schema[ $slug ]['has_multiple_val'] ) {
199
200 $rlike = array();
201 foreach ( $val as $match ) {
202
203 $rlike[] = $slug . ' RLIKE \'(^|[|])' . esc_sql( $match ) . '($|[|])\'';
204 }
205 $filter_str[] = '( ' . implode( ' OR ', $rlike ) . ' )';
206
207 } else {
208
209 $filter_str[] = $slug . ' IN ( \'' . implode( '\', \'', esc_sql( $val ) ) . '\' )';
210 }
211 break;
212
213 case 'NOT IN':
214 if ( $class_name::$schema[ $slug ]['has_multiple_val'] ) {
215
216 $rlike = array();
217 foreach ( $val as $match ) {
218
219 $rlike[] = $slug . ' NOT RLIKE \'(^|[|])' . esc_sql( $match ) . '($|[|])\'';
220 }
221 $filter_str[] = '( ' . implode( ' OR ', $rlike ) . ' )';
222
223 } else {
224
225 $filter_str[] = $slug . ' NOT IN ( \'' . implode( '\', \'', esc_sql( $val ) ) . '\' )';
226 }
227 break;
228
229 case 'IS':
230 $filter_str[] = $slug . ' IS NULL';
231 break;
232
233 case 'IS NOT':
234 $filter_str[] = $slug . ' IS NOT NULL';
235 break;
236
237 case 'LIKE':
238 $filter_str[] = $slug . ' ' . $compare . ' \'%' . esc_sql( $wpdb->esc_like( $val ) ) . '%\'';
239 break;
240 }
241 }
242 }
243
244 return count( $filter_str ) > 1 ?
245 '( ' . implode( ' ' . $relation . ' ', $filter_str ) . ' )' :
246 $filter_str[0];
247 }
248
249 /**
250 * Get order for find method of models
251 *
252 * @param array $filter - filter array.
253 * @return string
254 */
255 public static function parse_order( $filter ) {
256
257 $orderby = isset( $filter['orderby'] ) && $filter['orderby'] ?
258 $filter['orderby'] : '';
259
260 if ( ! $orderby ) {
261 return '';
262 }
263
264 $order = isset( $filter['order'] ) && $filter['order'] && in_array( $filter['order'], array( 'ASC', 'DESC' ) ) ?
265 $filter['order'] : 'ASC';
266
267 $orderby_slug = isset( $filter['orderby_slug'] ) && $filter['orderby_slug'] ? $filter['orderby_slug'] : '';
268 $cf = WPSC_Custom_Field::get_cf_by_slug( $orderby_slug );
269
270 if ( $cf && $cf->type::$slug == 'cf_number' ) {
271
272 return 'ORDER BY CAST(' . $orderby . ' AS SIGNED ) ' . $order . ' ';
273 } else {
274
275 return 'ORDER BY ' . $orderby . ' ' . $order . ' ';
276 }
277 }
278
279 /**
280 * Get order for find method of models
281 *
282 * @param array $filter - filter array.
283 * @return string
284 */
285 public static function parse_limit( $filter ) {
286
287 $items_per_page = isset( $filter['items_per_page'] ) ?
288 intval( $filter['items_per_page'] ) : 0;
289
290 if ( $items_per_page == 0 ) {
291 return '';
292 }
293
294 $page_no = isset( $filter['page_no'] ) && is_numeric( $filter['page_no'] ) ?
295 intval( $filter['page_no'] ) : 1;
296
297 $offset = ( $page_no - 1 ) * $items_per_page;
298
299 return 'LIMIT ' . $offset . ', ' . $items_per_page;
300 }
301
302 /**
303 * Calculate total pages, has_next_page, results, etc. for models
304 *
305 * @param string $results - page result.
306 * @param int $total_items - total page items.
307 * @param array $filter - filter items.
308 * @return array
309 */
310 public static function parse_response( $results, int $total_items, $filter ) {
311
312 $items_per_page = isset( $filter['items_per_page'] ) ?
313 intval( $filter['items_per_page'] ) : 0;
314
315 if ( ! $items_per_page ) {
316 return array(
317 'total_items' => $total_items,
318 'results' => $results,
319 );
320 }
321
322 $page_no = isset( $filter['page_no'] ) && is_numeric( $filter['page_no'] ) ?
323 intval( $filter['page_no'] ) : 1;
324
325 $total_pages = ceil( $total_items / $items_per_page );
326
327 $has_next_page = $page_no < $total_pages ? true : false;
328
329 return array(
330 'total_items' => $total_items,
331 'items_per_page' => $items_per_page,
332 'current_page' => $page_no,
333 'total_pages' => $total_pages,
334 'has_next_page' => $has_next_page,
335 'results' => $results,
336 );
337 }
338
339 /**
340 * Check whether current page is supportcandy page or not
341 * Used for loading framework.
342 * Pages like dashboard pages and where wpsc shortcode is present are considered true.
343 *
344 * @return boolean
345 */
346 public static function is_wpsc_page() {
347
348 if ( is_admin() ) {
349
350 return isset( $_REQUEST['page'] ) && preg_match( '/wpsc-/', $_REQUEST['page'] ) ? true : false; // phpcs:ignore
351
352 } else {
353
354 return true;
355 }
356 }
357
358 /**
359 * Check whether current use is site admin or not
360 *
361 * @return boolean
362 */
363 public static function is_site_admin() {
364
365 global $current_user;
366 return $current_user && $current_user->ID && $current_user->has_cap( 'manage_options' ) ? true : false;
367 }
368
369 /**
370 * Get default filter auto-increament number
371 *
372 * @return integer
373 */
374 public static function get_tl_df_auto_increament() {
375
376 $index = intval( get_option( 'wpsc-tl-df-auto-increament', 0 ) );
377 update_option( 'wpsc-tl-df-auto-increament', ++$index );
378 return $index;
379 }
380
381 /**
382 * Get user custom filter auto-increament number
383 *
384 * @return integer
385 */
386 public static function get_tl_cf_auto_increament() {
387
388 global $current_user;
389 $index = intval( get_user_meta( $current_user->ID, get_current_blog_id() . '-wpsc-tl-cf-auto-increament', true ) );
390 update_user_meta( $current_user->ID, get_current_blog_id() . '-wpsc-tl-cf-auto-increament', ++$index );
391 return $index;
392 }
393
394 /**
395 * Return css classes string as per size
396 *
397 * @param WPSC_custom_field $cf - custom field.
398 * @param WPSC_TFF $tff - ticket form field.
399 * @return string
400 */
401 public static function get_tff_classes( $cf, $tff ) {
402
403 $classes = 'wpsc-tff ' . $cf->slug . ' wpsc-xs-12 ';
404 switch ( $tff['width'] ) {
405 case '1/3':
406 $classes .= 'wpsc-sm-4 wpsc-md-4 wpsc-lg-4 ';
407 break;
408
409 case 'half':
410 $classes .= 'wpsc-sm-6 wpsc-md-6 wpsc-lg-6 ';
411 break;
412
413 case 'full':
414 $classes .= 'wpsc-sm-12 wpsc-md-12 wpsc-lg-12 ';
415 break;
416 }
417 $classes .= $tff['is-required'] ? 'required ' : '';
418 $visibility = WPSC_TFF::get_visibility( $tff, true );
419 $classes .= $visibility ? 'wpsc-hidden conditional' : 'wpsc-visible';
420
421 return $classes;
422 }
423
424 /**
425 * Sort an array with key
426 *
427 * @param array $array_name - macro array.
428 * @param array $on - title.
429 * @param array $order - SORT_ASC.
430 * @return array
431 */
432 public static function array_sort( $array_name, $on, $order = SORT_ASC ) {
433
434 $new_array = array();
435 $sortable_array = array();
436
437 if ( count( $array_name ) > 0 ) {
438 foreach ( $array_name as $k => $v ) {
439 if ( is_array( $v ) ) {
440 foreach ( $v as $k2 => $v2 ) {
441 if ( $k2 == $on ) {
442 $sortable_array[ $k ] = $v2;
443 }
444 }
445 } else {
446 $sortable_array[ $k ] = $v;
447 }
448 }
449 switch ( $order ) {
450 case SORT_ASC:
451 asort( $sortable_array );
452 break;
453 case SORT_DESC:
454 arsort( $sortable_array );
455 break;
456 }
457 foreach ( $sortable_array as $k => $v ) {
458 $new_array[ $k ] = $array_name[ $k ];
459 }
460 }
461 return $new_array;
462 }
463
464 /**
465 * Convert date from WP timezone date to UTC equivalant date
466 *
467 * @param string $date_str - date to UTC equivalant date.
468 * @return DateTime
469 */
470 public static function get_utc_date_str( $date_str ) {
471
472 $tz = wp_timezone();
473 $date = DateTime::createFromFormat( 'Y-m-d H:i:s', $date_str, $tz );
474 $date->setTimezone( new DateTimeZone( '+0000' ) );
475 return $date->format( 'Y-m-d H:i:s' );
476 }
477
478 /**
479 * Get new ticket url
480 *
481 * @return string
482 */
483 public static function get_new_ticket_url() {
484
485 $page_settings = get_option( 'wpsc-gs-page-settings' );
486 $url = '';
487
488 if ( $page_settings['new-ticket-page'] == 'default' && $page_settings['support-page'] ) {
489
490 $url = get_permalink( $page_settings['support-page'] );
491 $url = add_query_arg( array( 'wpsc-section' => 'new-ticket' ), $url );
492
493 } elseif ( $page_settings['new-ticket-page'] == 'custom' && $page_settings['new-ticket-url'] ) {
494
495 $url = $page_settings['new-ticket-url'];
496 }
497
498 return apply_filters( 'wpsc_get_new_ticket_url', $url );
499 }
500
501 /**
502 * Load package for third-party php library without composer
503 *
504 * @param string $dir - directory path of package.
505 * @return void
506 */
507 public static function load_library( $dir ) {
508
509 $composer = json_decode( file_get_contents( "$dir/composer.json" ), 1 ); // phpcs:ignore
510 $namespaces = $composer['autoload']['psr-4'];
511
512 // Foreach namespace specified in the composer, load the given classes.
513 foreach ( $namespaces as $namespace => $classpaths ) {
514 if ( ! is_array( $classpaths ) ) {
515 $classpaths = array( $classpaths );
516 }
517 spl_autoload_register(
518 function ( $classname ) use ( $namespace, $classpaths, $dir ) {
519 // Check if the namespace matches the class we are looking for.
520 if ( preg_match( '#^' . preg_quote( $namespace, '/' ) . '#', $classname ) ) {
521 // Remove the namespace from the file path since it's psr4.
522 $classname = str_replace( $namespace, '', $classname );
523 $filename = preg_replace( '#\\\\#', '/', $classname ) . '.php';
524 foreach ( $classpaths as $classpath ) {
525 $fullpath = $dir . '/' . $classpath . "/$filename";
526 if ( file_exists( $fullpath ) ) {
527 include_once $fullpath;
528 }
529 }
530 }
531 }
532 );
533 }
534 }
535
536 /**
537 * Create a random string
538 *
539 * @param integer $length - random strig lenght.
540 * @return string
541 */
542 public static function get_random_string( $length = 8 ) {
543
544 $characters = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
545 $string = '';
546 for ( $i = 0; $i < $length; $i++ ) {
547 $string .= $characters[ wp_rand( 0, strlen( $characters ) - 1 ) ];
548 }
549 return $string;
550 }
551
552 /**
553 * Perform sum of date intervals
554 *
555 * @param array $arr - date interval array.
556 * @return DateInterval
557 */
558 public static function date_interval_sum( $arr ) {
559
560 $response = $arr[0];
561 $arrau_count = count( $arr );
562 for ( $i = 1; $i < $arrau_count; $i++ ) {
563 $today = new DateTime();
564 $sum_today = clone $today;
565 $sum_today->add( $response );
566 $sum_today->add( $arr[ $i ] );
567 $response = $today->diff( $sum_today );
568 }
569 return $response;
570 }
571
572 /**
573 * Return string representation of date interval
574 *
575 * @param DateInterval $diff - date interval.
576 * @return string
577 */
578 public static function date_interval_to_string( $diff ) {
579
580 $str = 'P';
581
582 if ( $diff->days ) {
583
584 $str .= $diff->format( '%aD' );
585
586 } elseif ( $diff->d ) {
587
588 $str .= $diff->format( '%dD' );
589
590 }
591
592 if ( $diff->h || $diff->i ) {
593
594 $str .= 'T';
595 $str .= $diff->h ? $diff->format( '%hH' ) : '';
596 $str .= $diff->i ? $diff->format( '%iM' ) : '';
597 }
598
599 if ( $str === 'P' ) {
600 $str = 'PT0M';
601 }
602
603 return $str;
604 }
605
606 /**
607 * Return readable time interval so that we can print this on user interface.
608 *
609 * @param DateInterval $diff - time interval.
610 * @return string
611 */
612 public static function date_interval_to_readable( $diff ) {
613
614 $arr = array();
615
616 // days.
617 if ( $diff->days ) {
618
619 $arr[] = sprintf(
620 /* translators: %d: number of days */
621 __( '%dd', 'supportcandy' ),
622 $diff->format( '%a' )
623 );
624
625 } elseif ( $diff->d ) {
626
627 $arr[] = sprintf(
628 /* translators: %d: number of days */
629 __( '%dd', 'supportcandy' ),
630 $diff->format( '%d' )
631 );
632
633 }
634
635 // hours.
636 if ( $diff->h ) {
637 $arr[] = sprintf(
638 /* translators: %d: number of hours */
639 __( '%dh', 'supportcandy' ),
640 $diff->format( '%h' )
641 );
642 }
643
644 // minutes.
645 if ( $diff->i ) {
646 $arr[] = sprintf(
647 /* translators: %d: number of minutes */
648 __( '%dm', 'supportcandy' ),
649 $diff->format( '%i' )
650 );
651 }
652
653 return $arr ? implode( ' ', $arr ) : '0m';
654 }
655
656 /**
657 * Return time interval object from readable string (usually comes from user interface)
658 *
659 * @param string $str - string to date format.
660 * @return DateInterval
661 */
662 public static function readable_to_date_interval( $str ) {
663
664 // remove spaces in between.
665 $str = str_replace( ' ', '', $str );
666
667 // invalid if not given.
668 if ( ! $str ) {
669 return false;
670 }
671
672 // validate format.
673 $flag = preg_match( '/^(\d*d)?(\d*h)?(\d*m)?$/', $str, $matches );
674 if ( ! $flag ) {
675 return false;
676 }
677
678 // build interval string.
679 $str = 'P';
680 $str .= $matches[1] ? strtoupper( $matches[1] ) : '';
681 if ( $matches[2] || $matches[3] ) {
682 $str .= 'T';
683 $str .= $matches[2] ? strtoupper( $matches[2] ) : '';
684 $str .= $matches[3] ? strtoupper( $matches[3] ) : '';
685 }
686
687 // return dateinterval object.
688 return new DateInterval( $str );
689 }
690
691 /**
692 * Return time ago string for highest unit. For example, if difference is 2hr 30min 34sec then return 2 hour ago.
693 *
694 * @param DateInterval $diff - date interval object.
695 * @return string
696 */
697 public static function date_interval_highest_unit_ago( $diff ) {
698
699 // return years if any.
700 if ( $diff->y ) {
701 return sprintf(
702 /* translators: %d: number of years */
703 __( '%d years ago', 'supportcandy' ),
704 intval( $diff->format( '%y' ) )
705 );
706 }
707
708 // return months if any.
709 if ( $diff->m ) {
710 return sprintf(
711 /* translators: %d: number of months */
712 __( '%d months ago', 'supportcandy' ),
713 intval( $diff->format( '%m' ) )
714 );
715 }
716
717 // return days if any.
718 $days = $diff->days ? intval( $diff->format( '%a' ) ) : intval( $diff->format( '%d' ) );
719 if ( $days ) {
720 return sprintf(
721 /* translators: %d: number of days */
722 __( '%d days ago', 'supportcandy' ),
723 $days
724 );
725 }
726
727 // return hours if any.
728 if ( $diff->h ) {
729 return sprintf(
730 /* translators: %d: number of hours */
731 __( '%d hours ago', 'supportcandy' ),
732 intval( $diff->format( '%h' ) )
733 );
734 }
735
736 // return minutes if any.
737 if ( $diff->i ) {
738 return sprintf(
739 /* translators: %d: number of minutes */
740 __( '%d minutes ago', 'supportcandy' ),
741 intval( $diff->format( '%i' ) )
742 );
743 }
744
745 // return seconds if any.
746 if ( $diff->s ) {
747 return sprintf(
748 /* translators: %d: number of seconds */
749 __( '%d seconds ago', 'supportcandy' ),
750 intval( $diff->format( '%s' ) )
751 );
752 }
753
754 return __( 'Just now', 'supportcandy' );
755 }
756
757 /**
758 * Return day name
759 *
760 * @param int $day - week days.
761 * @return string
762 */
763 public static function get_day_name( $day ) {
764
765 $days = array(
766 1 => wpsc__( 'Monday' ),
767 2 => wpsc__( 'Tuesday' ),
768 3 => wpsc__( 'Wednesday' ),
769 4 => wpsc__( 'Thursday' ),
770 5 => wpsc__( 'Friday' ),
771 6 => wpsc__( 'Saturday' ),
772 7 => wpsc__( 'Sunday' ),
773 );
774 return isset( $days[ $day ] ) ? $days[ $day ] : '';
775 }
776
777 /**
778 * Return month name
779 *
780 * @param int $month - month names.
781 * @return string
782 */
783 public static function get_month_name( $month ) {
784
785 $months = array(
786 1 => wpsc__( 'January' ),
787 2 => wpsc__( 'February' ),
788 3 => wpsc__( 'March' ),
789 4 => wpsc__( 'April' ),
790 5 => wpsc__( 'May' ),
791 6 => wpsc__( 'June' ),
792 7 => wpsc__( 'July' ),
793 8 => wpsc__( 'August' ),
794 9 => wpsc__( 'September' ),
795 10 => wpsc__( 'October' ),
796 11 => wpsc__( 'November' ),
797 12 => wpsc__( 'December' ),
798 );
799 return isset( $months[ $month ] ) ? $months[ $month ] : '';
800 }
801
802 /**
803 * Sanitize SQL key to allow only possible lowercase keys with joins.
804 *
805 * @param string $key - key to sanitize.
806 * @return string
807 */
808 public static function sanitize_sql_key( $key ) {
809
810 $sanitized_key = '';
811
812 if ( is_scalar( $key ) ) {
813 $key = strtolower( $key );
814 if ( preg_match( '/^([a-z]{1,2}\.)?[a-z0-9_]+$/', $key ) ) {
815 $sanitized_key = $key;
816 }
817 }
818
819 return $sanitized_key;
820 }
821
822 /**
823 * Sanitize date string e.g. "2022-12-25" and return with datetime format
824 *
825 * @param string $date - date string to be sanitized.
826 * @return string
827 */
828 public static function sanitize_date( $date ) {
829
830 if ( ! $date ) {
831 return $date;
832 }
833
834 if ( ! preg_match( '/\d{4}-\d{2}-\d{2}/', $date ) ) {
835 return '';
836 }
837
838 $format = 'Y-m-d';
839 $d = DateTime::createFromFormat( $format, $date );
840 return $d && $d->format( $format ) == $date ? $date . ' 00:00:00' : '';
841 }
842
843 /**
844 * Sanitize date string e.g. "2022-12-25 12:00:00"
845 *
846 * @param string $date - date string to be sanitized.
847 * @return string
848 */
849 public static function sanitize_datetime( $date ) {
850
851 if ( ! $date ) {
852 return $date;
853 }
854
855 if ( ! preg_match( '/\d{4}-\d{2}-\d{2}\s\d{2}:\d{2}/', $date ) ) {
856 return '';
857 }
858
859 $format = 'Y-m-d H:i';
860 $d = DateTime::createFromFormat( $format, $date );
861 return $d && $d->format( $format ) == $date ? $date . ':00' : '';
862 }
863
864 /**
865 * Sanitize time string e.g. "12:31"
866 *
867 * @param string $time - time string to be sanitized.
868 * @return string
869 */
870 public static function sanitize_time( $time ) {
871
872 if ( ! $time ) {
873 return $time;
874 }
875
876 if ( ! preg_match( '/(\d{2}):(\d{2})/', $time, $matches ) ) {
877 return '';
878 }
879
880 return intval( $matches[1] ) < 24 && intval( $matches[2] ) < 60 ? $time : '';
881 }
882
883 /**
884 * Sanitiize email string
885 *
886 * @param string $email - email string to be sanitized.
887 * @return string
888 */
889 public static function sanitize_email( $email ) {
890
891 return filter_var( $email, FILTER_VALIDATE_EMAIL ) ? $email : '';
892 }
893
894 /**
895 * Sanitiize url string
896 *
897 * @param string $url - email string to be sanitized.
898 * @return string
899 */
900 public static function sanitize_url( $url ) {
901
902 return filter_var( $url, FILTER_VALIDATE_URL ) ? $url : '';
903 }
904
905 /**
906 * Sanitize attachment id came as user input
907 *
908 * @param integer $id - attachment id.
909 * @return integer|boolean
910 */
911 public static function sanitize_attachment( $id ) {
912
913 if ( ! $id ) {
914 return false;
915 }
916
917 $attachment = new WPSC_Attachment( $id );
918 return $attachment->id ? $id : false;
919 }
920
921 /**
922 * Sanitize option id provided by user
923 *
924 * @param integer $id - option id.
925 * @param WPSC_Custom_Field $cf - custom field object.
926 * @param array $options - array of option objects.
927 * @return integer|boolean
928 */
929 public static function sanitize_option( $id, $cf, $options ) {
930
931 $option = new WPSC_Option( $id );
932 $options = array_filter(
933 array_map(
934 fn( $option ) => $option->id ? $option->id : false,
935 $options
936 )
937 );
938 return $option->id && in_array( $option->id, $options ) ? $id : false;
939 }
940
941 /**
942 * Get current langauge iso code. Use for datepicker library.
943 *
944 * @return string
945 */
946 public static function get_locale_iso() {
947
948 $locale = substr( get_locale(), 0, 2 );
949 if ( $locale == 'el' ) {
950 $locale = 'gr';
951 }
952 return $locale;
953 }
954
955 /**
956 * Get anonymous customer id.
957 *
958 * @return object
959 */
960 public static function anonymous_customer() {
961
962 global $wpdb;
963 $id = get_option( 'wpsc-anonymous-user-id' );
964 if ( ! $id ) {
965
966 // add anonymuos customer to customer table.
967 $success = $wpdb->insert(
968 $wpdb->prefix . 'psmsc_customers',
969 array(
970 'name' => 'Anonymous',
971 'email' => '[email protected]',
972 )
973 );
974 if ( ! $success ) {
975 return false;
976 }
977
978 // Store anonymous customer ID in option.
979 $id = $wpdb->insert_id;
980 update_option( 'wpsc-anonymous-user-id', $id );
981 }
982
983 $anonymous = new WPSC_Customer( $id );
984 return $anonymous;
985 }
986
987 /**
988 * Calculate date range
989 *
990 * @param string $date - date string.
991 * @return array
992 */
993 public static function get_dashboard_date_range( $date ) {
994
995 $today = new DateTime();
996 switch ( $date ) {
997 case 'today':
998 // Start of today at 00:00:00.
999 $today_start = clone $today;
1000 $today_start->setTime( 0, 0, 0 );
1001 // End of today with the current time.
1002 $today_end = clone $today;
1003 return array( $today_start->format( 'Y-m-d H:i:s' ), $today_end->format( 'Y-m-d H:i:s' ) );
1004
1005 case 'yesterday':
1006 // Start of yesterday at 00:00:00.
1007 $yesterday_start = clone $today;
1008 $yesterday_start->modify( '-1 day' )->setTime( 0, 0, 0 );
1009 // End of yesterday at 23:59:59.
1010 $yesterday_end = clone $yesterday_start;
1011 $yesterday_end->setTime( 23, 59, 59 );
1012 return array( $yesterday_start->format( 'Y-m-d H:i:s' ), $yesterday_end->format( 'Y-m-d H:i:s' ) );
1013
1014 case 'last-7':
1015 // Calculate last 7 days from today's date.
1016 $last7_days_start = clone $today;
1017 $last7_days_start->modify( '-6 days' )->setTime( 0, 0, 0 );
1018 $last7_days_end = clone $today;
1019 $last7_days_end->setTime( 23, 59, 59 );
1020 return array( $last7_days_start->format( 'Y-m-d H:i:s' ), $last7_days_end->format( 'Y-m-d H:i:s' ) );
1021
1022 case 'this-week':
1023 // Calculate this week's start and end (Sunday to Saturday).
1024 $week_start = clone $today;
1025 $week_start->modify( 'last Sunday' )->setTime( 0, 0, 0 );
1026 $week_end = clone $week_start;
1027 $week_end->modify( 'next Saturday' )->setTime( 23, 59, 59 );
1028 return array( $week_start->format( 'Y-m-d H:i:s' ), $week_end->format( 'Y-m-d H:i:s' ) );
1029
1030 case 'last-week':
1031 // Calculate last week's start and end (Sunday to Saturday).
1032 $last_week_start = clone $today;
1033 $last_week_start->modify( 'last Sunday' )->sub( new DateInterval( 'P7D' ) )->setTime( 0, 0, 0 );
1034 $last_week_end = clone $last_week_start;
1035 $last_week_end->modify( 'next Saturday' )->setTime( 23, 59, 59 );
1036 return array( $last_week_start->format( 'Y-m-d H:i:s' ), $last_week_end->format( 'Y-m-d H:i:s' ) );
1037
1038 case 'last-30-days':
1039 // Calculate last 30 days from today's date.
1040 $last30_days_start = clone $today;
1041 $last30_days_start->modify( '-29 days' )->setTime( 0, 0, 0 );
1042 return array( $last30_days_start->format( 'Y-m-d H:i:s' ), $today->format( 'Y-m-d H:i:s' ) );
1043
1044 case 'this-month':
1045 // Calculate this month's start and end date.
1046 $start_month = clone $today;
1047 $start_month->modify( 'first day of this month' )->setTime( 0, 0, 0 );
1048 $end_month = clone $today;
1049 $end_month->setTime( 23, 59, 59 );
1050 return array( $start_month->format( 'Y-m-d H:i:s' ), $end_month->format( 'Y-m-d H:i:s' ) );
1051
1052 case 'this-quarter':
1053 // Calculate this quarter's start and end date.
1054 $month = (int) $today->format( 'n' );
1055 $start_quarter = clone $today;
1056 $start_quarter->setDate( $today->format( 'Y' ), floor( ( $month - 1 ) / 3 ) * 3 + 1, 1 )->setTime( 0, 0, 0 );
1057 return array( $start_quarter->format( 'Y-m-d H:i:s' ), $today->format( 'Y-m-d H:i:s' ) );
1058
1059 case 'this-year':
1060 // Calculate this year's start date to today.
1061 $start_year = clone $today;
1062 $start_year->setDate( $today->format( 'Y' ), 1, 1 )->setTime( 0, 0, 0 );
1063 return array( $start_year->format( 'Y-m-d H:i:s' ), $today->format( 'Y-m-d H:i:s' ) );
1064
1065 case 'last-month':
1066 // Calculate last month's start and end date.
1067 $last_month_start = clone $today;
1068 $last_month_start->modify( 'first day of last month' )->setTime( 0, 0, 0 );
1069 $last_month_end = clone $today;
1070 $last_month_end->modify( 'last day of last month' )->setTime( 23, 59, 59 );
1071 return array( $last_month_start->format( 'Y-m-d H:i:s' ), $last_month_end->format( 'Y-m-d H:i:s' ) );
1072
1073 case 'last-quarter':
1074 // Last quarter: from the first to the last day of the previous quarter.
1075 $current_month = (int) $today->format( 'n' );
1076
1077 // Calculate the first month of the previous quarter.
1078 $last_quarter_start_month = 3 * ( floor( ( $current_month - 1 ) / 3 ) ) - 2;
1079 if ( $last_quarter_start_month <= 0 ) {
1080 // If the calculated month is 0 or negative, it means we are in Q1, so the last quarter is Q4 of the previous year.
1081 $last_quarter_start_month += 12;
1082 $start_last_quarter = ( clone $today )->setDate( $today->format( 'Y' ) - 1, $last_quarter_start_month, 1 )->setTime( 0, 0, 0 );
1083 } else {
1084 $start_last_quarter = ( clone $today )->setDate( $today->format( 'Y' ), $last_quarter_start_month, 1 )->setTime( 0, 0, 0 );
1085 }
1086
1087 // Calculate the end of the last quarter.
1088 $end_last_quarter = clone $start_last_quarter;
1089 $end_last_quarter->modify( '+2 months' )->modify( 'last day of this month' )->setTime( 23, 59, 59 );
1090
1091 return array( $start_last_quarter->format( 'Y-m-d H:i:s' ), $end_last_quarter->format( 'Y-m-d H:i:s' ) );
1092
1093 case 'last-year':
1094 // Calculate last year's start and end date.
1095 $start_last_year = clone $today;
1096 $start_last_year->setDate( $today->format( 'Y' ) - 1, 1, 1 )->setTime( 0, 0, 0 );
1097 $end_last_year = clone $start_last_year;
1098 $end_last_year->setDate( $today->format( 'Y' ) - 1, 12, 31 )->setTime( 23, 59, 59 );
1099 return array( $start_last_year->format( 'Y-m-d H:i:s' ), $end_last_year->format( 'Y-m-d H:i:s' ) );
1100 }
1101 }
1102
1103 /**
1104 * Generate random colors.
1105 *
1106 * @return string
1107 */
1108 public static function generate_random_color() {
1109 $min_luminance = 0.7; // Adjust this value based on your preference.
1110
1111 do {
1112 $color = wp_rand( 0x000000, 0xFFFFFF );
1113 $red = ( $color >> 16 ) & 0xFF;
1114 $green = ( $color >> 8 ) & 0xFF;
1115 $blue = $color & 0xFF;
1116
1117 // Calculate luminance (brightness).
1118 $luminance = ( 0.299 * $red + 0.587 * $green + 0.114 * $blue ) / 255;
1119
1120 } while ( $luminance < $min_luminance );
1121
1122 return '#' . dechex( $color );
1123 }
1124
1125 /**
1126 * Get ticket url depending on view using ticket id.
1127 *
1128 * @param int $ticket_id - ticket id.
1129 * @param string $view - view - frontend/backend.
1130 * @return string
1131 */
1132 public static function get_ticket_url( $ticket_id, $view ) {
1133
1134 $url = '';
1135 $page_settings = get_option( 'wpsc-gs-page-settings' );
1136 $view = (int) $view;
1137 if ( $view === 0 ) {
1138 $url = admin_url( 'admin.php?page=wpsc-tickets&section=ticket-list&id=' . $ticket_id );
1139 } elseif ( $page_settings['ticket-url-page'] == 'support-page' && $page_settings['support-page'] ) {
1140 $url = get_permalink( $page_settings['support-page'] );
1141 $url = add_query_arg(
1142 array(
1143 'wpsc-section' => 'ticket-list',
1144 'ticket-id' => $ticket_id,
1145 ),
1146 $url
1147 );
1148 } elseif ( $page_settings['ticket-url-page'] == 'open-ticket-page' && $page_settings['open-ticket-page'] ) {
1149 $url = get_permalink( $page_settings['open-ticket-page'] );
1150 $ticket = new WPSC_Ticket( $ticket_id );
1151 $url = add_query_arg(
1152 array(
1153 'ticket-id' => $ticket_id,
1154 'auth-code' => $ticket->auth_code,
1155 ),
1156 $url
1157 );
1158 }
1159
1160 return apply_filters( 'wpsc_get_ticket_url_by_view', $url, $ticket_id, $view );
1161 }
1162 }
1163 endif;
1164
1165 WPSC_Functions::init();
1166