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 | class-wpsc-installation.php +825 -226 3.3.6 → 3.5.4 View file →
@@ -232,8 +232,9 @@
232 232 source VARCHAR(200) NOT NULL,
233 233 source_id BIGINT NOT NULL DEFAULT 0,
234 234 ticket_id BIGINT NOT NULL DEFAULT 0,
235 235 customer_id BIGINT NOT NULL DEFAULT 0,
236 + uploaded_by VARCHAR(64) NOT NULL DEFAULT '',
236 237 PRIMARY KEY (id)
237 238 ) $collate;
238 239 CREATE TABLE {$wpdb->prefix}psmsc_agents (
239 240 id BIGINT NOT NULL AUTO_INCREMENT,
@@ -282,9 +283,9 @@
282 283 ) $collate;
283 284 CREATE TABLE {$wpdb->prefix}psmsc_email_otp (
284 285 id INT NOT NULL AUTO_INCREMENT,
285 286 email VARCHAR(200) NOT NULL,
286 - otp INT NOT NULL,
287 + otp VARCHAR(10) NOT NULL,
287 288 date_expiry DATETIME NOT NULL,
288 289 data LONGTEXT NULL DEFAULT NULL,
289 290 PRIMARY KEY (id)
290 291 ) $collate;
@@ -322,11 +323,99 @@
322 323 color VARCHAR(50) NOT NULL,
323 324 bg_color VARCHAR(50) NOT NULL,
324 325 PRIMARY KEY (id)
325 326 ) $collate;
327 + CREATE TABLE {$wpdb->prefix}psmsc_ai_logs (
328 + id BIGINT NOT NULL AUTO_INCREMENT,
329 + customer BIGINT NOT NULL,
330 + ticket BIGINT NOT NULL,
331 + provider VARCHAR(100) NOT NULL,
332 + model VARCHAR(100) NOT NULL,
333 + feature VARCHAR(50) NOT NULL,
334 + tokens INT NOT NULL,
335 + prompt LONGTEXT NOT NULL,
336 + date_created DATETIME NOT NULL,
337 + PRIMARY KEY (id),
338 + KEY customer (customer),
339 + KEY date_created (date_created)
340 + ) $collate;
341 + CREATE TABLE {$wpdb->prefix}psmsc_ai_training (
342 + id BIGINT NOT NULL AUTO_INCREMENT,
343 + status VARCHAR(20) NOT NULL,
344 + provider VARCHAR(50) NOT NULL,
345 + source VARCHAR(50) NOT NULL,
346 + source_id BIGINT NOT NULL,
347 + doc_source VARCHAR(255) NULL,
348 + name VARCHAR(255) NOT NULL,
349 + file_path VARCHAR(500) NOT NULL,
350 + provider_file_id VARCHAR(255) NULL,
351 + meta_data LONGTEXT NULL,
352 + post_updated_on DATETIME NOT NULL,
353 + date_updated DATETIME NOT NULL,
354 + date_created DATETIME NOT NULL,
355 + PRIMARY KEY (id),
356 + INDEX idx_status (status),
357 + INDEX idx_source (source),
358 + INDEX idx_status_source (status, source)
359 + ) $collate;
360 + CREATE TABLE {$wpdb->prefix}psmsc_acb_sessions (
361 + id BIGINT NOT NULL AUTO_INCREMENT,
362 + session_id CHAR(36) NOT NULL,
363 + visitor_id CHAR(36) NOT NULL,
364 + subject LONGTEXT NULL,
365 + provider VARCHAR(20) NOT NULL DEFAULT '',
366 + reaction tinyint(1) NULL,
367 + ticket_id BIGINT NULL,
368 + status tinyint(1) NOT NULL,
369 + token_count INT UNSIGNED NOT NULL,
370 + last_activity DATETIME NOT NULL,
371 + date_created DATETIME NOT NULL,
372 + PRIMARY KEY (id),
373 + UNIQUE KEY session_id (session_id),
374 + KEY visitor_id (visitor_id),
375 + KEY status (status),
376 + KEY date_created (date_created)
377 + ) $collate;
378 + CREATE TABLE {$wpdb->prefix}psmsc_acb_messages (
379 + id BIGINT NOT NULL AUTO_INCREMENT,
380 + session_id CHAR(36) NOT NULL,
381 + sender VARCHAR(10) NOT NULL,
382 + message LONGTEXT NULL,
383 + token_count INT UNSIGNED NOT NULL,
384 + date_created DATETIME NOT NULL,
385 + PRIMARY KEY (id),
386 + KEY session_id (session_id),
387 + KEY session_messages (session_id, date_created)
388 + ) $collate;
326 389 ";
327 390
328 391 dbDelta( $tables );
392 +
393 + // Copy structure of psmsc_ticket table to psmsc_archived_tickets table.
394 + if ( $wpdb->get_var( "SHOW TABLES LIKE '{$wpdb->prefix}psmsc_archived_tickets'" ) !== "{$wpdb->prefix}psmsc_archived_tickets" ) {
395 + $wpdb->query( "CREATE TABLE {$wpdb->prefix}psmsc_archived_tickets LIKE {$wpdb->prefix}psmsc_tickets" );
396 + }
397 +
398 + // Copy structure of psmsc_thread table to psmsc_archived_threads table.
399 + if ( $wpdb->get_var( "SHOW TABLES LIKE '{$wpdb->prefix}psmsc_archived_threads'" ) !== "{$wpdb->prefix}psmsc_archived_threads" ) {
400 + $wpdb->query( "CREATE TABLE {$wpdb->prefix}psmsc_archived_threads LIKE {$wpdb->prefix}psmsc_threads" );
401 + }
402 +
403 + // AI assistant feature: add 'ticket_summary' column to tickets and archived tickets table.
404 + $column_exists = $wpdb->get_results( "SHOW COLUMNS FROM {$wpdb->prefix}psmsc_tickets LIKE 'ticket_summary'" );
405 + if ( empty( $column_exists ) ) {
406 + $wpdb->query( "ALTER TABLE {$wpdb->prefix}psmsc_tickets ADD ticket_summary TEXT NULL" );
407 + }
408 + $column_exists = $wpdb->get_results( "SHOW COLUMNS FROM {$wpdb->prefix}psmsc_archived_tickets LIKE 'ticket_summary'" );
409 + if ( empty( $column_exists ) ) {
410 + $wpdb->query( "ALTER TABLE {$wpdb->prefix}psmsc_archived_tickets ADD ticket_summary TEXT NULL" );
411 + }
412 +
413 + // Attachment ownership: add 'uploaded_by' column to attachments table.
414 + $column_exists = $wpdb->get_results( "SHOW COLUMNS FROM {$wpdb->prefix}psmsc_attachments LIKE 'uploaded_by'" );
415 + if ( empty( $column_exists ) ) {
416 + $wpdb->query( "ALTER TABLE {$wpdb->prefix}psmsc_attachments ADD uploaded_by VARCHAR(64) NOT NULL DEFAULT ''" );
417 + }
329 418 }
330 419
331 420 /**
332 421 * First time installation
@@ -334,16 +423,13 @@
334 423 public static function initial_setup() {
335 424
336 425 global $wpdb;
337 426
338 - $wpdb->query( 'SET auto_increment_increment = 1' );
339 - $wpdb->query( 'SET auto_increment_offset = 1' );
340 -
341 427 // string translations.
342 428 $string_translations = array();
343 429
344 430 // Insert default custom fields.
345 - $name = esc_attr__( 'ID', 'supportcandy' );
431 + $name = __( 'ID', 'supportcandy' );
346 432 $wpdb->insert(
347 433 $wpdb->prefix . 'psmsc_custom_fields',
348 434 array(
349 435 'name' => $name,
@@ -355,10 +441,10 @@
355 441 )
356 442 );
357 443 $string_translations[ 'wpsc-cf-name-' . $wpdb->insert_id ] = $name;
358 444
359 - $name = esc_attr__( 'Customer', 'supportcandy' );
360 - $extra_info = esc_attr__( 'Select customer for whom you wish to create a ticket', 'supportcandy' );
445 + $name = __( 'Customer', 'supportcandy' );
446 + $extra_info = __( 'Select customer for whom you wish to create a ticket', 'supportcandy' );
361 447 $wpdb->insert(
362 448 $wpdb->prefix . 'psmsc_custom_fields',
363 449 array(
364 450 'name' => $name,
@@ -371,10 +457,10 @@
371 457 );
372 458 $string_translations[ 'wpsc-cf-name-' . $wpdb->insert_id ] = $name;
373 459 $string_translations[ 'wpsc-cf-exi-' . $wpdb->insert_id ] = $extra_info;
374 460
375 - $name = esc_attr__( 'Name', 'supportcandy' );
376 - $extra_info = esc_attr__( 'Please insert your name', 'supportcandy' );
461 + $name = __( 'Name', 'supportcandy' );
462 + $extra_info = __( 'Please insert your name', 'supportcandy' );
377 463 $wpdb->insert(
378 464 $wpdb->prefix . 'psmsc_custom_fields',
379 465 array(
380 466 'name' => $name,
@@ -389,10 +475,10 @@
389 475 );
390 476 $string_translations[ 'wpsc-cf-name-' . $wpdb->insert_id ] = $name;
391 477 $string_translations[ 'wpsc-cf-exi-' . $wpdb->insert_id ] = $extra_info;
392 478
393 - $name = esc_attr__( 'Email Address', 'supportcandy' );
394 - $extra_info = esc_attr__( 'Please insert your email address', 'supportcandy' );
479 + $name = __( 'Email Address', 'supportcandy' );
480 + $extra_info = __( 'Please insert your email address', 'supportcandy' );
395 481 $wpdb->insert(
396 482 $wpdb->prefix . 'psmsc_custom_fields',
397 483 array(
398 484 'name' => $name,
@@ -407,10 +493,10 @@
407 493 );
408 494 $string_translations[ 'wpsc-cf-name-' . $wpdb->insert_id ] = $name;
409 495 $string_translations[ 'wpsc-cf-exi-' . $wpdb->insert_id ] = $extra_info;
410 496
411 - $name = esc_attr__( 'Subject', 'supportcandy' );
412 - $extra_info = esc_attr__( 'Short description of the ticket', 'supportcandy' );
497 + $name = __( 'Subject', 'supportcandy' );
498 + $extra_info = __( 'Short description of the ticket', 'supportcandy' );
413 499 $wpdb->insert(
414 500 $wpdb->prefix . 'psmsc_custom_fields',
415 501 array(
416 502 'name' => $name,
@@ -425,10 +511,10 @@
425 511 );
426 512 $string_translations[ 'wpsc-cf-name-' . $wpdb->insert_id ] = $name;
427 513 $string_translations[ 'wpsc-cf-exi-' . $wpdb->insert_id ] = $extra_info;
428 514
429 - $name = esc_attr__( 'Description', 'supportcandy' );
430 - $extra_info = esc_attr__( 'Detailed description of the ticket', 'supportcandy' );
515 + $name = __( 'Description', 'supportcandy' );
516 + $extra_info = __( 'Detailed description of the ticket', 'supportcandy' );
431 517 $wpdb->insert(
432 518 $wpdb->prefix . 'psmsc_custom_fields',
433 519 array(
434 520 'name' => $name,
@@ -442,10 +528,10 @@
442 528 );
443 529 $string_translations[ 'wpsc-cf-name-' . $wpdb->insert_id ] = $name;
444 530 $string_translations[ 'wpsc-cf-exi-' . $wpdb->insert_id ] = $extra_info;
445 531
446 - $name = esc_attr__( 'Status', 'supportcandy' );
447 - $extra_info = esc_attr__( 'Please select status', 'supportcandy' );
532 + $name = __( 'Status', 'supportcandy' );
533 + $extra_info = __( 'Please select status', 'supportcandy' );
448 534 $wpdb->insert(
449 535 $wpdb->prefix . 'psmsc_custom_fields',
450 536 array(
451 537 'name' => $name,
@@ -460,10 +546,10 @@
460 546 );
461 547 $string_translations[ 'wpsc-cf-name-' . $wpdb->insert_id ] = $name;
462 548 $string_translations[ 'wpsc-cf-exi-' . $wpdb->insert_id ] = $extra_info;
463 549
464 - $name = esc_attr__( 'Priority', 'supportcandy' );
465 - $extra_info = esc_attr__( 'Please select priority', 'supportcandy' );
550 + $name = __( 'Priority', 'supportcandy' );
551 + $extra_info = __( 'Please select priority', 'supportcandy' );
466 552 $wpdb->insert(
467 553 $wpdb->prefix . 'psmsc_custom_fields',
468 554 array(
469 555 'name' => $name,
@@ -478,10 +564,10 @@
478 564 );
479 565 $string_translations[ 'wpsc-cf-name-' . $wpdb->insert_id ] = $name;
480 566 $string_translations[ 'wpsc-cf-exi-' . $wpdb->insert_id ] = $extra_info;
481 567
482 - $name = esc_attr__( 'Category', 'supportcandy' );
483 - $extra_info = esc_attr__( 'Please select category', 'supportcandy' );
568 + $name = __( 'Category', 'supportcandy' );
569 + $extra_info = __( 'Please select category', 'supportcandy' );
484 570 $wpdb->insert(
485 571 $wpdb->prefix . 'psmsc_custom_fields',
486 572 array(
487 573 'name' => $name,
@@ -496,10 +582,10 @@
496 582 );
497 583 $string_translations[ 'wpsc-cf-name-' . $wpdb->insert_id ] = $name;
498 584 $string_translations[ 'wpsc-cf-exi-' . $wpdb->insert_id ] = $extra_info;
499 585
500 - $name = esc_attr__( 'Assignee', 'supportcandy' );
501 - $extra_info = esc_attr__( 'Please select an agent', 'supportcandy' );
586 + $name = __( 'Assignee', 'supportcandy' );
587 + $extra_info = __( 'Please select an agent', 'supportcandy' );
502 588 $wpdb->insert(
503 589 $wpdb->prefix . 'psmsc_custom_fields',
504 590 array(
505 591 'name' => $name,
@@ -513,9 +599,9 @@
513 599 );
514 600 $string_translations[ 'wpsc-cf-name-' . $wpdb->insert_id ] = $name;
515 601 $string_translations[ 'wpsc-cf-exi-' . $wpdb->insert_id ] = $extra_info;
516 602
517 - $name = esc_attr__( 'Date Created', 'supportcandy' );
603 + $name = __( 'Date Created', 'supportcandy' );
518 604 $wpdb->insert(
519 605 $wpdb->prefix . 'psmsc_custom_fields',
520 606 array(
521 607 'name' => $name,
@@ -528,9 +614,9 @@
528 614 )
529 615 );
530 616 $string_translations[ 'wpsc-cf-name-' . $wpdb->insert_id ] = $name;
531 617
532 - $name = esc_attr__( 'Date Updated', 'supportcandy' );
618 + $name = __( 'Date Updated', 'supportcandy' );
533 619 $wpdb->insert(
534 620 $wpdb->prefix . 'psmsc_custom_fields',
535 621 array(
536 622 'name' => $name,
@@ -543,9 +629,9 @@
543 629 )
544 630 );
545 631 $string_translations[ 'wpsc-cf-name-' . $wpdb->insert_id ] = $name;
546 632
547 - $name = esc_attr__( 'Agent Created', 'supportcandy' );
633 + $name = __( 'Agent Created', 'supportcandy' );
548 634 $wpdb->insert(
549 635 $wpdb->prefix . 'psmsc_custom_fields',
550 636 array(
551 637 'name' => $name,
@@ -557,9 +643,9 @@
557 643 )
558 644 );
559 645 $string_translations[ 'wpsc-cf-name-' . $wpdb->insert_id ] = $name;
560 646
561 - $name = esc_attr__( 'IP Address', 'supportcandy' );
647 + $name = __( 'IP Address', 'supportcandy' );
562 648 $wpdb->insert(
563 649 $wpdb->prefix . 'psmsc_custom_fields',
564 650 array(
565 651 'name' => $name,
@@ -572,9 +658,9 @@
572 658 )
573 659 );
574 660 $string_translations[ 'wpsc-cf-name-' . $wpdb->insert_id ] = $name;
575 661
576 - $name = esc_attr__( 'Source', 'supportcandy' );
662 + $name = __( 'Source', 'supportcandy' );
577 663 $wpdb->insert(
578 664 $wpdb->prefix . 'psmsc_custom_fields',
579 665 array(
580 666 'name' => $name,
@@ -586,9 +672,9 @@
586 672 )
587 673 );
588 674 $string_translations[ 'wpsc-cf-name-' . $wpdb->insert_id ] = $name;
589 675
590 - $name = esc_attr__( 'Browser', 'supportcandy' );
676 + $name = __( 'Browser', 'supportcandy' );
591 677 $wpdb->insert(
592 678 $wpdb->prefix . 'psmsc_custom_fields',
593 679 array(
594 680 'name' => $name,
@@ -600,9 +686,9 @@
600 686 )
601 687 );
602 688 $string_translations[ 'wpsc-cf-name-' . $wpdb->insert_id ] = $name;
603 689
604 - $name = esc_attr__( 'Operating System', 'supportcandy' );
690 + $name = __( 'Operating System', 'supportcandy' );
605 691 $wpdb->insert(
606 692 $wpdb->prefix . 'psmsc_custom_fields',
607 693 array(
608 694 'name' => $name,
@@ -614,10 +700,10 @@
614 700 )
615 701 );
616 702 $string_translations[ 'wpsc-cf-name-' . $wpdb->insert_id ] = $name;
617 703
618 - $name = esc_attr__( 'Additional Recipients', 'supportcandy' );
619 - $extra_info = esc_attr__( 'Please insert email addresses (one per line)', 'supportcandy' );
704 + $name = __( 'Additional Recipients', 'supportcandy' );
705 + $extra_info = __( 'Please insert email addresses (one per line)', 'supportcandy' );
620 706 $wpdb->insert(
621 707 $wpdb->prefix . 'psmsc_custom_fields',
622 708 array(
623 709 'name' => $name,
@@ -631,9 +717,9 @@
631 717 );
632 718 $string_translations[ 'wpsc-cf-name-' . $wpdb->insert_id ] = $name;
633 719 $string_translations[ 'wpsc-cf-exi-' . $wpdb->insert_id ] = $extra_info;
634 720
635 - $name = esc_attr__( 'Previous Assignee', 'supportcandy' );
721 + $name = __( 'Previous Assignee', 'supportcandy' );
636 722 $wpdb->insert(
637 723 $wpdb->prefix . 'psmsc_custom_fields',
638 724 array(
639 725 'name' => $name,
@@ -646,9 +732,9 @@
646 732 )
647 733 );
648 734 $string_translations[ 'wpsc-cf-name-' . $wpdb->insert_id ] = $name;
649 735
650 - $name = esc_attr__( 'Date Closed', 'supportcandy' );
736 + $name = __( 'Date Closed', 'supportcandy' );
651 737 $wpdb->insert(
652 738 $wpdb->prefix . 'psmsc_custom_fields',
653 739 array(
654 740 'name' => $name,
@@ -662,9 +748,9 @@
662 748 )
663 749 );
664 750 $string_translations[ 'wpsc-cf-name-' . $wpdb->insert_id ] = $name;
665 751
666 - $name = esc_attr__( 'User Type', 'supportcandy' );
752 + $name = __( 'User Type', 'supportcandy' );
667 753 $wpdb->insert(
668 754 $wpdb->prefix . 'psmsc_custom_fields',
669 755 array(
670 756 'name' => $name,
@@ -677,9 +763,9 @@
677 763 )
678 764 );
679 765 $string_translations[ 'wpsc-cf-name-' . $wpdb->insert_id ] = $name;
680 766
681 - $name = esc_attr__( 'Last Reply On', 'supportcandy' );
767 + $name = __( 'Last Reply On', 'supportcandy' );
682 768 $wpdb->insert(
683 769 $wpdb->prefix . 'psmsc_custom_fields',
684 770 array(
685 771 'name' => $name,
@@ -693,9 +779,9 @@
693 779 )
694 780 );
695 781 $string_translations[ 'wpsc-cf-name-' . $wpdb->insert_id ] = $name;
696 782
697 - $name = esc_attr__( 'Last Reply By', 'supportcandy' );
783 + $name = __( 'Last Reply By', 'supportcandy' );
698 784 $wpdb->insert(
699 785 $wpdb->prefix . 'psmsc_custom_fields',
700 786 array(
701 787 'name' => $name,
@@ -708,9 +794,9 @@
708 794 )
709 795 );
710 796 $string_translations[ 'wpsc-cf-name-' . $wpdb->insert_id ] = $name;
711 797
712 - $name = esc_attr__( 'Tags', 'supportcandy' );
798 + $name = __( 'Tags', 'supportcandy' );
713 799 $wpdb->insert(
714 800 $wpdb->prefix . 'psmsc_custom_fields',
715 801 array(
716 802 'name' => $name,
@@ -723,9 +809,9 @@
723 809 )
724 810 );
725 811 $string_translations[ 'wpsc-cf-name-' . $wpdb->insert_id ] = $name;
726 812
727 - $name = esc_attr__( 'Last Reply Source', 'supportcandy' );
813 + $name = __( 'Last Reply Source', 'supportcandy' );
728 814 $wpdb->insert(
729 815 $wpdb->prefix . 'psmsc_custom_fields',
730 816 array(
731 817 'name' => $name,
@@ -738,104 +824,110 @@
738 824 )
739 825 );
740 826 $string_translations[ 'wpsc-cf-name-' . $wpdb->insert_id ] = $name;
741 827
742 - // Insert default category.
743 - $name = esc_attr__( 'General', 'supportcandy' );
744 - $wpdb->insert(
745 - $wpdb->prefix . 'psmsc_categories',
746 - array(
747 - 'name' => $name,
748 - 'load_order' => 1,
749 - )
750 - );
751 - $string_translations[ 'wpsc-category-' . $wpdb->insert_id ] = $name;
828 + // Insert default category, guarded against re-running initial_setup().
829 + if ( ! $wpdb->get_var( "SELECT id FROM {$wpdb->prefix}psmsc_categories LIMIT 1" ) ) {
830 + $name = __( 'General', 'supportcandy' );
831 + $wpdb->insert(
832 + $wpdb->prefix . 'psmsc_categories',
833 + array(
834 + 'name' => $name,
835 + 'load_order' => 1,
836 + )
837 + );
838 + $string_translations[ 'wpsc-category-' . $wpdb->insert_id ] = $name;
839 + }
752 840
753 - // Insert default statuses.
754 - $name = esc_attr__( 'Open', 'supportcandy' );
755 - $wpdb->insert(
756 - $wpdb->prefix . 'psmsc_statuses',
757 - array(
758 - 'name' => $name,
759 - 'color' => '#ec1010',
760 - 'bg_color' => '#ffe7e1',
761 - 'load_order' => 1,
762 - )
763 - );
764 - $string_translations[ 'wpsc-status-' . $wpdb->insert_id ] = $name;
841 + // Insert default statuses, guarded against re-running initial_setup().
842 + if ( ! $wpdb->get_var( "SELECT id FROM {$wpdb->prefix}psmsc_statuses LIMIT 1" ) ) {
843 + $name = __( 'Open', 'supportcandy' );
844 + $wpdb->insert(
845 + $wpdb->prefix . 'psmsc_statuses',
846 + array(
847 + 'name' => $name,
848 + 'color' => '#ec1010',
849 + 'bg_color' => '#ffe7e1',
850 + 'load_order' => 1,
851 + )
852 + );
853 + $string_translations[ 'wpsc-status-' . $wpdb->insert_id ] = $name;
765 854
766 - $name = esc_attr__( 'Awaiting customer reply', 'supportcandy' );
767 - $wpdb->insert(
768 - $wpdb->prefix . 'psmsc_statuses',
769 - array(
770 - 'name' => $name,
771 - 'color' => '#8222E6',
772 - 'bg_color' => '#E9D3FF',
773 - 'load_order' => 2,
774 - )
775 - );
776 - $string_translations[ 'wpsc-status-' . $wpdb->insert_id ] = $name;
855 + $name = __( 'Awaiting customer reply', 'supportcandy' );
856 + $wpdb->insert(
857 + $wpdb->prefix . 'psmsc_statuses',
858 + array(
859 + 'name' => $name,
860 + 'color' => '#8222E6',
861 + 'bg_color' => '#E9D3FF',
862 + 'load_order' => 2,
863 + )
864 + );
865 + $string_translations[ 'wpsc-status-' . $wpdb->insert_id ] = $name;
777 866
778 - $name = esc_attr__( 'Awaiting agent reply', 'supportcandy' );
779 - $wpdb->insert(
780 - $wpdb->prefix . 'psmsc_statuses',
781 - array(
782 - 'name' => $name,
783 - 'color' => '#EB961C',
784 - 'bg_color' => '#FFEBCE',
785 - 'load_order' => 3,
786 - )
787 - );
788 - $string_translations[ 'wpsc-status-' . $wpdb->insert_id ] = $name;
867 + $name = __( 'Awaiting agent reply', 'supportcandy' );
868 + $wpdb->insert(
869 + $wpdb->prefix . 'psmsc_statuses',
870 + array(
871 + 'name' => $name,
872 + 'color' => '#EB961C',
873 + 'bg_color' => '#FFEBCE',
874 + 'load_order' => 3,
875 + )
876 + );
877 + $string_translations[ 'wpsc-status-' . $wpdb->insert_id ] = $name;
789 878
790 - $name = esc_attr__( 'Closed', 'supportcandy' );
791 - $wpdb->insert(
792 - $wpdb->prefix . 'psmsc_statuses',
793 - array(
794 - 'name' => $name,
795 - 'color' => '#22940d',
796 - 'bg_color' => '#c1ffcf',
797 - 'load_order' => 4,
798 - )
799 - );
800 - $string_translations[ 'wpsc-status-' . $wpdb->insert_id ] = $name;
879 + $name = __( 'Closed', 'supportcandy' );
880 + $wpdb->insert(
881 + $wpdb->prefix . 'psmsc_statuses',
882 + array(
883 + 'name' => $name,
884 + 'color' => '#22940d',
885 + 'bg_color' => '#c1ffcf',
886 + 'load_order' => 4,
887 + )
888 + );
889 + $string_translations[ 'wpsc-status-' . $wpdb->insert_id ] = $name;
890 + }
801 891
802 - // Insert default priorities.
803 - $name = esc_attr__( 'Low', 'supportcandy' );
804 - $wpdb->insert(
805 - $wpdb->prefix . 'psmsc_priorities',
806 - array(
807 - 'name' => $name,
808 - 'color' => '#22940d',
809 - 'bg_color' => '#c1ffcf',
810 - 'load_order' => 1,
811 - )
812 - );
813 - $string_translations[ 'wpsc-priority-' . $wpdb->insert_id ] = $name;
892 + // Insert default priorities, guarded against re-running initial_setup().
893 + if ( ! $wpdb->get_var( "SELECT id FROM {$wpdb->prefix}psmsc_priorities LIMIT 1" ) ) {
894 + $name = __( 'Low', 'supportcandy' );
895 + $wpdb->insert(
896 + $wpdb->prefix . 'psmsc_priorities',
897 + array(
898 + 'name' => $name,
899 + 'color' => '#22940d',
900 + 'bg_color' => '#c1ffcf',
901 + 'load_order' => 1,
902 + )
903 + );
904 + $string_translations[ 'wpsc-priority-' . $wpdb->insert_id ] = $name;
814 905
815 - $name = esc_attr__( 'Medium', 'supportcandy' );
816 - $wpdb->insert(
817 - $wpdb->prefix . 'psmsc_priorities',
818 - array(
819 - 'name' => $name,
820 - 'color' => '#EB961C',
821 - 'bg_color' => '#FFEBCE',
822 - 'load_order' => 2,
823 - )
824 - );
825 - $string_translations[ 'wpsc-priority-' . $wpdb->insert_id ] = $name;
906 + $name = __( 'Medium', 'supportcandy' );
907 + $wpdb->insert(
908 + $wpdb->prefix . 'psmsc_priorities',
909 + array(
910 + 'name' => $name,
911 + 'color' => '#EB961C',
912 + 'bg_color' => '#FFEBCE',
913 + 'load_order' => 2,
914 + )
915 + );
916 + $string_translations[ 'wpsc-priority-' . $wpdb->insert_id ] = $name;
826 917
827 - $name = esc_attr__( 'High', 'supportcandy' );
828 - $wpdb->insert(
829 - $wpdb->prefix . 'psmsc_priorities',
830 - array(
831 - 'name' => $name,
832 - 'color' => '#ec1010',
833 - 'bg_color' => '#ffe7e1',
834 - 'load_order' => 3,
835 - )
836 - );
837 - $string_translations[ 'wpsc-priority-' . $wpdb->insert_id ] = $name;
918 + $name = __( 'High', 'supportcandy' );
919 + $wpdb->insert(
920 + $wpdb->prefix . 'psmsc_priorities',
921 + array(
922 + 'name' => $name,
923 + 'color' => '#ec1010',
924 + 'bg_color' => '#ffe7e1',
925 + 'load_order' => 3,
926 + )
927 + );
928 + $string_translations[ 'wpsc-priority-' . $wpdb->insert_id ] = $name;
929 + }
838 930
839 931 // company working hrs.
840 932 for ( $i = 1; $i <= 7; $i++ ) {
841 933 $wpdb->insert(
@@ -917,12 +1009,18 @@
917 1009 'create-as' => true, // Create ticket on others behalf.
918 1010 'dtt-access' => true, // Deleted ticket access.
919 1011 'eci-access' => true, // Edit customer info.
920 1012 'dash-access' => true, // Dashboard access.
1013 + 'at-access' => true, // Archive tickets menu access.
1014 + 'at-delete-access' => true, // Archive tickets delete access.
921 1015
922 1016 'tt-unassigned' => true, // Ticket tags.
923 1017 'tt-assigned-me' => true,
924 1018 'tt-assigned-others' => true,
1019 +
1020 + 'at-unassigned' => true, // Archive ticket permissions.
1021 + 'at-assigned-me' => true,
1022 + 'at-assigned-others' => true,
925 1023 ),
926 1024 ),
927 1025 2 => array(
928 1026 'label' => 'Agent',
@@ -988,12 +1086,18 @@
988 1086 'create-as' => true,
989 1087 'dtt-access' => false,
990 1088 'eci-access' => false,
991 1089 'dash-access' => true, // Dashboard access.
1090 + 'at-access' => false, // Archive tickets menu access.
1091 + 'at-delete-access' => false, // Archive tickets delete access.
992 1092
993 1093 'tt-unassigned' => true, // Ticket tags.
994 1094 'tt-assigned-me' => true,
995 1095 'tt-assigned-others' => false,
1096 +
1097 + 'at-unassigned' => false, // Archive ticket permissions.
1098 + 'at-assigned-me' => false,
1099 + 'at-assigned-others' => false,
996 1100 ),
997 1101 ),
998 1102 )
999 1103 );
@@ -1083,14 +1187,14 @@
1083 1187 'wpsc-atl-filter-items',
1084 1188 array( 'id', 'status', 'customer', 'subject', 'category', 'priority', 'assigned_agent', 'date_updated', 'date_created' )
1085 1189 );
1086 1190 $labels = array(
1087 - 'all' => esc_attr__( 'All', 'supportcandy' ),
1088 - 'unresolved' => esc_attr__( 'Unresolved', 'supportcandy' ),
1089 - 'unassigned' => esc_attr__( 'Unassigned', 'supportcandy' ),
1090 - 'mine' => esc_attr__( 'Mine', 'supportcandy' ),
1091 - 'closed' => esc_attr__( 'Closed', 'supportcandy' ),
1092 - 'deleted' => esc_attr__( 'Deleted', 'supportcandy' ),
1191 + 'all' => __( 'All', 'supportcandy' ),
1192 + 'unresolved' => __( 'Unresolved', 'supportcandy' ),
1193 + 'unassigned' => __( 'Unassigned', 'supportcandy' ),
1194 + 'mine' => __( 'Mine', 'supportcandy' ),
1195 + 'closed' => __( 'Closed', 'supportcandy' ),
1196 + 'deleted' => __( 'Deleted', 'supportcandy' ),
1093 1197 );
1094 1198 foreach ( $labels as $key => $string ) {
1095 1199 $string_translations[ 'wpsc-atl-' . $key ] = $string;
1096 1200 }
@@ -1133,11 +1237,11 @@
1133 1237 'wpsc-ctl-filter-items',
1134 1238 array( 'id', 'status', 'subject', 'category', 'date_updated', 'date_created' )
1135 1239 );
1136 1240 $labels = array(
1137 - 'all' => esc_attr__( 'All', 'supportcandy' ),
1138 - 'unresolved' => esc_attr__( 'Unresolved', 'supportcandy' ),
1139 - 'closed' => esc_attr__( 'Closed', 'supportcandy' ),
1241 + 'all' => __( 'All', 'supportcandy' ),
1242 + 'unresolved' => __( 'Unresolved', 'supportcandy' ),
1243 + 'closed' => __( 'Closed', 'supportcandy' ),
1140 1244 );
1141 1245 foreach ( $labels as $key => $string ) {
1142 1246 $string_translations[ 'wpsc-ctl-' . $key ] = $string;
1143 1247 }
@@ -1453,8 +1557,9 @@
1453 1557 'editor' => 'html',
1454 1558 'allow-gdpr-reg-user' => 1,
1455 1559 'gdpr-text-reg-user' => $translation,
1456 1560 'editor-reg-user' => 'html',
1561 + 'ip-address-collection' => 1,
1457 1562 )
1458 1563 );
1459 1564
1460 1565 update_option(
@@ -1459,12 +1564,14 @@
1459 1564
1460 1565 update_option(
1461 1566 'wpsc-recaptcha-settings',
1462 1567 array(
1463 - 'allow-recaptcha' => 0,
1464 - 'recaptcha-version' => 3,
1465 - 'recaptcha-site-key' => '',
1466 - 'recaptcha-secret-key' => '',
1568 + 'captcha-provider' => 0,
1569 + 'recaptcha-version' => 3,
1570 + 'recaptcha-site-key' => '',
1571 + 'recaptcha-secret-key' => '',
1572 + 'cloudflare-site-key' => '',
1573 + 'cloudflare-secret-key' => '',
1467 1574 )
1468 1575 );
1469 1576
1470 1577 update_option(
@@ -1469,36 +1576,39 @@
1469 1576
1470 1577 update_option(
1471 1578 'wpsc-ms-advanced-settings',
1472 1579 array(
1473 - 'public-mode' => 0,
1474 - 'public-mode-reply' => 0,
1475 - 'reply-confirmation' => 1,
1476 - 'thread-date-display-as' => 'diff',
1477 - 'thread-date-format' => 'F d, Y h:i A',
1478 - 'do-not-notify-owner' => 1,
1479 - 'do-not-notify-owner-status' => 1,
1480 - 'ticket-id-format' => 'sequential',
1481 - 'starting-ticket-id' => 1,
1482 - 'random-id-length' => 8,
1483 - 'ticket-history-macro-threads' => 5,
1484 - 'register-user-if-not-exist' => 0,
1485 - 'auto-delete-tickets-time' => 0,
1486 - 'auto-delete-tickets-unit' => 'days',
1487 - 'permanent-delete-tickets-time' => 0,
1488 - 'permanent-delete-tickets-unit' => 'days',
1489 - 'allow-bcc' => 0,
1490 - 'allow-cc' => 0,
1491 - 'view-more' => 1,
1492 - 'allow-reply-to-close-ticket' => array( 'customer', 'agent' ),
1493 - 'raised-by-user' => 'customer',
1494 - 'allow-my-profile' => 1,
1495 - 'allow-agent-profile' => 1,
1496 - 'ticket-url-auth' => 0,
1497 - 'rest-api' => 1,
1498 - 'agent-collision' => 1,
1499 - 'self-assign' => 1,
1500 - 'reply-close' => 0,
1580 + 'public-mode' => 0,
1581 + 'public-mode-reply' => 0,
1582 + 'reply-confirmation' => 1,
1583 + 'note-confirmation' => 0,
1584 + 'thread-date-display-as' => 'diff',
1585 + 'thread-date-format' => 'F d, Y h:i A',
1586 + 'do-not-notify-owner' => 1,
1587 + 'do-not-notify-owner-status' => 1,
1588 + 'ticket-id-format' => 'sequential',
1589 + 'starting-ticket-id' => 1,
1590 + 'random-id-length' => 8,
1591 + 'ticket-history-macro-threads' => 5,
1592 + 'register-user-if-not-exist' => 0,
1593 + 'auto-archive-tickets-time' => 0,
1594 + 'auto-archive-tickets-unit' => 'days',
1595 + 'permanent-archive-tickets-time' => 0,
1596 + 'permanent-archive-tickets-unit' => 'days',
1597 + 'permanent-delete-tickets-time' => 0,
1598 + 'permanent-delete-tickets-unit' => 'days',
1599 + 'allow-bcc' => 0,
1600 + 'allow-cc' => 0,
1601 + 'view-more' => 1,
1602 + 'allow-reply-to-close-ticket' => array( 'customer', 'agent' ),
1603 + 'raised-by-user' => 'customer',
1604 + 'allow-my-profile' => 1,
1605 + 'allow-agent-profile' => 1,
1606 + 'ticket-url-auth' => 0,
1607 + 'rest-api' => 1,
1608 + 'agent-collision' => 1,
1609 + 'self-assign' => 1,
1610 + 'reply-close' => 0,
1501 1611 )
1502 1612 );
1503 1613
1504 1614 $translation = '<p>I agree to the terms and conditions</p>';
@@ -1517,17 +1627,18 @@
1517 1627 );
1518 1628
1519 1629 // ticket widgets.
1520 1630 $labels = array(
1521 - 'change-status' => esc_attr__( 'Ticket status', 'supportcandy' ),
1522 - 'raised-by' => esc_attr__( 'Customer', 'supportcandy' ),
1523 - 'ticket-info' => esc_attr__( 'Ticket info', 'supportcandy' ),
1524 - 'assignee' => esc_attr__( 'Assignee', 'supportcandy' ),
1525 - 'ticket-fields' => esc_attr__( 'Ticket fields', 'supportcandy' ),
1526 - 'agentonly-fields' => esc_attr__( 'Agent only fields', 'supportcandy' ),
1527 - 'additional-recipients' => esc_attr__( 'Additional recipients', 'supportcandy' ),
1528 - 'biographical-info' => esc_attr__( 'Biographical Info', 'supportcandy' ),
1529 - 'tags' => esc_attr__( 'Tags', 'supportcandy' ),
1631 + 'agent-collision' => __( 'Currently viewing', 'supportcandy' ),
1632 + 'change-status' => __( 'Ticket status', 'supportcandy' ),
1633 + 'raised-by' => __( 'Customer', 'supportcandy' ),
1634 + 'ticket-info' => __( 'Ticket info', 'supportcandy' ),
1635 + 'assignee' => __( 'Assignee', 'supportcandy' ),
1636 + 'ticket-fields' => __( 'Ticket fields', 'supportcandy' ),
1637 + 'agentonly-fields' => __( 'Agent only fields', 'supportcandy' ),
1638 + 'additional-recipients' => __( 'Additional recipients', 'supportcandy' ),
1639 + 'biographical-info' => __( 'Biographical Info', 'supportcandy' ),
1640 + 'tags' => __( 'Tags', 'supportcandy' ),
1530 1641 );
1531 1642 foreach ( $labels as $key => $string ) {
1532 1643 $string_translations[ 'wpsc-twt-' . $key ] = $string;
1533 1644 }
@@ -1533,17 +1644,25 @@
1533 1644 }
1534 1645 update_option(
1535 1646 'wpsc-ticket-widget',
1536 1647 array(
1537 - 'change-status' => array(
1538 - 'title' => $labels['change-status'],
1648 + 'agent-collision' => array(
1649 + 'title' => $labels['agent-collision'],
1539 1650 'is_enable' => 1,
1540 - 'allow-customer' => 1,
1651 + 'allow-customer' => 0,
1541 1652 'allowed-agent-roles' => array( 1, 2 ),
1542 1653 'show-priority-to-customer' => 0,
1543 - 'callback' => 'wpsc_get_tw_ticket_status()',
1544 - 'class' => 'WPSC_ITW_Change_Status',
1654 + 'callback' => 'wpsc_get_tw_agent_collision()',
1655 + 'class' => 'WPSC_ITW_Agent_Collision',
1545 1656 ),
1657 + 'change-status' => array(
1658 + 'title' => $labels['change-status'],
1659 + 'is_enable' => 1,
1660 + 'allow-customer' => 1,
1661 + 'allowed-agent-roles' => array( 1, 2 ),
1662 + 'callback' => 'wpsc_get_tw_ticket_status()',
1663 + 'class' => 'WPSC_ITW_Change_Status',
1664 + ),
1546 1665 'raised-by' => array(
1547 1666 'title' => $labels['raised-by'],
1548 1667 'is_enable' => 1,
1549 1668 'allow-customer' => 0,
@@ -1612,9 +1731,9 @@
1612 1731
1613 1732 // Rich text editor.
1614 1733 $notice = sprintf(
1615 1734 /* translators: %1$s: attachment max file size, %2$s: allowed file extenstions. */
1616 - esc_attr__( 'You can upload files maximum size %1$s mb of types %2$s.', 'supportcandy' ),
1735 + __( 'You can upload files maximum size %1$s mb of types %2$s.', 'supportcandy' ),
1617 1736 20,
1618 1737 'jpg, jpeg, png, gif, pdf, doc, docx, ppt, pptx, pps, ppsx, odt, xls, xlsx, mp3, m4a, ogg, wav, mp4, m4v, mov, wmv, avi, mpg, ogv, 3gp, 3g2, zip, eml'
1619 1738 );
1620 1739 update_option(
@@ -1700,15 +1819,8 @@
1700 1819 'z-index' => 900000000,
1701 1820 )
1702 1821 );
1703 1822 update_option(
1704 - 'wpsc-ap-agent-collision',
1705 - array(
1706 - 'header-bg-color' => '#e6e6e6',
1707 - 'header-text-color' => '#2c3e50',
1708 - )
1709 - );
1710 - update_option(
1711 1823 'wpsc-ap-ticket-list',
1712 1824 array(
1713 1825 'list-header-background-color' => '#2c3e50',
1714 1826 'list-header-text-color' => '#fff',
@@ -1733,12 +1845,12 @@
1733 1845 // dashboard general setting.
1734 1846 update_option(
1735 1847 'wpsc-ap-dashboard',
1736 1848 array(
1737 - 'card-body-bg-color' => '#f9f9f9',
1849 + 'card-body-bg-color' => '#ffffff',
1738 1850 'card-body-svg-color' => '#777',
1739 1851 'card-body-text-color' => '#2c3e50',
1740 - 'widget-body-bg-color' => '#f9f9f9',
1852 + 'widget-body-bg-color' => '#ffffff',
1741 1853 'widget-body-svg-color' => '#777',
1742 1854 'widget-body-text-color' => '#2c3e50',
1743 1855 )
1744 1856 );
@@ -1751,13 +1863,13 @@
1751 1863 }
1752 1864
1753 1865 // Dashboard cards.
1754 1866 $labels = array(
1755 - 'new-tickets' => esc_attr__( 'New Tickets', 'supportcandy' ),
1756 - 'unresolved' => esc_attr__( 'Unresolved', 'supportcandy' ),
1757 - 'unassigned' => esc_attr__( 'Unassigned', 'supportcandy' ),
1758 - 'closed' => esc_attr__( 'Closed', 'supportcandy' ),
1759 - 'mine' => esc_attr__( 'Mine', 'supportcandy' ),
1867 + 'new-tickets' => __( 'New Tickets', 'supportcandy' ),
1868 + 'unresolved' => __( 'Unresolved', 'supportcandy' ),
1869 + 'unassigned' => __( 'Unassigned', 'supportcandy' ),
1870 + 'closed' => __( 'Closed', 'supportcandy' ),
1871 + 'mine' => __( 'Mine', 'supportcandy' ),
1760 1872 );
1761 1873 foreach ( $labels as $key => $string ) {
1762 1874 $string_translations[ 'wpsc-dashboard-card-' . $key ] = $string;
1763 1875 }
@@ -1808,17 +1920,17 @@
1808 1920 );
1809 1921
1810 1922 // Dashboard widget.
1811 1923 $labels = array(
1812 - 'ticket-statistics' => esc_attr__( 'Ticket Statistics', 'supportcandy' ),
1813 - 'todays-trends' => esc_attr__( 'Todays Trends', 'supportcandy' ),
1814 - 'agent-list' => esc_attr__( 'Agent Workload', 'supportcandy' ),
1815 - 'recent-activities' => esc_attr__( 'Recent Activities', 'supportcandy' ),
1816 - 'recent-tickets' => esc_attr__( 'Recent Tickets', 'supportcandy' ),
1817 - 'category-report' => esc_attr__( 'Tickets by Category', 'supportcandy' ),
1818 - 'unresolved-priorities' => esc_attr__( 'Tickets by Priority', 'supportcandy' ),
1819 - 'unresolved-statuses' => esc_attr__( 'Tickets by Status', 'supportcandy' ),
1820 - 'week-trends' => esc_attr__( 'Ticket statistics by day of week', 'supportcandy' ),
1924 + 'ticket-statistics' => __( 'Ticket Statistics', 'supportcandy' ),
1925 + 'todays-trends' => __( 'Todays Trends', 'supportcandy' ),
1926 + 'agent-list' => __( 'Agent Workload', 'supportcandy' ),
1927 + 'recent-activities' => __( 'Recent Activities', 'supportcandy' ),
1928 + 'recent-tickets' => __( 'Recent Tickets', 'supportcandy' ),
1929 + 'category-report' => __( 'Tickets by Category', 'supportcandy' ),
1930 + 'unresolved-priorities' => __( 'Tickets by Priority', 'supportcandy' ),
1931 + 'unresolved-statuses' => __( 'Tickets by Status', 'supportcandy' ),
1932 + 'week-trends' => __( 'Ticket statistics by day of week', 'supportcandy' ),
1821 1933 );
1822 1934 foreach ( $labels as $key => $string ) {
1823 1935 $string_translations[ 'wpsc-dashboard-widget-' . $key ] = $string;
1824 1936 }
@@ -1920,10 +2032,88 @@
1920 2032 );
1921 2033
1922 2034 self::attachment_security_file();
1923 2035
2036 + // Create required database indexes.
2037 + self::create_indexing();
2038 +
1924 2039 // update string translations.
1925 2040 update_option( 'wpsc-string-translation', $string_translations );
2041 +
2042 + // Add AI assistant option.
2043 + update_option(
2044 + 'wpsc-ps-ai-assistant-settings',
2045 + array(
2046 + 'status' => '0',
2047 + 'provider' => 'openai',
2048 + 'api_key' => '',
2049 + 'model' => 'gpt-4o-mini',
2050 + 'max-tokens' => 500,
2051 + 'auto-delete-ai-logs-time' => 1,
2052 + 'auto-delete-ai-logs-unit' => 'year',
2053 + 'custom-prompt' => '',
2054 + 'summary-custom-prompt' => '',
2055 + 'auto-draft-custom-prompt' => '',
2056 + 'is-active' => 0,
2057 + 'last-error' => '',
2058 + 'ai-max-upload-file-size' => 10,
2059 + )
2060 + );
2061 +
2062 + // update AI training options.
2063 + update_option(
2064 + 'wpsc-ps-ai-training-sources',
2065 + array(
2066 + array(
2067 + 'slug' => 'local',
2068 + 'type' => 'localhost',
2069 + 'name' => 'Local',
2070 + 'api-url' => rest_url(),
2071 + 'post-types' => array(),
2072 + ),
2073 + ),
2074 + );
2075 +
2076 + // default AI chatbot settings.
2077 + update_option(
2078 + 'wpsc-ps-acb-chatbot-settings',
2079 + array(
2080 + 'status' => '0',
2081 + 'delete-acb-session-time' => 1,
2082 + 'delete-acb-session-unit' => 'year',
2083 + 'show-footer-branding' => '1',
2084 + 'sessions-per-page' => 30,
2085 + 'popup-delay-status' => '0',
2086 + 'popup-delay' => 10,
2087 + 'popup-display-limit' => 3,
2088 + 'custom-prompt' => '',
2089 + )
2090 + );
2091 +
2092 + // default chatbot appearance settings.
2093 + update_option(
2094 + 'wpsc-acb-appearance-general',
2095 + array(
2096 + 'background-color' => '#2271b1',
2097 + 'icon-color' => '#ffffff',
2098 + 'header-text' => __( 'AI Chatbot', 'supportcandy' ),
2099 + 'greeting-text' => __( 'Hey, I\'m your assistant. How can I help you today?', 'supportcandy' ),
2100 + 'warning-text' => __( 'AI can make mistakes. Check important info.', 'supportcandy' ),
2101 + )
2102 + );
2103 +
2104 + // Onboarding wizard: seed pending state for this fresh install and flag a
2105 + // one-time redirect so WPSC_Onboarding shows the wizard on the next admin
2106 + // page load. Existing sites being upgraded never reach this method, so the
2107 + // wizard never auto-appears for them.
2108 + update_option(
2109 + 'wpsc-onboarding-wizard',
2110 + array(
2111 + 'status' => 'pending',
2112 + 'steps' => array(),
2113 + )
2114 + );
2115 + set_transient( 'wpsc_onboarding_redirect', 1, 5 * MINUTE_IN_SECONDS );
1926 2116 }
1927 2117
1928 2118 /**
1929 2119 * Upgrade the version
@@ -1930,8 +2120,9 @@
1930 2120 */
1931 2121 public static function upgrade() {
1932 2122
1933 2123 global $wpdb;
2124 +
1934 2125 $string_translations = get_option( 'wpsc-string-translation' );
1935 2126
1936 2127 if ( version_compare( self::$current_version, '3.0.4', '<' ) ) {
1937 2128
@@ -2151,9 +2342,9 @@
2151 2342 }
2152 2343
2153 2344 $tag_exists = $wpdb->get_results( "SELECT id from {$wpdb->prefix}psmsc_custom_fields WHERE slug = 'tags'" );
2154 2345 if ( empty( $tag_exists ) ) {
2155 - $name = esc_attr__( 'Tags', 'supportcandy' );
2346 + $name = __( 'Tags', 'supportcandy' );
2156 2347 $wpdb->insert(
2157 2348 $wpdb->prefix . 'psmsc_custom_fields',
2158 2349 array(
2159 2350 'name' => $name,
@@ -2226,9 +2417,9 @@
2226 2417
2227 2418 if ( version_compare( self::$current_version, '3.2.4', '<' ) ) {
2228 2419
2229 2420 // add default true to admin and agent dashboard access.
2230 - $roles = get_option( 'wpsc-agent-roles' );
2421 + $roles = get_option( 'wpsc-agent-roles', array() );
2231 2422 $role_keys = array();
2232 2423 foreach ( $roles as $key => $role ) {
2233 2424 $role['caps']['dash-access'] = true;
2234 2425 $roles[ $key ] = $role;
@@ -2236,13 +2427,13 @@
2236 2427 }
2237 2428
2238 2429 // Dashboard cards.
2239 2430 $labels = array(
2240 - 'new-tickets' => esc_attr__( 'New Tickets', 'supportcandy' ),
2241 - 'unresolved' => esc_attr__( 'Unresolved', 'supportcandy' ),
2242 - 'unassigned' => esc_attr__( 'Unassigned', 'supportcandy' ),
2243 - 'closed' => esc_attr__( 'Closed', 'supportcandy' ),
2244 - 'mine' => esc_attr__( 'Mine', 'supportcandy' ),
2431 + 'new-tickets' => __( 'New Tickets', 'supportcandy' ),
2432 + 'unresolved' => __( 'Unresolved', 'supportcandy' ),
2433 + 'unassigned' => __( 'Unassigned', 'supportcandy' ),
2434 + 'closed' => __( 'Closed', 'supportcandy' ),
2435 + 'mine' => __( 'Mine', 'supportcandy' ),
2245 2436 );
2246 2437 foreach ( $labels as $key => $string ) {
2247 2438 $string_translations[ 'wpsc-dashboard-card-' . $key ] = $string;
2248 2439 }
@@ -2293,16 +2484,16 @@
2293 2484 );
2294 2485
2295 2486 // Dashboard widget.
2296 2487 $labels = array(
2297 - 'ticket-statistics' => esc_attr__( 'Ticket Statistics', 'supportcandy' ),
2298 - 'todays-trends' => esc_attr__( 'Todays Trends', 'supportcandy' ),
2299 - 'agent-list' => esc_attr__( 'Agent Workload', 'supportcandy' ),
2300 - 'recent-activities' => esc_attr__( 'Recent Activities', 'supportcandy' ),
2301 - 'recent-tickets' => esc_attr__( 'Recent Tickets', 'supportcandy' ),
2302 - 'category-report' => esc_attr__( 'Unresolved tickets by Category', 'supportcandy' ),
2303 - 'unresolved-priorities' => esc_attr__( 'Unresolved tickets by Priority', 'supportcandy' ),
2304 - 'unresolved-statuses' => esc_attr__( 'Unresolved tickets by Status', 'supportcandy' ),
2488 + 'ticket-statistics' => __( 'Ticket Statistics', 'supportcandy' ),
2489 + 'todays-trends' => __( 'Todays Trends', 'supportcandy' ),
2490 + 'agent-list' => __( 'Agent Workload', 'supportcandy' ),
2491 + 'recent-activities' => __( 'Recent Activities', 'supportcandy' ),
2492 + 'recent-tickets' => __( 'Recent Tickets', 'supportcandy' ),
2493 + 'category-report' => __( 'Unresolved tickets by Category', 'supportcandy' ),
2494 + 'unresolved-priorities' => __( 'Unresolved tickets by Priority', 'supportcandy' ),
2495 + 'unresolved-statuses' => __( 'Unresolved tickets by Status', 'supportcandy' ),
2305 2496 );
2306 2497 foreach ( $labels as $key => $string ) {
2307 2498 $string_translations[ 'wpsc-dashboard-widget-' . $key ] = $string;
2308 2499 }
@@ -2387,12 +2578,12 @@
2387 2578 // dashboard appreance general setting.
2388 2579 update_option(
2389 2580 'wpsc-ap-dashboard',
2390 2581 array(
2391 - 'card-body-bg-color' => '#f9f9f9',
2582 + 'card-body-bg-color' => '#ffffff',
2392 2583 'card-body-svg-color' => '#777',
2393 2584 'card-body-text-color' => '#2c3e50',
2394 - 'widget-body-bg-color' => '#f9f9f9',
2585 + 'widget-body-bg-color' => '#ffffff',
2395 2586 'widget-body-svg-color' => '#777',
2396 2587 'widget-body-text-color' => '#2c3e50',
2397 2588 )
2398 2589 );
@@ -2456,9 +2647,9 @@
2456 2647
2457 2648 $lrs_exists = $wpdb->get_results( "SELECT id from {$wpdb->prefix}psmsc_custom_fields WHERE slug = 'last_reply_source'" );
2458 2649 if ( empty( $lrs_exists ) ) {
2459 2650
2460 - $name = esc_attr__( 'Last Reply Source', 'supportcandy' );
2651 + $name = __( 'Last Reply Source', 'supportcandy' );
2461 2652 $wpdb->insert(
2462 2653 $wpdb->prefix . 'psmsc_custom_fields',
2463 2654 array(
2464 2655 'name' => $name,
@@ -2495,9 +2686,9 @@
2495 2686 if ( version_compare( self::$current_version, '3.2.8', '<' ) ) {
2496 2687
2497 2688 $widgets = get_option( 'wpsc-dashboard-widgets', array() );
2498 2689 if ( ! isset( $widgets['week-trends'] ) ) {
2499 - $label = esc_attr__( 'Ticket statistics by day of week', 'supportcandy' );
2690 + $label = __( 'Ticket statistics by day of week', 'supportcandy' );
2500 2691 $string_translations['wpsc-dashboard-widget-week-trends'] = $label;
2501 2692 $widgets['week-trends'] = array(
2502 2693 'title' => $label,
2503 2694 'is_enable' => 1,
@@ -2542,8 +2733,335 @@
2542 2733 }
2543 2734 }
2544 2735 }
2545 2736
2737 + if ( version_compare( self::$current_version, '3.3.7', '<' ) ) {
2738 + $advanced = get_option( 'wpsc-ms-advanced-settings' );
2739 + $advanced['note-confirmation'] = 0;
2740 + update_option( 'wpsc-ms-advanced-settings', $advanced );
2741 + }
2742 +
2743 + if ( version_compare( self::$current_version, '3.3.8', '<' ) ) {
2744 +
2745 + $gdpr = get_option( 'wpsc-gdpr-settings', array() );
2746 + $gdpr['ip-address-collection'] = 1;
2747 + update_option( 'wpsc-gdpr-settings', $gdpr );
2748 +
2749 + $wpdb->query( "ALTER TABLE {$wpdb->prefix}psmsc_email_otp MODIFY otp VARCHAR(10) NOT NULL" );
2750 + }
2751 +
2752 + if ( version_compare( self::$current_version, '3.4.0', '<' ) ) {
2753 + // Create required database indexes.
2754 + self::create_indexing();
2755 + }
2756 +
2757 + if ( version_compare( self::$current_version, '3.4.2', '<' ) ) {
2758 +
2759 + // add advanced settings for archive tickets.
2760 + $advanced = get_option( 'wpsc-ms-advanced-settings' );
2761 + $advanced['auto-archive-tickets-time'] = $advanced['auto-delete-tickets-time'] ?? 0;
2762 + $advanced['auto-archive-tickets-unit'] = $advanced['auto-delete-tickets-unit'] ?? 'days';
2763 + $advanced['permanent-archive-tickets-time'] = $advanced['permanent-delete-tickets-time'] ?? 0;
2764 + $advanced['permanent-archive-tickets-unit'] = $advanced['permanent-delete-tickets-unit'] ?? 'days';
2765 + unset(
2766 + $advanced['auto-delete-tickets-time'],
2767 + $advanced['auto-delete-tickets-unit'],
2768 + );
2769 + update_option( 'wpsc-ms-advanced-settings', $advanced );
2770 +
2771 + // Remove 'dtt-access' and set new capabilities while preserving role keys.
2772 + $roles = get_option( 'wpsc-agent-roles', array() );
2773 + if ( ! empty( $roles ) && is_array( $roles ) ) {
2774 + foreach ( $roles as $key => &$role ) {
2775 + // Ensure caps array exists.
2776 + if ( empty( $role['caps'] ) || ! is_array( $role['caps'] ) ) {
2777 + $role['caps'] = array();
2778 + }
2779 + // Bydefault only Admin (1) has access to archive tickets.
2780 + $is_enabled = ( $key == 1 );
2781 + // Set new capabilities.
2782 + $role['caps']['at-unassigned'] = $is_enabled;
2783 + $role['caps']['at-assigned-me'] = $is_enabled;
2784 + $role['caps']['at-assigned-others'] = $is_enabled;
2785 + $role['caps']['at-access'] = $is_enabled;
2786 + $role['caps']['at-delete-access'] = $is_enabled;
2787 + }
2788 + update_option( 'wpsc-agent-roles', $roles );
2789 + }
2790 + }
2791 +
2792 + if ( version_compare( self::$current_version, '3.4.4', '<' ) ) {
2793 +
2794 + $atl_filters = get_option( 'wpsc-atl-default-filters', array() );
2795 + $atl_filters['deleted'] = array(
2796 + 'label' => __( 'Deleted', 'supportcandy' ),
2797 + 'is_enable' => 1,
2798 + );
2799 + update_option( 'wpsc-atl-default-filters', $atl_filters );
2800 +
2801 + // Add capability for delete ticket filter access.
2802 + $roles = get_option( 'wpsc-agent-roles', array() );
2803 + foreach ( $roles as $key => &$role ) {
2804 + $is_enabled = ( $key == 1 );
2805 + $roles[ $key ]['caps']['dtt-access'] = $is_enabled;
2806 + }
2807 + update_option( 'wpsc-agent-roles', $roles );
2808 +
2809 + // permanently delete tickets.
2810 + $advanced = get_option( 'wpsc-ms-advanced-settings' );
2811 + $advanced['permanent-delete-tickets-time'] = $advanced['permanent-archive-tickets-time'] ?? 0;
2812 + $advanced['permanent-delete-tickets-unit'] = $advanced['permanent-archive-tickets-unit'] ?? 'days';
2813 + update_option( 'wpsc-ms-advanced-settings', $advanced );
2814 +
2815 + // clear old scheduled task.
2816 + wp_clear_scheduled_hook( 'wpsc_permanently_delete_archive_tickets' );
2817 + wp_clear_scheduled_hook( 'wpsc_permenently_delete_tickets' );
2818 + wp_clear_scheduled_hook( 'wpsc_auto_archive_closed_tickets' );
2819 + }
2820 +
2821 + if ( version_compare( self::$current_version, '3.4.7', '<' ) ) {
2822 +
2823 + $widgets = get_option( 'wpsc-ticket-widget', array() );
2824 + if ( ! isset( $widgets['agent-collision'] ) ) {
2825 +
2826 + $roles = get_option( 'wpsc-agent-roles', array() );
2827 + $role_keys = array();
2828 + foreach ( $roles as $key => $role ) {
2829 + $role_keys[] = $key;
2830 + }
2831 +
2832 + $label = esc_attr__( 'Currently viewing', 'supportcandy' );
2833 + $agent_collision = array(
2834 + 'agent-collision' => array(
2835 + 'title' => $label,
2836 + 'is_enable' => 1,
2837 + 'allow-customer' => 0,
2838 + 'allowed-agent-roles' => $role_keys,
2839 + 'show-priority-to-customer' => 0,
2840 + 'callback' => 'wpsc_get_tw_agent_collision()',
2841 + 'class' => 'WPSC_ITW_Agent_Collision',
2842 + ),
2843 + );
2844 +
2845 + // append the widget on the top.
2846 + $widgets = array_merge( $agent_collision, $widgets );
2847 + update_option( 'wpsc-ticket-widget', $widgets );
2848 +
2849 + // string translations.
2850 + $string_translations = get_option( 'wpsc-string-translation' );
2851 + $string_translations['wpsc-twt-agent-collision'] = $label;
2852 + update_option( 'wpsc-string-translation', $string_translations );
2853 + }
2854 + }
2855 +
2856 + if ( version_compare( self::$current_version, '3.4.8', '<' ) ) {
2857 +
2858 + $recaptcha = get_option( 'wpsc-recaptcha-settings' );
2859 + $recaptcha['captcha-provider'] = $recaptcha['allow-recaptcha'] ? 'google-recaptcha' : '0';
2860 + $recaptcha['cloudflare-site-key'] = '';
2861 + $recaptcha['cloudflare-secret-key'] = '';
2862 + unset( $recaptcha['allow-recaptcha'] );
2863 + update_option( 'wpsc-recaptcha-settings', $recaptcha );
2864 + }
2865 +
2866 + if ( version_compare( self::$current_version, '3.5.1', '<' ) ) {
2867 +
2868 + // AI assistant feature moved into core - seed defaults for sites upgrading from an older core version.
2869 + if ( false === get_option( 'wpsc-ps-ai-assistant-settings', false ) ) {
2870 + update_option(
2871 + 'wpsc-ps-ai-assistant-settings',
2872 + array(
2873 + 'status' => '0',
2874 + 'provider' => 'openai',
2875 + 'api_key' => '',
2876 + 'model' => 'gpt-4o-mini',
2877 + 'max-tokens' => 500,
2878 + 'auto-delete-ai-logs-time' => 1,
2879 + 'auto-delete-ai-logs-unit' => 'year',
2880 + 'custom-prompt' => '',
2881 + 'summary-custom-prompt' => '',
2882 + 'auto-draft-custom-prompt' => '',
2883 + 'is-active' => 0,
2884 + 'last-error' => '',
2885 + 'ai-max-upload-file-size' => 10,
2886 + )
2887 + );
2888 + }
2889 +
2890 + if ( false === get_option( 'wpsc-ps-ai-training-sources', false ) ) {
2891 + update_option(
2892 + 'wpsc-ps-ai-training-sources',
2893 + array(
2894 + array(
2895 + 'slug' => 'local',
2896 + 'type' => 'localhost',
2897 + 'name' => 'Local',
2898 + 'api-url' => rest_url(),
2899 + 'post-types' => array(),
2900 + ),
2901 + ),
2902 + );
2903 + }
2904 +
2905 + // AI chatbot feature moved into core - seed defaults for sites upgrading from an older core version.
2906 + if ( false === get_option( 'wpsc-ps-acb-chatbot-settings', false ) ) {
2907 + update_option(
2908 + 'wpsc-ps-acb-chatbot-settings',
2909 + array(
2910 + 'status' => '0',
2911 + 'delete-acb-session-time' => 1,
2912 + 'delete-acb-session-unit' => 'year',
2913 + 'show-footer-branding' => '1',
2914 + 'sessions-per-page' => 30,
2915 + 'popup-delay-status' => '0',
2916 + 'popup-delay' => 10,
2917 + 'popup-display-limit' => 3,
2918 + 'custom-prompt' => '',
2919 + )
2920 + );
2921 + }
2922 +
2923 + if ( false === get_option( 'wpsc-acb-appearance-general', false ) ) {
2924 + update_option(
2925 + 'wpsc-acb-appearance-general',
2926 + array(
2927 + 'background-color' => '#2271b1',
2928 + 'icon-color' => '#ffffff',
2929 + 'header-text' => __( 'AI Chatbot', 'supportcandy' ),
2930 + 'greeting-text' => __( 'Hey, I\'m your assistant. How can I help you today?', 'supportcandy' ),
2931 + 'warning-text' => __( 'AI can make mistakes. Check important info.', 'supportcandy' ),
2932 + )
2933 + );
2934 + }
2935 +
2936 + // Migrate legacy AI training data - only for sites that already used AI assistant / AI chatbot via Productivity Suite.
2937 + $ps_settings = get_option( 'wpsc-ps-settings', array() );
2938 +
2939 + $wpdb->query( "UPDATE {$wpdb->prefix}psmsc_ai_training SET doc_source = 'local' WHERE source NOT IN ( 'file', 'url', 'ticket' )" );
2940 + $wpdb->query( "UPDATE {$wpdb->prefix}psmsc_ai_training SET doc_source = '' WHERE source IN ( 'file', 'url', 'ticket' )" );
2941 +
2942 + // update AI training options.
2943 + $local_post_types = array(
2944 + array(
2945 + 'slug' => 'post',
2946 + 'name' => 'Posts',
2947 + 'status' => 0,
2948 + 'endpoint' => rest_url( 'wp/v2/posts' ),
2949 + ),
2950 + array(
2951 + 'slug' => 'page',
2952 + 'name' => 'Pages',
2953 + 'status' => 0,
2954 + 'endpoint' => rest_url( 'wp/v2/pages' ),
2955 + ),
2956 + );
2957 +
2958 + $bd_settings = get_option( 'wpsc-ps-ai-bd-settings', array() );
2959 + if ( isset( $bd_settings['bd-status'] ) && $bd_settings['bd-status'] == 1 ) {
2960 + $local_post_types[] = array(
2961 + 'slug' => 'docs',
2962 + 'name' => 'Betterdocs',
2963 + 'status' => 1,
2964 + 'endpoint' => rest_url( 'wp/v2/docs' ),
2965 + );
2966 +
2967 + // Update source column for betterdocs source.
2968 + $wpdb->query( "UPDATE {$wpdb->prefix}psmsc_ai_training SET source = 'docs' WHERE source = 'betterdocs'" );
2969 + }
2970 +
2971 + update_option(
2972 + 'wpsc-ps-ai-training-sources',
2973 + array(
2974 + array(
2975 + 'slug' => 'local',
2976 + 'type' => 'localhost',
2977 + 'name' => 'Local',
2978 + 'api-url' => rest_url(),
2979 + 'post-types' => $local_post_types,
2980 + ),
2981 + ),
2982 + );
2983 +
2984 + // wpsc_ps_ai_categories is no longer used - post-type training sources are
2985 + // now routed directly by source type instead of through a categories registry.
2986 + delete_option( 'wpsc_ps_ai_categories' );
2987 +
2988 + // remove 'category', 'is_expire' and 'expiry_date' columns from AI training table.
2989 + foreach ( array( 'category', 'is_expire', 'expiry_date' ) as $column ) {
2990 + $column_exists = $wpdb->get_results( "SHOW COLUMNS FROM {$wpdb->prefix}psmsc_ai_training LIKE '{$column}'" );
2991 + if ( ! empty( $column_exists ) ) {
2992 + $wpdb->query( "ALTER TABLE {$wpdb->prefix}psmsc_ai_training DROP COLUMN {$column}" );
2993 + }
2994 + }
2995 +
2996 + // unschedule expired training cleanup cron, this feature has been removed.
2997 + wp_clear_scheduled_hook( 'wpsc_auto_delete_ai_training_expired_records' );
2998 +
2999 + // remove 'manage-ai-training' capability, this is no longer used.
3000 + $roles = get_option( 'wpsc-agent-roles', array() );
3001 + foreach ( $roles as $key => $role ) {
3002 + unset( $role['caps']['manage-ai-training'] );
3003 + $roles[ $key ] = $role;
3004 + }
3005 + update_option( 'wpsc-agent-roles', $roles );
3006 +
3007 + if ( isset( $ai_assistant['is-active'] ) ) {
3008 + $ai_assistant = get_option( 'wpsc-ps-ai-assistant-settings' );
3009 + $ai_assistant['status'] = $ai_assistant['is-active'] ? 1 : 0;
3010 + update_option( 'wpsc-ps-ai-assistant-settings', $ai_assistant );
3011 + }
3012 +
3013 + // enable chatbot feature.
3014 + if ( isset( $ps_settings['ai-chatbot'] ) ) {
3015 + $chatbot = get_option( 'wpsc-ps-acb-chatbot-settings' );
3016 + $chatbot['status'] = $ps_settings['ai-chatbot'] ? 1 : 0;
3017 + update_option( 'wpsc-ps-acb-chatbot-settings', $chatbot );
3018 + }
3019 + }
3020 +
3021 + if ( version_compare( self::$current_version, '3.5.2', '<' ) ) {
3022 +
3023 + $chatbot = get_option( 'wpsc-ps-acb-chatbot-settings' );
3024 + $chatbot['popup-delay-status'] = '0';
3025 + $chatbot['popup-delay'] = 10;
3026 + $chatbot['popup-display-limit'] = 3;
3027 + update_option( 'wpsc-ps-acb-chatbot-settings', $chatbot );
3028 + }
3029 +
3030 + if ( version_compare( self::$current_version, '3.5.3', '<' ) ) {
3031 +
3032 + $chatbot = get_option( 'wpsc-ps-acb-chatbot-settings' );
3033 + $chatbot['custom-prompt'] = '';
3034 + update_option( 'wpsc-ps-acb-chatbot-settings', $chatbot );
3035 + }
3036 +
3037 + if ( version_compare( self::$current_version, '3.5.4', '<' ) ) {
3038 +
3039 + $appearance = get_option( 'wpsc-acb-appearance-general' );
3040 + if ( is_array( $appearance ) ) {
3041 + if ( ! isset( $appearance['header-text'] ) ) {
3042 + $appearance['header-text'] = __( 'AI Chatbot', 'supportcandy' );
3043 + }
3044 + if ( ! isset( $appearance['greeting-text'] ) ) {
3045 + $appearance['greeting-text'] = __( 'Hey, I\'m your assistant. How can I help you today?', 'supportcandy' );
3046 + }
3047 + if ( ! isset( $appearance['warning-text'] ) ) {
3048 + $appearance['warning-text'] = __( 'AI can make mistakes. Check important info.', 'supportcandy' );
3049 + }
3050 + update_option( 'wpsc-acb-appearance-general', $appearance );
3051 + }
3052 +
3053 + self::create_indexing();
3054 +
3055 + update_option(
3056 + 'wpsc-onboarding-wizard',
3057 + array(
3058 + 'status' => 'completed',
3059 + 'steps' => array(),
3060 + )
3061 + );
3062 + }
3063 +
2546 3064 update_option( 'wpsc-string-translation', $string_translations );
2547 3065 self::set_upgrade_complete();
2548 3066 }
2549 3067
@@ -2579,8 +3097,89 @@
2579 3097 $upload_dir = wp_upload_dir();
2580 3098 $wpsc_dir = $upload_dir['basedir'] . '/wpsc';
2581 3099 if ( ! is_file( $wpsc_dir . '/.htaccess' ) ) {
2582 3100 @file_put_contents( $wpsc_dir . '/.htaccess', 'deny from all' ); //phpcs:ignore
3101 + }
3102 + }
3103 +
3104 + /**
3105 + * Create required database indexes
3106 + *
3107 + * @return void
3108 + */
3109 + private static function create_indexing() {
3110 +
3111 + global $wpdb;
3112 +
3113 + $column_slugs = array( 'status', 'customer', 'category', 'priority', 'date_updated', 'date_created', 'date_closed' );
3114 + foreach ( $column_slugs as $slug ) {
3115 + $index_name = "idx_cf_{$slug}";
3116 +
3117 + // Check if index already exists.
3118 + $index_exists = $wpdb->get_var(
3119 + $wpdb->prepare(
3120 + "SHOW INDEX FROM {$wpdb->prefix}psmsc_tickets WHERE Key_name = %s",
3121 + $index_name
3122 + )
3123 + );
3124 +
3125 + if ( ! $index_exists ) {
3126 + $wpdb->query( "ALTER TABLE {$wpdb->prefix}psmsc_tickets ADD INDEX {$index_name} (`{$slug}`)" );
3127 + }
3128 + }
3129 +
3130 + // create index on thread table.
3131 + $index_name = 'idx_ticket_id';
3132 + $index_exists = $wpdb->get_var(
3133 + $wpdb->prepare(
3134 + "SHOW INDEX FROM {$wpdb->prefix}psmsc_threads WHERE Key_name = %s",
3135 + $index_name
3136 + )
3137 + );
3138 + if ( ! $index_exists ) {
3139 + $wpdb->query( "ALTER TABLE {$wpdb->prefix}psmsc_threads ADD INDEX {$index_name} (ticket)" );
3140 + }
3141 +
3142 + // create index on archive ticket table.
3143 + $column_slugs = array( 'status', 'customer', 'category', 'priority', 'date_updated', 'date_created', 'date_closed' );
3144 + foreach ( $column_slugs as $slug ) {
3145 + $index_name = "idx_cf_{$slug}";
3146 +
3147 + // Check if index already exists.
3148 + $index_exists = $wpdb->get_var(
3149 + $wpdb->prepare(
3150 + "SHOW INDEX FROM {$wpdb->prefix}psmsc_archived_tickets WHERE Key_name = %s",
3151 + $index_name
3152 + )
3153 + );
3154 +
3155 + if ( ! $index_exists ) {
3156 + $wpdb->query( "ALTER TABLE {$wpdb->prefix}psmsc_archived_tickets ADD INDEX {$index_name} (`{$slug}`)" );
3157 + }
3158 + }
3159 +
3160 + // create index on thread table.
3161 + $index_name = 'idx_ticket_id';
3162 + $index_exists = $wpdb->get_var(
3163 + $wpdb->prepare(
3164 + "SHOW INDEX FROM {$wpdb->prefix}psmsc_archived_threads WHERE Key_name = %s",
3165 + $index_name
3166 + )
3167 + );
3168 + if ( ! $index_exists ) {
3169 + $wpdb->query( "ALTER TABLE {$wpdb->prefix}psmsc_archived_threads ADD INDEX {$index_name} (ticket)" );
3170 + }
3171 +
3172 + // Create index on AI training table.
3173 + $index_name = 'idx_doc_source_source_provider_source_id';
3174 + $index_exists = $wpdb->get_var(
3175 + $wpdb->prepare(
3176 + "SHOW INDEX FROM {$wpdb->prefix}psmsc_ai_training WHERE Key_name = %s",
3177 + $index_name
3178 + )
3179 + );
3180 + if ( ! $index_exists ) {
3181 + $wpdb->query( "ALTER TABLE {$wpdb->prefix}psmsc_ai_training ADD INDEX {$index_name} (doc_source, source, provider, source_id)" );
2583 3182 }
2584 3183 }
2585 3184 }
2586 3185 endif;