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 +761 -226 3.4.1 → 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,
@@ -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 }
@@ -1460,12 +1564,14 @@
1460 1564
1461 1565 update_option(
1462 1566 'wpsc-recaptcha-settings',
1463 1567 array(
1464 - 'allow-recaptcha' => 0,
1465 - 'recaptcha-version' => 3,
1466 - 'recaptcha-site-key' => '',
1467 - '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' => '',
1468 1574 )
1469 1575 );
1470 1576
1471 1577 update_option(
@@ -1470,37 +1576,39 @@
1470 1576
1471 1577 update_option(
1472 1578 'wpsc-ms-advanced-settings',
1473 1579 array(
1474 - 'public-mode' => 0,
1475 - 'public-mode-reply' => 0,
1476 - 'reply-confirmation' => 1,
1477 - 'note-confirmation' => 0,
1478 - 'thread-date-display-as' => 'diff',
1479 - 'thread-date-format' => 'F d, Y h:i A',
1480 - 'do-not-notify-owner' => 1,
1481 - 'do-not-notify-owner-status' => 1,
1482 - 'ticket-id-format' => 'sequential',
1483 - 'starting-ticket-id' => 1,
1484 - 'random-id-length' => 8,
1485 - 'ticket-history-macro-threads' => 5,
1486 - 'register-user-if-not-exist' => 0,
1487 - 'auto-delete-tickets-time' => 0,
1488 - 'auto-delete-tickets-unit' => 'days',
1489 - 'permanent-delete-tickets-time' => 0,
1490 - 'permanent-delete-tickets-unit' => 'days',
1491 - 'allow-bcc' => 0,
1492 - 'allow-cc' => 0,
1493 - 'view-more' => 1,
1494 - 'allow-reply-to-close-ticket' => array( 'customer', 'agent' ),
1495 - 'raised-by-user' => 'customer',
1496 - 'allow-my-profile' => 1,
1497 - 'allow-agent-profile' => 1,
1498 - 'ticket-url-auth' => 0,
1499 - 'rest-api' => 1,
1500 - 'agent-collision' => 1,
1501 - 'self-assign' => 1,
1502 - '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,
1503 1611 )
1504 1612 );
1505 1613
1506 1614 $translation = '<p>I agree to the terms and conditions</p>';
@@ -1519,17 +1627,18 @@
1519 1627 );
1520 1628
1521 1629 // ticket widgets.
1522 1630 $labels = array(
1523 - 'change-status' => esc_attr__( 'Ticket status', 'supportcandy' ),
1524 - 'raised-by' => esc_attr__( 'Customer', 'supportcandy' ),
1525 - 'ticket-info' => esc_attr__( 'Ticket info', 'supportcandy' ),
1526 - 'assignee' => esc_attr__( 'Assignee', 'supportcandy' ),
1527 - 'ticket-fields' => esc_attr__( 'Ticket fields', 'supportcandy' ),
1528 - 'agentonly-fields' => esc_attr__( 'Agent only fields', 'supportcandy' ),
1529 - 'additional-recipients' => esc_attr__( 'Additional recipients', 'supportcandy' ),
1530 - 'biographical-info' => esc_attr__( 'Biographical Info', 'supportcandy' ),
1531 - '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' ),
1532 1641 );
1533 1642 foreach ( $labels as $key => $string ) {
1534 1643 $string_translations[ 'wpsc-twt-' . $key ] = $string;
1535 1644 }
@@ -1535,17 +1644,25 @@
1535 1644 }
1536 1645 update_option(
1537 1646 'wpsc-ticket-widget',
1538 1647 array(
1539 - 'change-status' => array(
1540 - 'title' => $labels['change-status'],
1648 + 'agent-collision' => array(
1649 + 'title' => $labels['agent-collision'],
1541 1650 'is_enable' => 1,
1542 - 'allow-customer' => 1,
1651 + 'allow-customer' => 0,
1543 1652 'allowed-agent-roles' => array( 1, 2 ),
1544 1653 'show-priority-to-customer' => 0,
1545 - 'callback' => 'wpsc_get_tw_ticket_status()',
1546 - 'class' => 'WPSC_ITW_Change_Status',
1654 + 'callback' => 'wpsc_get_tw_agent_collision()',
1655 + 'class' => 'WPSC_ITW_Agent_Collision',
1547 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 + ),
1548 1665 'raised-by' => array(
1549 1666 'title' => $labels['raised-by'],
1550 1667 'is_enable' => 1,
1551 1668 'allow-customer' => 0,
@@ -1614,9 +1731,9 @@
1614 1731
1615 1732 // Rich text editor.
1616 1733 $notice = sprintf(
1617 1734 /* translators: %1$s: attachment max file size, %2$s: allowed file extenstions. */
1618 - 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' ),
1619 1736 20,
1620 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'
1621 1738 );
1622 1739 update_option(
@@ -1702,15 +1819,8 @@
1702 1819 'z-index' => 900000000,
1703 1820 )
1704 1821 );
1705 1822 update_option(
1706 - 'wpsc-ap-agent-collision',
1707 - array(
1708 - 'header-bg-color' => '#e6e6e6',
1709 - 'header-text-color' => '#2c3e50',
1710 - )
1711 - );
1712 - update_option(
1713 1823 'wpsc-ap-ticket-list',
1714 1824 array(
1715 1825 'list-header-background-color' => '#2c3e50',
1716 1826 'list-header-text-color' => '#fff',
@@ -1735,12 +1845,12 @@
1735 1845 // dashboard general setting.
1736 1846 update_option(
1737 1847 'wpsc-ap-dashboard',
1738 1848 array(
1739 - 'card-body-bg-color' => '#f9f9f9',
1849 + 'card-body-bg-color' => '#ffffff',
1740 1850 'card-body-svg-color' => '#777',
1741 1851 'card-body-text-color' => '#2c3e50',
1742 - 'widget-body-bg-color' => '#f9f9f9',
1852 + 'widget-body-bg-color' => '#ffffff',
1743 1853 'widget-body-svg-color' => '#777',
1744 1854 'widget-body-text-color' => '#2c3e50',
1745 1855 )
1746 1856 );
@@ -1753,13 +1863,13 @@
1753 1863 }
1754 1864
1755 1865 // Dashboard cards.
1756 1866 $labels = array(
1757 - 'new-tickets' => esc_attr__( 'New Tickets', 'supportcandy' ),
1758 - 'unresolved' => esc_attr__( 'Unresolved', 'supportcandy' ),
1759 - 'unassigned' => esc_attr__( 'Unassigned', 'supportcandy' ),
1760 - 'closed' => esc_attr__( 'Closed', 'supportcandy' ),
1761 - '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' ),
1762 1872 );
1763 1873 foreach ( $labels as $key => $string ) {
1764 1874 $string_translations[ 'wpsc-dashboard-card-' . $key ] = $string;
1765 1875 }
@@ -1810,17 +1920,17 @@
1810 1920 );
1811 1921
1812 1922 // Dashboard widget.
1813 1923 $labels = array(
1814 - 'ticket-statistics' => esc_attr__( 'Ticket Statistics', 'supportcandy' ),
1815 - 'todays-trends' => esc_attr__( 'Todays Trends', 'supportcandy' ),
1816 - 'agent-list' => esc_attr__( 'Agent Workload', 'supportcandy' ),
1817 - 'recent-activities' => esc_attr__( 'Recent Activities', 'supportcandy' ),
1818 - 'recent-tickets' => esc_attr__( 'Recent Tickets', 'supportcandy' ),
1819 - 'category-report' => esc_attr__( 'Tickets by Category', 'supportcandy' ),
1820 - 'unresolved-priorities' => esc_attr__( 'Tickets by Priority', 'supportcandy' ),
1821 - 'unresolved-statuses' => esc_attr__( 'Tickets by Status', 'supportcandy' ),
1822 - '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' ),
1823 1933 );
1824 1934 foreach ( $labels as $key => $string ) {
1825 1935 $string_translations[ 'wpsc-dashboard-widget-' . $key ] = $string;
1826 1936 }
@@ -1927,8 +2037,83 @@
1927 2037 self::create_indexing();
1928 2038
1929 2039 // update string translations.
1930 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 );
1931 2116 }
1932 2117
1933 2118 /**
1934 2119 * Upgrade the version
@@ -1935,8 +2120,9 @@
1935 2120 */
1936 2121 public static function upgrade() {
1937 2122
1938 2123 global $wpdb;
2124 +
1939 2125 $string_translations = get_option( 'wpsc-string-translation' );
1940 2126
1941 2127 if ( version_compare( self::$current_version, '3.0.4', '<' ) ) {
1942 2128
@@ -2156,9 +2342,9 @@
2156 2342 }
2157 2343
2158 2344 $tag_exists = $wpdb->get_results( "SELECT id from {$wpdb->prefix}psmsc_custom_fields WHERE slug = 'tags'" );
2159 2345 if ( empty( $tag_exists ) ) {
2160 - $name = esc_attr__( 'Tags', 'supportcandy' );
2346 + $name = __( 'Tags', 'supportcandy' );
2161 2347 $wpdb->insert(
2162 2348 $wpdb->prefix . 'psmsc_custom_fields',
2163 2349 array(
2164 2350 'name' => $name,
@@ -2231,9 +2417,9 @@
2231 2417
2232 2418 if ( version_compare( self::$current_version, '3.2.4', '<' ) ) {
2233 2419
2234 2420 // add default true to admin and agent dashboard access.
2235 - $roles = get_option( 'wpsc-agent-roles' );
2421 + $roles = get_option( 'wpsc-agent-roles', array() );
2236 2422 $role_keys = array();
2237 2423 foreach ( $roles as $key => $role ) {
2238 2424 $role['caps']['dash-access'] = true;
2239 2425 $roles[ $key ] = $role;
@@ -2241,13 +2427,13 @@
2241 2427 }
2242 2428
2243 2429 // Dashboard cards.
2244 2430 $labels = array(
2245 - 'new-tickets' => esc_attr__( 'New Tickets', 'supportcandy' ),
2246 - 'unresolved' => esc_attr__( 'Unresolved', 'supportcandy' ),
2247 - 'unassigned' => esc_attr__( 'Unassigned', 'supportcandy' ),
2248 - 'closed' => esc_attr__( 'Closed', 'supportcandy' ),
2249 - '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' ),
2250 2436 );
2251 2437 foreach ( $labels as $key => $string ) {
2252 2438 $string_translations[ 'wpsc-dashboard-card-' . $key ] = $string;
2253 2439 }
@@ -2298,16 +2484,16 @@
2298 2484 );
2299 2485
2300 2486 // Dashboard widget.
2301 2487 $labels = array(
2302 - 'ticket-statistics' => esc_attr__( 'Ticket Statistics', 'supportcandy' ),
2303 - 'todays-trends' => esc_attr__( 'Todays Trends', 'supportcandy' ),
2304 - 'agent-list' => esc_attr__( 'Agent Workload', 'supportcandy' ),
2305 - 'recent-activities' => esc_attr__( 'Recent Activities', 'supportcandy' ),
2306 - 'recent-tickets' => esc_attr__( 'Recent Tickets', 'supportcandy' ),
2307 - 'category-report' => esc_attr__( 'Unresolved tickets by Category', 'supportcandy' ),
2308 - 'unresolved-priorities' => esc_attr__( 'Unresolved tickets by Priority', 'supportcandy' ),
2309 - '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' ),
2310 2496 );
2311 2497 foreach ( $labels as $key => $string ) {
2312 2498 $string_translations[ 'wpsc-dashboard-widget-' . $key ] = $string;
2313 2499 }
@@ -2392,12 +2578,12 @@
2392 2578 // dashboard appreance general setting.
2393 2579 update_option(
2394 2580 'wpsc-ap-dashboard',
2395 2581 array(
2396 - 'card-body-bg-color' => '#f9f9f9',
2582 + 'card-body-bg-color' => '#ffffff',
2397 2583 'card-body-svg-color' => '#777',
2398 2584 'card-body-text-color' => '#2c3e50',
2399 - 'widget-body-bg-color' => '#f9f9f9',
2585 + 'widget-body-bg-color' => '#ffffff',
2400 2586 'widget-body-svg-color' => '#777',
2401 2587 'widget-body-text-color' => '#2c3e50',
2402 2588 )
2403 2589 );
@@ -2461,9 +2647,9 @@
2461 2647
2462 2648 $lrs_exists = $wpdb->get_results( "SELECT id from {$wpdb->prefix}psmsc_custom_fields WHERE slug = 'last_reply_source'" );
2463 2649 if ( empty( $lrs_exists ) ) {
2464 2650
2465 - $name = esc_attr__( 'Last Reply Source', 'supportcandy' );
2651 + $name = __( 'Last Reply Source', 'supportcandy' );
2466 2652 $wpdb->insert(
2467 2653 $wpdb->prefix . 'psmsc_custom_fields',
2468 2654 array(
2469 2655 'name' => $name,
@@ -2500,9 +2686,9 @@
2500 2686 if ( version_compare( self::$current_version, '3.2.8', '<' ) ) {
2501 2687
2502 2688 $widgets = get_option( 'wpsc-dashboard-widgets', array() );
2503 2689 if ( ! isset( $widgets['week-trends'] ) ) {
2504 - $label = esc_attr__( 'Ticket statistics by day of week', 'supportcandy' );
2690 + $label = __( 'Ticket statistics by day of week', 'supportcandy' );
2505 2691 $string_translations['wpsc-dashboard-widget-week-trends'] = $label;
2506 2692 $widgets['week-trends'] = array(
2507 2693 'title' => $label,
2508 2694 'is_enable' => 1,
@@ -2567,8 +2753,315 @@
2567 2753 // Create required database indexes.
2568 2754 self::create_indexing();
2569 2755 }
2570 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 +
2571 3064 update_option( 'wpsc-string-translation', $string_translations );
2572 3065 self::set_upgrade_complete();
2573 3066 }
2574 3067
@@ -2643,8 +3136,50 @@
2643 3136 )
2644 3137 );
2645 3138 if ( ! $index_exists ) {
2646 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)" );
2647 3182 }
2648 3183 }
2649 3184 }
2650 3185 endif;