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 +819 -227 3.3.7 → 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,37 +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 - 'note-confirmation' => 0,
1477 - 'thread-date-display-as' => 'diff',
1478 - 'thread-date-format' => 'F d, Y h:i A',
1479 - 'do-not-notify-owner' => 1,
1480 - 'do-not-notify-owner-status' => 1,
1481 - 'ticket-id-format' => 'sequential',
1482 - 'starting-ticket-id' => 1,
1483 - 'random-id-length' => 8,
1484 - 'ticket-history-macro-threads' => 5,
1485 - 'register-user-if-not-exist' => 0,
1486 - 'auto-delete-tickets-time' => 0,
1487 - 'auto-delete-tickets-unit' => 'days',
1488 - 'permanent-delete-tickets-time' => 0,
1489 - 'permanent-delete-tickets-unit' => 'days',
1490 - 'allow-bcc' => 0,
1491 - 'allow-cc' => 0,
1492 - 'view-more' => 1,
1493 - 'allow-reply-to-close-ticket' => array( 'customer', 'agent' ),
1494 - 'raised-by-user' => 'customer',
1495 - 'allow-my-profile' => 1,
1496 - 'allow-agent-profile' => 1,
1497 - 'ticket-url-auth' => 0,
1498 - 'rest-api' => 1,
1499 - 'agent-collision' => 1,
1500 - 'self-assign' => 1,
1501 - '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,
1502 1611 )
1503 1612 );
1504 1613
1505 1614 $translation = '<p>I agree to the terms and conditions</p>';
@@ -1518,17 +1627,18 @@
1518 1627 );
1519 1628
1520 1629 // ticket widgets.
1521 1630 $labels = array(
1522 - 'change-status' => esc_attr__( 'Ticket status', 'supportcandy' ),
1523 - 'raised-by' => esc_attr__( 'Customer', 'supportcandy' ),
1524 - 'ticket-info' => esc_attr__( 'Ticket info', 'supportcandy' ),
1525 - 'assignee' => esc_attr__( 'Assignee', 'supportcandy' ),
1526 - 'ticket-fields' => esc_attr__( 'Ticket fields', 'supportcandy' ),
1527 - 'agentonly-fields' => esc_attr__( 'Agent only fields', 'supportcandy' ),
1528 - 'additional-recipients' => esc_attr__( 'Additional recipients', 'supportcandy' ),
1529 - 'biographical-info' => esc_attr__( 'Biographical Info', 'supportcandy' ),
1530 - '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' ),
1531 1641 );
1532 1642 foreach ( $labels as $key => $string ) {
1533 1643 $string_translations[ 'wpsc-twt-' . $key ] = $string;
1534 1644 }
@@ -1534,17 +1644,25 @@
1534 1644 }
1535 1645 update_option(
1536 1646 'wpsc-ticket-widget',
1537 1647 array(
1538 - 'change-status' => array(
1539 - 'title' => $labels['change-status'],
1648 + 'agent-collision' => array(
1649 + 'title' => $labels['agent-collision'],
1540 1650 'is_enable' => 1,
1541 - 'allow-customer' => 1,
1651 + 'allow-customer' => 0,
1542 1652 'allowed-agent-roles' => array( 1, 2 ),
1543 1653 'show-priority-to-customer' => 0,
1544 - 'callback' => 'wpsc_get_tw_ticket_status()',
1545 - 'class' => 'WPSC_ITW_Change_Status',
1654 + 'callback' => 'wpsc_get_tw_agent_collision()',
1655 + 'class' => 'WPSC_ITW_Agent_Collision',
1546 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 + ),
1547 1665 'raised-by' => array(
1548 1666 'title' => $labels['raised-by'],
1549 1667 'is_enable' => 1,
1550 1668 'allow-customer' => 0,
@@ -1613,9 +1731,9 @@
1613 1731
1614 1732 // Rich text editor.
1615 1733 $notice = sprintf(
1616 1734 /* translators: %1$s: attachment max file size, %2$s: allowed file extenstions. */
1617 - 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' ),
1618 1736 20,
1619 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'
1620 1738 );
1621 1739 update_option(
@@ -1701,15 +1819,8 @@
1701 1819 'z-index' => 900000000,
1702 1820 )
1703 1821 );
1704 1822 update_option(
1705 - 'wpsc-ap-agent-collision',
1706 - array(
1707 - 'header-bg-color' => '#e6e6e6',
1708 - 'header-text-color' => '#2c3e50',
1709 - )
1710 - );
1711 - update_option(
1712 1823 'wpsc-ap-ticket-list',
1713 1824 array(
1714 1825 'list-header-background-color' => '#2c3e50',
1715 1826 'list-header-text-color' => '#fff',
@@ -1734,12 +1845,12 @@
1734 1845 // dashboard general setting.
1735 1846 update_option(
1736 1847 'wpsc-ap-dashboard',
1737 1848 array(
1738 - 'card-body-bg-color' => '#f9f9f9',
1849 + 'card-body-bg-color' => '#ffffff',
1739 1850 'card-body-svg-color' => '#777',
1740 1851 'card-body-text-color' => '#2c3e50',
1741 - 'widget-body-bg-color' => '#f9f9f9',
1852 + 'widget-body-bg-color' => '#ffffff',
1742 1853 'widget-body-svg-color' => '#777',
1743 1854 'widget-body-text-color' => '#2c3e50',
1744 1855 )
1745 1856 );
@@ -1752,13 +1863,13 @@
1752 1863 }
1753 1864
1754 1865 // Dashboard cards.
1755 1866 $labels = array(
1756 - 'new-tickets' => esc_attr__( 'New Tickets', 'supportcandy' ),
1757 - 'unresolved' => esc_attr__( 'Unresolved', 'supportcandy' ),
1758 - 'unassigned' => esc_attr__( 'Unassigned', 'supportcandy' ),
1759 - 'closed' => esc_attr__( 'Closed', 'supportcandy' ),
1760 - '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' ),
1761 1872 );
1762 1873 foreach ( $labels as $key => $string ) {
1763 1874 $string_translations[ 'wpsc-dashboard-card-' . $key ] = $string;
1764 1875 }
@@ -1809,17 +1920,17 @@
1809 1920 );
1810 1921
1811 1922 // Dashboard widget.
1812 1923 $labels = array(
1813 - 'ticket-statistics' => esc_attr__( 'Ticket Statistics', 'supportcandy' ),
1814 - 'todays-trends' => esc_attr__( 'Todays Trends', 'supportcandy' ),
1815 - 'agent-list' => esc_attr__( 'Agent Workload', 'supportcandy' ),
1816 - 'recent-activities' => esc_attr__( 'Recent Activities', 'supportcandy' ),
1817 - 'recent-tickets' => esc_attr__( 'Recent Tickets', 'supportcandy' ),
1818 - 'category-report' => esc_attr__( 'Tickets by Category', 'supportcandy' ),
1819 - 'unresolved-priorities' => esc_attr__( 'Tickets by Priority', 'supportcandy' ),
1820 - 'unresolved-statuses' => esc_attr__( 'Tickets by Status', 'supportcandy' ),
1821 - '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' ),
1822 1933 );
1823 1934 foreach ( $labels as $key => $string ) {
1824 1935 $string_translations[ 'wpsc-dashboard-widget-' . $key ] = $string;
1825 1936 }
@@ -1921,10 +2032,88 @@
1921 2032 );
1922 2033
1923 2034 self::attachment_security_file();
1924 2035
2036 + // Create required database indexes.
2037 + self::create_indexing();
2038 +
1925 2039 // update string translations.
1926 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 );
1927 2116 }
1928 2117
1929 2118 /**
1930 2119 * Upgrade the version
@@ -1931,8 +2120,9 @@
1931 2120 */
1932 2121 public static function upgrade() {
1933 2122
1934 2123 global $wpdb;
2124 +
1935 2125 $string_translations = get_option( 'wpsc-string-translation' );
1936 2126
1937 2127 if ( version_compare( self::$current_version, '3.0.4', '<' ) ) {
1938 2128
@@ -2152,9 +2342,9 @@
2152 2342 }
2153 2343
2154 2344 $tag_exists = $wpdb->get_results( "SELECT id from {$wpdb->prefix}psmsc_custom_fields WHERE slug = 'tags'" );
2155 2345 if ( empty( $tag_exists ) ) {
2156 - $name = esc_attr__( 'Tags', 'supportcandy' );
2346 + $name = __( 'Tags', 'supportcandy' );
2157 2347 $wpdb->insert(
2158 2348 $wpdb->prefix . 'psmsc_custom_fields',
2159 2349 array(
2160 2350 'name' => $name,
@@ -2227,9 +2417,9 @@
2227 2417
2228 2418 if ( version_compare( self::$current_version, '3.2.4', '<' ) ) {
2229 2419
2230 2420 // add default true to admin and agent dashboard access.
2231 - $roles = get_option( 'wpsc-agent-roles' );
2421 + $roles = get_option( 'wpsc-agent-roles', array() );
2232 2422 $role_keys = array();
2233 2423 foreach ( $roles as $key => $role ) {
2234 2424 $role['caps']['dash-access'] = true;
2235 2425 $roles[ $key ] = $role;
@@ -2237,13 +2427,13 @@
2237 2427 }
2238 2428
2239 2429 // Dashboard cards.
2240 2430 $labels = array(
2241 - 'new-tickets' => esc_attr__( 'New Tickets', 'supportcandy' ),
2242 - 'unresolved' => esc_attr__( 'Unresolved', 'supportcandy' ),
2243 - 'unassigned' => esc_attr__( 'Unassigned', 'supportcandy' ),
2244 - 'closed' => esc_attr__( 'Closed', 'supportcandy' ),
2245 - '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' ),
2246 2436 );
2247 2437 foreach ( $labels as $key => $string ) {
2248 2438 $string_translations[ 'wpsc-dashboard-card-' . $key ] = $string;
2249 2439 }
@@ -2294,16 +2484,16 @@
2294 2484 );
2295 2485
2296 2486 // Dashboard widget.
2297 2487 $labels = array(
2298 - 'ticket-statistics' => esc_attr__( 'Ticket Statistics', 'supportcandy' ),
2299 - 'todays-trends' => esc_attr__( 'Todays Trends', 'supportcandy' ),
2300 - 'agent-list' => esc_attr__( 'Agent Workload', 'supportcandy' ),
2301 - 'recent-activities' => esc_attr__( 'Recent Activities', 'supportcandy' ),
2302 - 'recent-tickets' => esc_attr__( 'Recent Tickets', 'supportcandy' ),
2303 - 'category-report' => esc_attr__( 'Unresolved tickets by Category', 'supportcandy' ),
2304 - 'unresolved-priorities' => esc_attr__( 'Unresolved tickets by Priority', 'supportcandy' ),
2305 - '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' ),
2306 2496 );
2307 2497 foreach ( $labels as $key => $string ) {
2308 2498 $string_translations[ 'wpsc-dashboard-widget-' . $key ] = $string;
2309 2499 }
@@ -2388,12 +2578,12 @@
2388 2578 // dashboard appreance general setting.
2389 2579 update_option(
2390 2580 'wpsc-ap-dashboard',
2391 2581 array(
2392 - 'card-body-bg-color' => '#f9f9f9',
2582 + 'card-body-bg-color' => '#ffffff',
2393 2583 'card-body-svg-color' => '#777',
2394 2584 'card-body-text-color' => '#2c3e50',
2395 - 'widget-body-bg-color' => '#f9f9f9',
2585 + 'widget-body-bg-color' => '#ffffff',
2396 2586 'widget-body-svg-color' => '#777',
2397 2587 'widget-body-text-color' => '#2c3e50',
2398 2588 )
2399 2589 );
@@ -2457,9 +2647,9 @@
2457 2647
2458 2648 $lrs_exists = $wpdb->get_results( "SELECT id from {$wpdb->prefix}psmsc_custom_fields WHERE slug = 'last_reply_source'" );
2459 2649 if ( empty( $lrs_exists ) ) {
2460 2650
2461 - $name = esc_attr__( 'Last Reply Source', 'supportcandy' );
2651 + $name = __( 'Last Reply Source', 'supportcandy' );
2462 2652 $wpdb->insert(
2463 2653 $wpdb->prefix . 'psmsc_custom_fields',
2464 2654 array(
2465 2655 'name' => $name,
@@ -2496,9 +2686,9 @@
2496 2686 if ( version_compare( self::$current_version, '3.2.8', '<' ) ) {
2497 2687
2498 2688 $widgets = get_option( 'wpsc-dashboard-widgets', array() );
2499 2689 if ( ! isset( $widgets['week-trends'] ) ) {
2500 - $label = esc_attr__( 'Ticket statistics by day of week', 'supportcandy' );
2690 + $label = __( 'Ticket statistics by day of week', 'supportcandy' );
2501 2691 $string_translations['wpsc-dashboard-widget-week-trends'] = $label;
2502 2692 $widgets['week-trends'] = array(
2503 2693 'title' => $label,
2504 2694 'is_enable' => 1,
@@ -2549,8 +2739,329 @@
2549 2739 $advanced['note-confirmation'] = 0;
2550 2740 update_option( 'wpsc-ms-advanced-settings', $advanced );
2551 2741 }
2552 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 +
2553 3064 update_option( 'wpsc-string-translation', $string_translations );
2554 3065 self::set_upgrade_complete();
2555 3066 }
2556 3067
@@ -2586,8 +3097,89 @@
2586 3097 $upload_dir = wp_upload_dir();
2587 3098 $wpsc_dir = $upload_dir['basedir'] . '/wpsc';
2588 3099 if ( ! is_file( $wpsc_dir . '/.htaccess' ) ) {
2589 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)" );
2590 3182 }
2591 3183 }
2592 3184 }
2593 3185 endif;