PluginProbe
MxChat – AI Chatbot & Content Generation for WordPress / 2.0.1
MxChat – AI Chatbot & Content Generation for WordPress v2.0.1
3.2.21 3.2.20 3.2.19 3.2.18 3.2.17 3.2.16 3.2.15 3.2.14 3.2.12 3.2.13 3.2.11 3.2.10 3.2.9 3.2.8 3.2.7 3.2.6 3.2.5 3.2.4 3.2.3 3.2.2 3.2.1 2.0.3 2.0.4 2.0.5 2.0.6 All 152 releases
← All changes | includes/class-mxchat-admin.php +824 -840 2.0.62.0.1 View file →
@@ -43,11 +43,9 @@
43 43 add_action('admin_post_mxchat_edit_intent', array($this, 'handle_edit_intent'));
44 44 add_action('save_post', array($this, 'handle_post_update'), 10, 3);
45 45 add_action('post_updated', array($this, 'handle_post_update'), 10, 3);
46 46 add_action('wp_ajax_mxchat_save_setting', array($this, 'mxchat_save_setting_callback'));
47 - add_action('wp_trash_post', array($this, 'mxchat_handle_post_delete'));
48 - add_action('before_delete_post', array($this, 'mxchat_handle_post_delete'));
49 - add_action('wp_ajax_mxchat_export_transcripts', array($this, 'export_chat_transcripts'));
47 +
50 48 add_action('wp_ajax_mxchat_save_prompts_setting', array($this, 'mxchat_save_prompts_setting_callback'));
51 49 if (isset($this->options['enable_woocommerce_integration']) &&
52 50 ($this->options['enable_woocommerce_integration'] === '1' ||
53 51 $this->options['enable_woocommerce_integration'] === 'on')) {
@@ -71,14 +69,12 @@
71 69 'api_key' => '',
72 70 'xai_api_key' => '',
73 71 'claude_api_key' => '',
74 72 'deepseek_api_key' => '',
75 - 'voyage_api_key' => '',
76 - 'embedding_model' => 'text-embedding-ada-002',
77 73 'system_prompt_instructions' => esc_html__('[EXAMPLE INSTRUCTIONS] You are an AI Chatbot assistant for this website. The primary subject you should focus on is [insert proper subject here]. Your main goal is to assist visitors with questions related to this specific topic. Here are some key things to keep in mind:
78 74 - Your name is [Chatbot Name].
79 75 - Stay focused on topics related to [insert proper subject here]. If a visitor asks about an unrelated topic, politely redirect the conversation to how you can assist them with this subject.
80 - - Do not make up links to pages. Only use specific links you see in your knowledgebase from [insert your domain]. Do not make assumptions or make up URLs.
76 + - Do not make up links to pages. Only use specific links you see in your knowledgebase.
81 77 - Keep your responses short, concise, and to the point. Provide clear and direct answers suitable for a chatbot interaction.
82 78 - Provide answers based on the knowledge available to you. If you do not have an answer to a specific question, let the visitor know that you don’t have the information.', 'mxchat'),
83 79 'model' => esc_html__('gpt-4o', 'mxchat'),
84 80 'rate_limit_logged_out' => esc_html__('100', 'mxchat'),
@@ -176,24 +172,26 @@
176 172 'mxchat-prompts',
177 173 array($this, 'mxchat_create_prompts_page')
178 174 );
179 175
176 + // Submenu page for Chat Transcripts
180 177 add_submenu_page(
181 - 'mxchat-max',
178 + 'mxchat-max', // Corrected parent slug to match the main menu
182 179 esc_html__('Chat Transcripts', 'mxchat'),
183 180 esc_html__('Transcripts', 'mxchat'),
184 181 'manage_options',
185 182 'mxchat-transcripts',
186 - array($this, 'mxchat_create_transcripts_page')
183 + array($this, 'mxchat_create_transcripts_page') // Prefixed function name with mxchat_
187 184 );
188 185
186 + // Submenu page for Intents
189 187 add_submenu_page(
190 - 'mxchat-max',
191 - esc_html__('MxChat Intents', 'mxchat'),
192 - esc_html__('Intents', 'mxchat'),
193 - 'manage_options',
194 - 'mxchat-intents',
195 - array($this, 'mxchat_intents_page_html')
188 + 'mxchat-max', // Parent slug
189 + esc_html__('MxChat Intents', 'mxchat'), // Page title
190 + esc_html__('Intents', 'mxchat'), // Menu title
191 + 'manage_options', // Capability
192 + 'mxchat-intents', // Menu slug
193 + array($this, 'mxchat_intents_page_html') // Callback function
196 194 );
197 195
198 196 add_submenu_page(
199 197 'mxchat-max',
@@ -243,8 +241,9 @@
243 241 // Also update old option for backwards compatibility
244 242 update_option('additional_popular_questions', $questions);
245 243 }
246 244 break;
245 + case 'close_button_color':
247 246 case 'user_message_bg_color':
248 247 case 'user_message_font_color':
249 248 case 'bot_message_bg_color':
250 249 case 'bot_message_font_color':
@@ -411,15 +410,16 @@
411 410 <?php endif; ?>
412 411
413 412 <div class="mxchat-agents-banner">
414 413 <p>
415 - <strong><?php echo esc_html__('The MxChat Add-Ons Platform', 'mxchat'); ?></strong><?php echo esc_html__(' is here! Pro users get unlimited access to our growing collection of powerful add-ons. ', 'mxchat'); ?><a href="<?php echo admin_url('admin.php?page=mxchat-addons'); ?>"><?php echo esc_html__('Explore all add-ons', 'mxchat'); ?></a><?php echo esc_html__(' including Forms Builder, Theme Customizer, Content Moderation, and more – all included with your lifetime Pro license!', 'mxchat'); ?>
416 - </p>
414 + <?php echo esc_html__('Pro users get exclusive access to', 'mxchat'); ?> <a href="https://mxchat.ai/agents/" target="_blank"><?php echo esc_html__('MxChat AI Agents', 'mxchat'); ?></a> <?php echo esc_html__('– our groundbreaking platform to test, refine, and deploy your chatbot with confidence. Take your AI assistant to the next level!', 'mxchat'); ?>
415 + </p>
417 416 </div>
418 417
419 418 <h2 class="mxchat-nav-tab-wrapper">
420 419 <a href="#chatbot" class="mxchat-nav-tab mxchat-nav-tab-active" data-tab="chatbot"><?php echo esc_html__('Chatbot', 'mxchat'); ?></a>
421 420 <a href="#embed" class="mxchat-nav-tab" data-tab="embed"><?php echo esc_html__('Integrations', 'mxchat'); ?></a>
421 + <a href="#theme" class="mxchat-nav-tab" data-tab="theme"><?php echo esc_html__('Theme', 'mxchat'); ?></a>
422 422 <a href="#general" class="mxchat-nav-tab" data-tab="general"><?php echo esc_html__('FAQ', 'mxchat'); ?></a>
423 423 </h2>
424 424
425 425 <div id="chatbot" class="mxchat-tab-content active">
@@ -429,8 +429,15 @@
429 429 </div>
430 430
431 431 <div id="embed" class="mxchat-tab-content">
432 432 <div class="mxchat-autosave-section">
433 + <div class="mxchat-settings-section">
434 + <h2><?php echo esc_html__('WooCommerce Settings', 'mxchat'); ?></h2>
435 + <table class="form-table">
436 + <?php do_settings_fields('mxchat-embed', 'mxchat_woocommerce_section'); ?>
437 + </table>
438 + </div>
439 + <div class="section-divider"></div>
433 440
434 441 <div class="mxchat-settings-section">
435 442 <h2><?php echo esc_html__('Loops Settings', 'mxchat'); ?></h2>
436 443 <table class="form-table">
@@ -468,8 +475,13 @@
468 475 </div>
469 476 </div>
470 477 </div>
471 478
479 + <div id="theme" class="mxchat-tab-content">
480 + <div class="mxchat-autosave-section">
481 + <?php do_settings_sections('mxchat-theme'); ?>
482 + </div>
483 + </div>
472 484
473 485 <div id="general" class="mxchat-tab-content">
474 486 <?php do_settings_sections('mxchat-general'); ?>
475 487 <p>
@@ -578,8 +590,9 @@
578 590 <?php
579 591 }
580 592
581 593
594 +
582 595 public function mxchat_create_transcripts_page() {
583 596 global $wpdb;
584 597 $table_name = $wpdb->prefix . 'mxchat_chat_transcripts';
585 598
@@ -585,341 +598,65 @@
585 598
586 599 // Get basic stats
587 600 $total_chats = $wpdb->get_var("SELECT COUNT(DISTINCT session_id) FROM $table_name");
588 601 $total_messages = $wpdb->get_var("SELECT COUNT(*) FROM $table_name");
589 -
590 - // Count unique users with detailed breakdown
591 - $total_users = $wpdb->get_var("
592 - SELECT COUNT(DISTINCT
593 - CASE
594 - WHEN user_email != '' AND user_email IS NOT NULL THEN user_email
595 - WHEN user_id != 0 THEN CONCAT('user_', user_id)
596 - WHEN user_identifier NOT LIKE 'Tech-Savvy User'
597 - AND user_identifier NOT LIKE 'Detail-Oriented User'
598 - AND user_identifier NOT LIKE 'Language Learner'
599 - AND user_identifier NOT LIKE 'Casual Browser'
600 - AND user_identifier NOT LIKE 'Policy Enforcer'
601 - AND user_identifier NOT LIKE 'Researcher'
602 - AND user_identifier NOT LIKE 'Loyalty Member'
603 - AND user_identifier NOT LIKE 'Gift Buyer'
604 - AND user_identifier NOT LIKE 'Parent or Caregiver'
605 - THEN user_identifier
606 - ELSE session_id
607 - END
608 - )
609 - FROM $table_name
610 - WHERE role != 'assistant'
611 - ");
612 -
613 - // Get user type breakdown
614 - $registered_users = $wpdb->get_var("
615 - SELECT COUNT(DISTINCT user_email)
616 - FROM $table_name
617 - WHERE user_email != '' AND user_email IS NOT NULL
618 - ");
619 -
620 - $guest_users = $wpdb->get_var("
621 - SELECT COUNT(DISTINCT user_identifier)
622 - FROM $table_name
623 - WHERE (user_email = '' OR user_email IS NULL)
624 - AND role != 'assistant'
625 - AND user_identifier NOT LIKE 'Tech-Savvy User'
626 - AND user_identifier NOT LIKE 'Detail-Oriented User'
627 - AND user_identifier NOT LIKE 'Language Learner'
628 - AND user_identifier NOT LIKE 'Casual Browser'
629 - AND user_identifier NOT LIKE 'Policy Enforcer'
630 - AND user_identifier NOT LIKE 'Researcher'
631 - AND user_identifier NOT LIKE 'Loyalty Member'
632 - AND user_identifier NOT LIKE 'Gift Buyer'
633 - AND user_identifier NOT LIKE 'Parent or Caregiver'
634 - ");
635 -
636 - // Get agent test messages count
637 - $agent_tests = $wpdb->get_var("
638 - SELECT COUNT(DISTINCT session_id)
639 - FROM $table_name
640 - WHERE user_identifier IN (
641 - 'Tech-Savvy User',
642 - 'Detail-Oriented User',
643 - 'Language Learner',
644 - 'Casual Browser',
645 - 'Policy Enforcer',
646 - 'Researcher',
647 - 'Loyalty Member',
648 - 'Gift Buyer',
649 - 'Parent or Caregiver'
650 - )
651 - ");
602 + $total_users = $wpdb->get_var("SELECT COUNT(DISTINCT user_email) FROM $table_name WHERE user_email != ''");
652 603 ?>
653 - <div class="wrap mxchat-transcripts-wrapper">
654 - <!-- Hero Section -->
655 - <div class="mxchat-transcripts-hero">
656 - <h1 class="mxchat-main-title">
657 - Chat <span class="mxchat-gradient-text">Transcripts</span>
658 - </h1>
659 - <p class="mxchat-hero-subtitle">
660 - <?php esc_html_e('Review and manage your chatbot conversations with detailed message history.', 'mxchat'); ?>
661 - </p>
662 - </div>
663 - <div class="mxchat-content">
664 - <!-- Stats Cards -->
665 - <div class="mxchat-stats-grid">
666 - <div class="mxchat-stat-card">
667 - <div class="stat-icon">💬</div>
668 - <div class="stat-content">
669 - <span class="stat-value"><?php echo esc_html($total_chats); ?></span>
670 - <span class="stat-label"><?php esc_html_e('Total Chats', 'mxchat'); ?></span>
671 - </div>
604 + <div class="wrap mxchat-admin">
605 + <!-- Stats Cards -->
606 + <div class="mxchat-stats-grid">
607 + <div class="mxchat-stat-card">
608 + <div class="stat-icon">💬</div>
609 + <div class="stat-content">
610 + <span class="stat-value"><?php echo esc_html($total_chats); ?></span>
611 + <span class="stat-label"><?php esc_html_e('Total Chats', 'mxchat'); ?></span>
672 612 </div>
673 - <div class="mxchat-stat-card">
674 - <div class="stat-icon">📝</div>
675 - <div class="stat-content">
676 - <span class="stat-value"><?php echo esc_html($total_messages); ?></span>
677 - <span class="stat-label"><?php esc_html_e('Total Messages', 'mxchat'); ?></span>
678 - </div>
613 + </div>
614 + <div class="mxchat-stat-card">
615 + <div class="stat-icon">📝</div>
616 + <div class="stat-content">
617 + <span class="stat-value"><?php echo esc_html($total_messages); ?></span>
618 + <span class="stat-label"><?php esc_html_e('Total Messages', 'mxchat'); ?></span>
679 619 </div>
680 - <div class="mxchat-stat-card">
681 - <div class="stat-icon">👥</div>
682 - <div class="stat-content">
683 - <span class="stat-value"><?php echo esc_html($total_users); ?></span>
684 - <span class="stat-label"><?php esc_html_e('Unique Users', 'mxchat'); ?></span>
685 - <span class="stat-sublabel">
686 - <?php
687 - echo sprintf(
688 - esc_html__('%d registered, %d guests, %d agent tests', 'mxchat'),
689 - $registered_users,
690 - $guest_users,
691 - $agent_tests
692 - );
693 - ?>
694 - </span>
695 - </div>
696 - </div>
697 620 </div>
698 - <!-- Search and Filter Controls -->
699 - <div class="mxchat-controls-wrapper">
700 - <div class="mxchat-search-box">
701 - <input type="text" id="mxchat-search-transcripts"
702 - placeholder="<?php esc_attr_e('Search transcripts...', 'mxchat'); ?>"
703 - class="regular-text">
621 + <div class="mxchat-stat-card">
622 + <div class="stat-icon">👥</div>
623 + <div class="stat-content">
624 + <span class="stat-value"><?php echo esc_html($total_users); ?></span>
625 + <span class="stat-label"><?php esc_html_e('Unique Users', 'mxchat'); ?></span>
704 626 </div>
705 - <form id="mxchat-delete-form" method="post">
706 - <?php wp_nonce_field('mxchat_delete_chat_history', 'mxchat_delete_chat_nonce'); ?>
707 - <div class="mxchat-controls">
708 - <button type="button" id="mxchat-export-transcripts" class="mxchat-action-button">
709 - <span class="dashicons dashicons-download"></span>
710 - <?php esc_html_e('Export All Chats', 'mxchat'); ?>
711 - </button>
712 - <button type="button" id="mxchat-select-all-transcripts" class="mxchat-select-button">
713 - <span class="dashicons dashicons-yes-alt"></span>
714 - <span class="button-text"><?php esc_html_e('Select All', 'mxchat'); ?></span>
715 - </button>
716 - <button type="submit" class="button delete-chats-button">
717 - <span class="dashicons dashicons-trash"></span>
718 - <?php esc_html_e('Delete Selected', 'mxchat'); ?>
719 - </button>
720 - </div>
721 - </form>
722 627 </div>
723 - <!-- Transcripts Container -->
724 - <div id="mxchat-transcripts"></div>
725 628 </div>
726 - </div>
727 - <?php
728 -}
729 629
730 -public function export_chat_transcripts() {
731 - if (!current_user_can('manage_options')) {
732 - wp_die(esc_html__('You do not have sufficient permissions to access this page.', 'mxchat'));
733 - }
630 + <!-- Search and Filter Controls -->
631 + <div class="mxchat-controls-wrapper">
632 + <div class="mxchat-search-box">
633 + <input type="text" id="mxchat-search-transcripts"
634 + placeholder="<?php esc_attr_e('Search transcripts...', 'mxchat'); ?>"
635 + class="regular-text">
636 + </div>
734 637
735 - check_ajax_referer('mxchat_export_transcripts', 'security');
638 + <form id="mxchat-delete-form" method="post">
639 + <?php wp_nonce_field('mxchat_delete_chat_history', 'mxchat_delete_chat_nonce'); ?>
640 + <div class="mxchat-controls">
641 + <button type="button" id="mxchat-select-all-transcripts" class="mxchat-select-button">
642 + <span class="dashicons dashicons-yes-alt"></span>
643 + <span class="button-text"><?php esc_html_e('Select All', 'mxchat'); ?></span>
644 + </button>
645 + <button type="submit" class="button delete-chats-button">
646 + <span class="dashicons dashicons-trash"></span>
647 + <?php esc_html_e('Delete Selected', 'mxchat'); ?>
648 + </button>
649 + </div>
650 + </form>
651 + </div>
736 652
737 - global $wpdb;
738 - $table_name = $wpdb->prefix . 'mxchat_chat_transcripts';
739 -
740 - // Get all transcripts ordered by session and timestamp
741 - $results = $wpdb->get_results(
742 - "SELECT session_id, user_email, user_identifier, role, message, timestamp
743 - FROM {$table_name}
744 - ORDER BY session_id, timestamp ASC"
745 - );
746 -
747 - if (empty($results)) {
748 - wp_send_json_error(array('message' => 'No transcripts found.'));
749 - wp_die();
750 - }
751 -
752 - // Set headers for CSV download
753 - header('Content-Type: text/csv');
754 - header('Content-Disposition: attachment; filename="chat-transcripts-' . date('Y-m-d') . '.csv"');
755 - header('Pragma: no-cache');
756 - header('Expires: 0');
757 -
758 - // Create output stream
759 - $output = fopen('php://output', 'w');
760 -
761 - // Add UTF-8 BOM for proper Excel encoding
762 - fputs($output, "\xEF\xBB\xBF");
763 -
764 - // Add CSV headers
765 - fputcsv($output, array(
766 - 'Session ID',
767 - 'Email',
768 - 'User Identifier',
769 - 'Role',
770 - 'Message',
771 - 'Timestamp'
772 - ));
773 -
774 - // Add data rows
775 - foreach ($results as $row) {
776 - fputcsv($output, array(
777 - $row->session_id,
778 - $row->user_email,
779 - $row->user_identifier,
780 - $row->role,
781 - $row->message,
782 - $row->timestamp
783 - ));
784 - }
785 -
786 - fclose($output);
787 - wp_die();
653 + <!-- Transcripts Container -->
654 + <div id="mxchat-transcripts"></div>
655 + </div>
656 + <?php
788 657 }
789 658
790 -public function mxchat_fetch_chat_history() {
791 - global $wpdb;
792 - $table_name = $wpdb->prefix . 'mxchat_chat_transcripts';
793 -
794 - if (!current_user_can('manage_options')) {
795 - wp_die(esc_html__('You do not have sufficient permissions to view this page.', 'mxchat'));
796 - }
797 -
798 - // First get unique session IDs ordered by most recent message in each session
799 - $session_ids = $wpdb->get_col(
800 - $wpdb->prepare(
801 - "SELECT DISTINCT session_id
802 - FROM {$table_name}
803 - GROUP BY session_id
804 - ORDER BY MAX(timestamp) DESC"
805 - )
806 - );
807 -
808 - if (empty($session_ids)) {
809 - wp_die(esc_html__('No chat history available.', 'mxchat'));
810 - }
811 -
812 - ob_start();
813 - echo '<div class="mxchat-transcript">';
814 -
815 - // Iterate through sessions from newest to oldest
816 - foreach ($session_ids as $session_id) {
817 - // Get the email associated with this session (if available)
818 - $email = $wpdb->get_var(
819 - $wpdb->prepare(
820 - "SELECT user_email
821 - FROM {$table_name}
822 - WHERE session_id = %s AND user_email != ''
823 - ORDER BY timestamp ASC
824 - LIMIT 1",
825 - $session_id
826 - )
827 - );
828 -
829 - // Debug: Check email retrieval
830 - if (empty($email)) {
831 - //error_log("No email found for session {$session_id}");
832 - } else {
833 - //error_log("Email for session {$session_id}: " . $email);
834 - }
835 -
836 - // Get messages for this session ordered by timestamp
837 - $messages = $wpdb->get_results(
838 - $wpdb->prepare(
839 - "SELECT * FROM {$table_name}
840 - WHERE session_id = %s
841 - ORDER BY timestamp ASC",
842 - $session_id
843 - )
844 - );
845 -
846 - // Start session block
847 - echo '<div class="mxchat-session">';
848 - echo '<div class="mxchat-session-header">';
849 - // Wrap checkbox and session ID in one block
850 - echo '<div class="mxchat-session-id">';
851 - echo '<input type="checkbox" name="delete_session_ids[]" value="' . esc_attr($session_id) . '"> ';
852 - echo '<strong>' . esc_html__('Session ID:', 'mxchat') . '</strong> ' . esc_html($session_id);
853 - echo '</div>';
854 -
855 - // Place email directly below the session ID block
856 - if (!empty($email)) {
857 - echo '<div class="mxchat-session-email">';
858 - echo '<strong>' . esc_html__('Email:', 'mxchat') . '</strong> ' . esc_html($email);
859 - echo '</div>';
860 - }
861 - echo '</div>';
862 -
863 - echo '<div class="mxchat-messages">';
864 -
865 - // Display messages for this session
866 - foreach ($messages as $transcript) {
867 - $formatted_timestamp = date_i18n('F j, Y g:i a', strtotime($transcript->timestamp));
868 -
869 - // Determine message styling
870 - switch ($transcript->role) {
871 - case 'assistant':
872 - case 'bot':
873 - $message_class = 'bot-message';
874 - $display_role = esc_html__('Chatbot', 'mxchat');
875 - break;
876 - case 'user':
877 - $message_class = 'user-message';
878 - $display_role = !empty($transcript->user_identifier)
879 - ? sanitize_text_field($transcript->user_identifier)
880 - : esc_html__('User', 'mxchat');
881 - break;
882 - case 'agent':
883 - $message_class = 'agent-message';
884 - $display_role = esc_html__('Agent', 'mxchat');
885 - break;
886 - default:
887 - $message_class = 'unknown-message';
888 - $display_role = esc_html__('Unknown', 'mxchat');
889 - }
890 -
891 - // Process message content
892 - $message_content = wp_kses(
893 - stripslashes($transcript->message),
894 - [
895 - 'b' => [], 'strong' => [], 'i' => [], 'em' => [], 'u' => [],
896 - 'br' => [], 'p' => [], 'ul' => [], 'ol' => [], 'li' => [],
897 - 'a' => ['href' => [], 'title' => []]
898 - ]
899 - );
900 - $message_content = nl2br($message_content);
901 -
902 - // Render message
903 - echo '<div class="mxchat-message ' . esc_attr($message_class) . '">';
904 - echo '<div class="mxchat-message-header">' . esc_html($display_role) . '</div>';
905 - echo '<div class="mxchat-message-content">' . $message_content . '</div>';
906 - echo '<div class="mxchat-timestamp">' . esc_html($formatted_timestamp) . '</div>';
907 - echo '</div>';
908 - }
909 -
910 - // Close session block
911 - echo '</div></div>';
912 - }
913 -
914 - echo '</div>';
915 - $output = ob_get_clean();
916 - echo $output;
917 - wp_die();
918 -}
919 -
920 -
921 -
922 659 public function mxchat_create_prompts_page() {
923 660 global $wpdb;
924 661 $table_name = $wpdb->prefix . 'mxchat_system_prompt_content';
925 662
@@ -1010,9 +747,9 @@
1010 747 <!-- Auto-Sync Settings -->
1011 748 <div class="mxchat-settings-section">
1012 749 <h3><?php esc_html_e('Auto-Sync Settings', 'mxchat'); ?></h3>
1013 750 <p class="mxchat-description">
1014 - <?php esc_html_e('Note: Auto-sync works only for newly published content. Existing posts and pages must be imported manually below. Works with Pinecone if enabled', 'mxchat'); ?>
751 + <?php esc_html_e('Note: Auto-sync works only for newly published content. Existing posts and pages must be imported manually below.', 'mxchat'); ?>
1015 752 </p>
1016 753 <div class="mxchat-autosave-section"> <!-- Add this wrapper -->
1017 754 <div class="mxchat-toggle-group">
1018 755 <div class="mxchat-toggle-container">
@@ -1050,9 +787,10 @@
1050 787 <!-- Import Methods -->
1051 788 <div class="mxchat-import-methods">
1052 789 <div class="mxchat-method-card">
1053 790 <h4><?php esc_html_e('Sitemap Import', 'mxchat'); ?></h4>
1054 - <p><span class="red-warning">IMPORTANT:</span> <?php esc_html_e('Use a content-specific sub-sitemap, not the sitemap index.', 'mxchat'); ?></p> </div>
791 + <p><?php esc_html_e('Import all content from your sitemap automatically.', 'mxchat'); ?></p>
792 + </div>
1055 793 <div class="mxchat-method-card">
1056 794 <h4><?php esc_html_e('PDF Import', 'mxchat'); ?></h4>
1057 795 <p><?php esc_html_e('Import knowledge directly from PDF documents.', 'mxchat'); ?></p>
1058 796 </div>
@@ -1127,9 +865,9 @@
1127 865
1128 866 <?php if ($sitemap_status && $sitemap_status['status'] !== 'complete') : ?>
1129 867 <div class="mxchat-status-card">
1130 868 <div class="mxchat-status-header">
1131 - <h4><?php esc_html_e('Sitemap Processing Status (Refresh for update)', 'mxchat'); ?></h4>
869 + <h4><?php esc_html_e('Sitemap Processing Status', 'mxchat'); ?></h4>
1132 870 <?php if ($is_processing) : ?>
1133 871 <form method="post" class="mxchat-stop-form"
1134 872 action="<?php echo esc_url(admin_url('admin-post.php?action=mxchat_stop_processing')); ?>">
1135 873 <?php wp_nonce_field('mxchat_stop_processing_action', 'mxchat_stop_processing_nonce'); ?>
@@ -1359,90 +1097,30 @@
1359 1097
1360 1098 wp_safe_redirect(add_query_arg(array('page' => 'mxchat-prompts', 'deleted' => 'true'), admin_url('admin.php')));
1361 1099 exit;
1362 1100 }
1363 -
1364 -
1365 1101 public function mxchat_generate_embedding($text) {
1366 - //error_log('Starting embedding generation for text: ' . substr($text, 0, 100) . '...');
1102 + $options = get_option('mxchat_options');
1103 + $api_key = $options['api_key'] ?? esc_html__('default_api_key', 'mxchat');
1367 1104
1368 - $options = get_option('mxchat_options');
1369 - $selected_model = $options['embedding_model'] ?? 'text-embedding-ada-002';
1370 - //error_log('Selected embedding model: ' . $selected_model);
1105 + $response = wp_remote_post('https://api.openai.com/v1/embeddings', array(
1106 + 'body' => wp_json_encode(array(
1107 + 'model' => esc_html__('text-embedding-ada-002', 'mxchat'),
1108 + 'input' => $text
1109 + )),
1110 + 'headers' => array(
1111 + 'Authorization' => 'Bearer ' . $api_key,
1112 + 'Content-Type' => esc_html__('application/json', 'mxchat')
1113 + ),
1114 + ));
1371 1115
1372 - // Determine provider and endpoint
1373 - if (strpos($selected_model, 'voyage') === 0) {
1374 - $api_key = $options['voyage_api_key'] ?? '';
1375 - $endpoint = 'https://api.voyageai.com/v1/embeddings';
1376 - } else {
1377 - $api_key = $options['api_key'] ?? '';
1378 - $endpoint = 'https://api.openai.com/v1/embeddings';
1379 - }
1380 - //error_log('Using endpoint: ' . $endpoint);
1116 + if (is_wp_error($response)) {
1117 + return null;
1118 + }
1381 1119
1382 - if (empty($api_key)) {
1383 - //error_log('Error: API key not configured');
1384 - return null;
1120 + $response_data = json_decode(wp_remote_retrieve_body($response), true);
1121 + return $response_data['data'][0]['embedding'] ?? null;
1385 1122 }
1386 -
1387 - // Prepare request body
1388 - $request_body = array(
1389 - 'model' => $selected_model,
1390 - 'input' => $text
1391 - );
1392 -
1393 - // Add output_dimension for voyage-3-large model
1394 - if ($selected_model === 'voyage-3-large') {
1395 - $request_body['output_dimension'] = 2048;
1396 - }
1397 -
1398 - //error_log('Request body prepared: ' . wp_json_encode($request_body));
1399 -
1400 - // Make API request
1401 - $response = wp_remote_post($endpoint, array(
1402 - 'body' => wp_json_encode($request_body),
1403 - 'headers' => array(
1404 - 'Authorization' => 'Bearer ' . $api_key,
1405 - 'Content-Type' => 'application/json'
1406 - ),
1407 - 'timeout' => 30
1408 - ));
1409 -
1410 - // Handle wp_remote_post errors
1411 - if (is_wp_error($response)) {
1412 - //error_log('WP Remote Post Error: ' . $response->get_error_message());
1413 - return null;
1414 - }
1415 -
1416 - // Get and check HTTP response code
1417 - $http_code = wp_remote_retrieve_response_code($response);
1418 - //error_log('API Response Code: ' . $http_code);
1419 -
1420 - if ($http_code !== 200) {
1421 - //error_log('API Error Response Body: ' . wp_remote_retrieve_body($response));
1422 - return null;
1423 - }
1424 -
1425 - // Parse response body
1426 - $response_data = json_decode(wp_remote_retrieve_body($response), true);
1427 -
1428 - if (json_last_error() !== JSON_ERROR_NONE) {
1429 - //error_log('JSON Parse Error: ' . json_last_error_msg());
1430 - return null;
1431 - }
1432 -
1433 - // Both APIs use the same structure, so we can extract the embedding the same way
1434 - if (isset($response_data['data'][0]['embedding'])) {
1435 - //error_log('Successfully extracted embedding');
1436 - //error_log('Embedding dimension: ' . count($response_data['data'][0]['embedding']));
1437 - return $response_data['data'][0]['embedding'];
1438 - } else {
1439 - //error_log('Error: No embedding found in response. Response structure: ' . wp_json_encode($response_data));
1440 - return null;
1441 - }
1442 -}
1443 -
1444 -
1445 1123 public function mxchat_delete_chat_history() {
1446 1124 if (!current_user_can('manage_options')) {
1447 1125 echo wp_json_encode(['error' => esc_html__('You do not have sufficient permissions.', 'mxchat')]);
1448 1126 wp_die();
@@ -1591,9 +1269,9 @@
1591 1269 $pinecone_settings['mxchat_pinecone_index']
1592 1270 );
1593 1271
1594 1272 if (!$pinecone_result['success']) {
1595 - //error_log('MXChat: Pinecone sync failed - falling back to WordPress DB');
1273 + error_log('MXChat: Pinecone sync failed - falling back to WordPress DB');
1596 1274 $this->store_in_wordpress_db($content, $url, $embedding_vector);
1597 1275 }
1598 1276 } else {
1599 1277 // Fallback to WordPress DB storage
@@ -1599,15 +1277,19 @@
1599 1277 // Fallback to WordPress DB storage
1600 1278 $this->store_in_wordpress_db($content, $url, $embedding_vector);
1601 1279 }
1602 1280 }
1603 -// Modified storage function to add type field
1281 +
1604 1282 private function store_in_pinecone_main($embedding_vector, $content, $url, $api_key, $environment, $index_name, $vector_id = null) {
1283 + // Generate vector ID based on URL for consistent updates/inserts
1605 1284 $vector_id = $vector_id ?: md5($url);
1285 +
1286 + // Get the Pinecone host from options
1606 1287 $options = get_option('mxchat_pinecone_addon_options');
1607 1288 $host = $options['mxchat_pinecone_host'] ?? '';
1608 1289
1609 1290 if (empty($host)) {
1291 + //error_log('Pinecone host is not configured');
1610 1292 return array(
1611 1293 'success' => false,
1612 1294 'message' => 'Pinecone host is not configured. Please set the host in your settings.'
1613 1295 );
@@ -1612,12 +1294,11 @@
1612 1294 'message' => 'Pinecone host is not configured. Please set the host in your settings.'
1613 1295 );
1614 1296 }
1615 1297
1616 - // Determine if this is a product URL
1617 - $is_product = (strpos($url, '/product/') !== false || strpos($url, '/shop/') !== false);
1298 + // Build API endpoint using the configured host
1299 + $api_endpoint = "https://{$host}/vectors/upsert";
1618 1300
1619 - $api_endpoint = "https://{$host}/vectors/upsert";
1620 1301 $request_body = array(
1621 1302 'vectors' => array(
1622 1303 array(
1623 1304 'id' => $vector_id,
@@ -1624,9 +1305,8 @@
1624 1305 'values' => $embedding_vector,
1625 1306 'metadata' => array(
1626 1307 'text' => $content,
1627 1308 'source_url' => $url,
1628 - 'type' => $is_product ? 'product' : 'content',
1629 1309 'last_updated' => time()
1630 1310 )
1631 1311 )
1632 1312 )
@@ -1643,8 +1323,9 @@
1643 1323 'data_format' => 'body'
1644 1324 ));
1645 1325
1646 1326 if (is_wp_error($response)) {
1327 + //error_log('Pinecone API WP Error: ' . $response->get_error_message());
1647 1328 return array(
1648 1329 'success' => false,
1649 1330 'message' => $response->get_error_message()
1650 1331 );
@@ -1652,8 +1333,10 @@
1652 1333
1653 1334 $response_code = wp_remote_retrieve_response_code($response);
1654 1335 if ($response_code !== 200) {
1655 1336 $body = wp_remote_retrieve_body($response);
1337 + //error_log('Pinecone API Error Body: ' . $body);
1338 + //error_log('Pinecone API Request: ' . wp_json_encode($request_body));
1656 1339 return array(
1657 1340 'success' => false,
1658 1341 'message' => sprintf(
1659 1342 'Pinecone API error (HTTP %d): %s',
@@ -1667,8 +1350,10 @@
1667 1350 'success' => true,
1668 1351 'message' => 'Successfully stored in Pinecone'
1669 1352 );
1670 1353 }
1354 +
1355 +
1671 1356 // Helper method for WordPress DB storage
1672 1357 private function store_in_wordpress_db($content, $url, $embedding_vector) {
1673 1358 global $wpdb;
1674 1359 $table_name = $wpdb->prefix . 'mxchat_system_prompt_content';
@@ -1700,103 +1385,10 @@
1700 1385 array('%s', '%s', '%s', '%s')
1701 1386 );
1702 1387 }
1703 1388 }
1704 -/**
1705 - * Handle deletion of posts and pages from both Pinecone and WordPress DB
1706 - *
1707 - * @param int $post_id The ID of the post being deleted
1708 - * @return void
1709 - */
1710 -public function mxchat_handle_post_delete($post_id) {
1711 - // Get post data before it's deleted
1712 - $post = get_post($post_id);
1713 1389
1714 - // Basic validation
1715 - if (!$post || wp_is_post_revision($post_id)) {
1716 - return;
1717 - }
1718 1390
1719 - // Check post type
1720 - $post_type = $post->post_type;
1721 - if (!in_array($post_type, array('post', 'page'))) {
1722 - return;
1723 - }
1724 -
1725 - // Check if sync is enabled for this post type
1726 - $sync_option = ($post_type === 'post') ? 'mxchat_auto_sync_posts' : 'mxchat_auto_sync_pages';
1727 - if (get_option($sync_option) != '1') {
1728 - return;
1729 - }
1730 -
1731 - // Get the URL before post is deleted
1732 - $source_url = get_permalink($post_id);
1733 - if (!$source_url) {
1734 - //error_log('MXChat: Failed to get permalink for post ' . $post_id);
1735 - return;
1736 - }
1737 -
1738 - // Check for Pinecone addon and its settings
1739 - $pinecone_settings = get_option('mxchat_pinecone_addon_options');
1740 - $use_pinecone = false;
1741 - if ($pinecone_settings && is_array($pinecone_settings)) {
1742 - $use_pinecone = (
1743 - isset($pinecone_settings['mxchat_use_pinecone']) &&
1744 - $pinecone_settings['mxchat_use_pinecone'] === '1' &&
1745 - !empty($pinecone_settings['mxchat_pinecone_api_key']) &&
1746 - !empty($pinecone_settings['mxchat_pinecone_host']) &&
1747 - !empty($pinecone_settings['mxchat_pinecone_index']) &&
1748 - !empty($pinecone_settings['mxchat_pinecone_environment'])
1749 - );
1750 - }
1751 -
1752 - $deletion_successful = false;
1753 -
1754 - if ($use_pinecone) {
1755 - try {
1756 - $pinecone_result = $this->delete_from_pinecone(
1757 - array($source_url),
1758 - $pinecone_settings['mxchat_pinecone_api_key'],
1759 - $pinecone_settings['mxchat_pinecone_environment'],
1760 - $pinecone_settings['mxchat_pinecone_index']
1761 - );
1762 -
1763 - if (!$pinecone_result['success']) {
1764 - //error_log('MXChat: Pinecone deletion failed for URL: ' . $source_url . ' - ' . $pinecone_result['message']);
1765 - } else {
1766 - $deletion_successful = true;
1767 - }
1768 - } catch (Exception $e) {
1769 - //error_log('MXChat: Exception during Pinecone deletion - ' . $e->getMessage());
1770 - }
1771 - }
1772 -
1773 - // Always attempt WordPress DB deletion, regardless of Pinecone status
1774 - try {
1775 - global $wpdb;
1776 - $table_name = $wpdb->prefix . 'mxchat_system_prompt_content';
1777 -
1778 - $result = $wpdb->delete(
1779 - $table_name,
1780 - array('source_url' => $source_url),
1781 - array('%s')
1782 - );
1783 -
1784 - if ($result === false) {
1785 - //error_log('MXChat: WordPress DB deletion failed for URL: ' . $source_url);
1786 - } else {
1787 - $deletion_successful = true;
1788 - }
1789 - } catch (Exception $e) {
1790 - //error_log('MXChat: Exception during WordPress DB deletion - ' . $e->getMessage());
1791 - }
1792 -
1793 - if (!$deletion_successful) {
1794 - //error_log('MXChat: Complete deletion failure for post ID: ' . $post_id . ' URL: ' . $source_url);
1795 - }
1796 -}
1797 -
1798 -
1799 1391 public function mxchat_handle_content_submission() {
1800 1392 // Check if the form was submitted and the user has permission.
1801 1393 if (!isset($_POST['submit_content']) || !current_user_can('manage_options')) {
1802 1394 return;
@@ -2303,9 +1895,9 @@
2303 1895
2304 1896 $batch_stats['processed']++;
2305 1897 } else {
2306 1898 $batch_stats['failed']++;
2307 - $batch_stats['last_error'] = 'Failed to generate embedding. Please check embedding API key.';
1899 + $batch_stats['last_error'] = 'Failed to generate embedding. Please check OpenAI API key.';
2308 1900 }
2309 1901 }
2310 1902
2311 1903 $status['processed_urls'] = absint($i + 1);
@@ -2534,102 +2126,139 @@
2534 2126 $wpdb->delete($table_name, array('source_url' => $source_url), array('%s'));
2535 2127 }
2536 2128 }
2537 2129
2130 +public function mxchat_fetch_chat_history() {
2131 + global $wpdb;
2132 + $table_name = $wpdb->prefix . 'mxchat_chat_transcripts';
2538 2133
2539 -/**
2540 - * Delete vectors from Pinecone by source URL
2541 - *
2542 - * @param array $urls Array of source URLs to delete
2543 - * @param string $api_key Pinecone API key
2544 - * @param string $environment Pinecone environment
2545 - * @param string $index_name Pinecone index name
2546 - * @return array Associative array with 'success' boolean and 'message' string
2547 - */
2548 -private function delete_from_pinecone($urls, $api_key, $environment, $index_name) {
2549 - // Get the Pinecone host from options (matching your store_in_pinecone_main pattern)
2550 - $options = get_option('mxchat_pinecone_addon_options');
2551 - $host = $options['mxchat_pinecone_host'] ?? '';
2552 -
2553 - if (empty($host)) {
2554 - return array(
2555 - 'success' => false,
2556 - 'message' => 'Pinecone host is not configured. Please set the host in your settings.'
2557 - );
2134 + if (!current_user_can('manage_options')) {
2135 + wp_die(esc_html__('You do not have sufficient permissions to view this page.', 'mxchat'));
2558 2136 }
2559 2137
2560 - // Build API endpoint using the configured host
2561 - $api_endpoint = "https://{$host}/vectors/delete";
2562 -
2563 - // Create vector IDs from URLs (matching your store method's ID generation)
2564 - $vector_ids = array_map('md5', $urls);
2565 -
2566 - // Prepare the delete request body
2567 - $request_body = array(
2568 - 'ids' => $vector_ids,
2569 - 'filter' => array(
2570 - 'source_url' => array(
2571 - '$in' => $urls
2572 - )
2138 + // First get unique session IDs ordered by most recent message in each session
2139 + $session_ids = $wpdb->get_col(
2140 + $wpdb->prepare(
2141 + "SELECT DISTINCT session_id
2142 + FROM {$table_name}
2143 + GROUP BY session_id
2144 + ORDER BY MAX(timestamp) DESC"
2573 2145 )
2574 2146 );
2575 2147
2576 - // Make the deletion request
2577 - $response = wp_remote_post($api_endpoint, array(
2578 - 'headers' => array(
2579 - 'Api-Key' => $api_key,
2580 - 'accept' => 'application/json',
2581 - 'content-type' => 'application/json'
2582 - ),
2583 - 'body' => wp_json_encode($request_body),
2584 - 'timeout' => 30,
2585 - 'data_format' => 'body'
2586 - ));
2148 + if (empty($session_ids)) {
2149 + wp_die(esc_html__('No chat history available.', 'mxchat'));
2150 + }
2587 2151
2588 - // Handle WordPress HTTP API errors
2589 - if (is_wp_error($response)) {
2590 - return array(
2591 - 'success' => false,
2592 - 'message' => $response->get_error_message()
2152 + ob_start();
2153 + echo '<div class="mxchat-transcript">';
2154 +
2155 + // Iterate through sessions from newest to oldest
2156 + foreach ($session_ids as $session_id) {
2157 + // Get the email associated with this session (if available)
2158 + $email = $wpdb->get_var(
2159 + $wpdb->prepare(
2160 + "SELECT user_email
2161 + FROM {$table_name}
2162 + WHERE session_id = %s AND user_email != ''
2163 + ORDER BY timestamp ASC
2164 + LIMIT 1",
2165 + $session_id
2166 + )
2593 2167 );
2594 - }
2595 2168
2596 - // Check response status
2597 - $response_code = wp_remote_retrieve_response_code($response);
2598 - if ($response_code !== 200) {
2599 - $body = wp_remote_retrieve_body($response);
2600 - return array(
2601 - 'success' => false,
2602 - 'message' => sprintf(
2603 - 'Pinecone API error (HTTP %d): %s',
2604 - $response_code,
2605 - $body
2169 + // Debug: Check email retrieval
2170 + if (empty($email)) {
2171 + //error_log("No email found for session {$session_id}");
2172 + } else {
2173 + //error_log("Email for session {$session_id}: " . $email);
2174 + }
2175 +
2176 + // Get messages for this session ordered by timestamp
2177 + $messages = $wpdb->get_results(
2178 + $wpdb->prepare(
2179 + "SELECT * FROM {$table_name}
2180 + WHERE session_id = %s
2181 + ORDER BY timestamp ASC",
2182 + $session_id
2606 2183 )
2607 2184 );
2608 - }
2609 2185
2610 - // Parse response body
2611 - $body = wp_remote_retrieve_body($response);
2612 - $response_data = json_decode($body, true);
2186 + // Start session block
2187 + echo '<div class="mxchat-session">';
2188 + echo '<div class="mxchat-session-header">';
2189 + // Wrap checkbox and session ID in one block
2190 + echo '<div class="mxchat-session-id">';
2191 + echo '<input type="checkbox" name="delete_session_ids[]" value="' . esc_attr($session_id) . '"> ';
2192 + echo '<strong>' . esc_html__('Session ID:', 'mxchat') . '</strong> ' . esc_html($session_id);
2193 + echo '</div>';
2613 2194
2614 - // Final validation of the response
2615 - if (json_last_error() !== JSON_ERROR_NONE) {
2616 - return array(
2617 - 'success' => false,
2618 - 'message' => 'Failed to parse Pinecone response: ' . json_last_error_msg()
2619 - );
2620 - }
2195 + // Place email directly below the session ID block
2196 + if (!empty($email)) {
2197 + echo '<div class="mxchat-session-email">';
2198 + echo '<strong>' . esc_html__('Email:', 'mxchat') . '</strong> ' . esc_html($email);
2199 + echo '</div>';
2200 + }
2201 + echo '</div>';
2621 2202
2622 - return array(
2623 - 'success' => true,
2624 - 'message' => sprintf('Successfully deleted %d vectors from Pinecone', count($vector_ids))
2625 - );
2626 -}
2203 + echo '<div class="mxchat-messages">';
2627 2204
2205 + // Display messages for this session
2206 + foreach ($messages as $transcript) {
2207 + $formatted_timestamp = date_i18n('F j, Y g:i a', strtotime($transcript->timestamp));
2628 2208
2209 + // Determine message styling
2210 + switch ($transcript->role) {
2211 + case 'assistant':
2212 + case 'bot':
2213 + $message_class = 'bot-message';
2214 + $display_role = esc_html__('Chatbot', 'mxchat');
2215 + break;
2216 + case 'user':
2217 + $message_class = 'user-message';
2218 + $display_role = !empty($transcript->user_identifier)
2219 + ? sanitize_text_field($transcript->user_identifier)
2220 + : esc_html__('User', 'mxchat');
2221 + break;
2222 + case 'agent':
2223 + $message_class = 'agent-message';
2224 + $display_role = esc_html__('Agent', 'mxchat');
2225 + break;
2226 + default:
2227 + $message_class = 'unknown-message';
2228 + $display_role = esc_html__('Unknown', 'mxchat');
2229 + }
2629 2230
2231 + // Process message content
2232 + $message_content = wp_kses(
2233 + stripslashes($transcript->message),
2234 + [
2235 + 'b' => [], 'strong' => [], 'i' => [], 'em' => [], 'u' => [],
2236 + 'br' => [], 'p' => [], 'ul' => [], 'ol' => [], 'li' => [],
2237 + 'a' => ['href' => [], 'title' => []]
2238 + ]
2239 + );
2240 + $message_content = nl2br($message_content);
2630 2241
2242 + // Render message
2243 + echo '<div class="mxchat-message ' . esc_attr($message_class) . '">';
2244 + echo '<div class="mxchat-message-header">' . esc_html($display_role) . '</div>';
2245 + echo '<div class="mxchat-message-content">' . $message_content . '</div>';
2246 + echo '<div class="mxchat-timestamp">' . esc_html($formatted_timestamp) . '</div>';
2247 + echo '</div>';
2248 + }
2631 2249
2250 + // Close session block
2251 + echo '</div></div>';
2252 + }
2253 +
2254 + echo '</div>';
2255 + $output = ob_get_clean();
2256 + echo $output;
2257 + wp_die();
2258 +}
2259 +
2260 +
2632 2261 public function mxchat_create_activation_page() {
2633 2262 $license_status = get_option('mxchat_license_status', 'inactive');
2634 2263 $license_error = get_option('mxchat_license_error', '');
2635 2264 ?>
@@ -2864,123 +2493,83 @@
2864 2493 <th><?php esc_html_e('Similarity Threshold', 'mxchat'); ?></th>
2865 2494 <th><?php esc_html_e('Actions', 'mxchat'); ?></th>
2866 2495 </tr>
2867 2496 </thead>
2868 - <tbody>
2869 - <?php if ($intents) :
2870 - foreach ($intents as $intent) :
2871 - $callback_function = $intent->callback_function;
2872 - $callback_label = isset($available_callbacks[$callback_function]['label'])
2873 - ? $available_callbacks[$callback_function]['label']
2874 - : $callback_function;
2875 - $threshold_value = isset($intent->similarity_threshold)
2876 - ? round($intent->similarity_threshold * 100)
2877 - : 85;
2878 -
2879 - // Check if this is a form intent (its intent_label starts with "Form ")
2880 - $is_form_intent = strpos($intent->intent_label, 'Form ') === 0;
2881 - ?>
2882 - <tr<?php echo $is_form_intent ? ' class="mxchat-form-intent"' : ''; ?>>
2883 - <td>
2884 - <?php
2885 - if ($is_form_intent) {
2886 - // Attempt to extract the form ID from the intent_label.
2887 - preg_match('/Form (\d+)/', $intent->intent_label, $matches);
2888 - $form_id = isset($matches[1]) ? intval($matches[1]) : 0;
2889 - if ($form_id) {
2890 - global $wpdb;
2891 - $forms_table = $wpdb->prefix . 'mxchat_forms';
2892 - $form = $wpdb->get_row($wpdb->prepare("SELECT title FROM $forms_table WHERE id = %d", $form_id));
2893 - if ($form && !empty($form->title)) {
2894 - echo esc_html($form->title);
2895 - } else {
2896 - echo esc_html($intent->intent_label);
2897 - }
2898 - } else {
2899 - echo esc_html($intent->intent_label);
2900 - }
2901 - echo ' <span class="mxchat-badge">Form Intent</span>';
2902 - } else {
2903 - echo esc_html($intent->intent_label);
2904 - }
2905 - ?>
2906 - </td>
2907 - <td class="mxchat-content-cell">
2908 - <?php echo esc_html($intent->phrases); ?>
2909 - </td>
2910 - <td><?php echo esc_html($callback_label); ?></td>
2911 - <td>
2912 - <!-- Similarity threshold adjustment (shown for all intents) -->
2913 - <form method="post"
2914 - action="<?php echo esc_url(admin_url('admin-post.php')); ?>"
2915 - class="mxchat-threshold-form">
2916 - <?php wp_nonce_field('mxchat_update_intent_threshold_nonce'); ?>
2917 - <input type="hidden" name="action"
2918 - value="mxchat_update_intent_threshold">
2919 - <input type="hidden" name="intent_id"
2920 - value="<?php echo esc_attr($intent->id); ?>">
2921 - <div class="mxchat-slider-group">
2922 - <input type="range"
2923 - name="intent_threshold"
2924 - id="intent_threshold_<?php echo esc_attr($intent->id); ?>"
2925 - min="70"
2926 - max="95"
2927 - value="<?php echo esc_attr($threshold_value); ?>"
2928 - class="mxchat-intent-slider"
2929 - oninput="document.getElementById('threshold_output_<?php echo esc_attr($intent->id); ?>').value = this.value + '%'">
2930 - <output id="threshold_output_<?php echo esc_attr($intent->id); ?>"
2931 - class="mxchat-intent-output">
2932 - <?php echo esc_html($threshold_value); ?>%
2933 - </output>
2934 - </div>
2935 - <button type="submit" class="mxchat-button-icon">
2936 - <span class="dashicons dashicons-saved"></span>
2937 - </button>
2938 - </form>
2939 - </td>
2940 - <td class="mxchat-actions-cell">
2941 - <?php if (!$is_form_intent) : ?>
2942 - <!-- Standard intents: allow edit and delete -->
2943 - <button type="button"
2944 - class="mxchat-button-icon mxchat-edit-button"
2945 - data-intent-id="<?php echo esc_attr($intent->id); ?>"
2946 - data-phrases="<?php echo esc_attr($intent->phrases); ?>">
2947 - <span class="dashicons dashicons-edit"></span>
2948 - </button>
2949 - <form method="post"
2950 - action="<?php echo esc_url(admin_url('admin-post.php')); ?>"
2951 - class="mxchat-delete-form"
2952 - onsubmit="return confirm('<?php esc_attr_e('Are you sure you want to delete this intent?', 'mxchat'); ?>');">
2953 - <?php wp_nonce_field('mxchat_delete_intent_nonce'); ?>
2954 - <input type="hidden" name="action" value="mxchat_delete_intent">
2955 - <input type="hidden" name="intent_id"
2956 - value="<?php echo esc_attr($intent->id); ?>">
2957 - <button type="submit" class="mxchat-button-icon">
2958 - <span class="dashicons dashicons-trash"></span>
2959 - </button>
2960 - </form>
2961 - <?php else : ?>
2962 - <!-- Form intents: show manage in forms button -->
2963 - <?php
2964 - preg_match('/Form (\d+)/', $intent->intent_label, $matches);
2965 - $form_id = isset($matches[1]) ? $matches[1] : '';
2966 - ?>
2967 - <a href="<?php echo esc_url(admin_url('admin.php?page=mxchat-forms&action=edit&form_id=' . $form_id)); ?>"
2968 - class="mxchat-button-secondary">
2969 - <?php esc_html_e('Manage in Forms', 'mxchat'); ?>
2970 - </a>
2971 - <?php endif; ?>
2972 - </td>
2973 - </tr>
2974 - <?php endforeach;
2975 - else : ?>
2497 + <tbody>
2498 + <?php if ($intents) :
2499 + foreach ($intents as $intent) :
2500 + $callback_function = $intent->callback_function;
2501 + $callback_label = isset($available_callbacks[$callback_function]['label'])
2502 + ? $available_callbacks[$callback_function]['label']
2503 + : $callback_function;
2504 + $threshold_value = isset($intent->similarity_threshold)
2505 + ? round($intent->similarity_threshold * 100)
2506 + : 85;
2507 + ?>
2976 2508 <tr>
2977 - <td colspan="5" class="mxchat-no-records">
2978 - <?php esc_html_e('No intents found.', 'mxchat'); ?>
2509 + <td><?php echo esc_html($intent->intent_label); ?></td>
2510 + <td class="mxchat-content-cell">
2511 + <?php echo esc_html($intent->phrases); ?>
2979 2512 </td>
2513 + <td><?php echo esc_html($callback_label); ?></td>
2514 + <td>
2515 + <form method="post"
2516 + action="<?php echo esc_url(admin_url('admin-post.php')); ?>"
2517 + class="mxchat-threshold-form">
2518 + <?php wp_nonce_field('mxchat_update_intent_threshold_nonce'); ?>
2519 + <input type="hidden" name="action"
2520 + value="mxchat_update_intent_threshold">
2521 + <input type="hidden" name="intent_id"
2522 + value="<?php echo esc_attr($intent->id); ?>">
2523 + <div class="mxchat-slider-group">
2524 + <input type="range"
2525 + name="intent_threshold"
2526 + id="intent_threshold_<?php echo esc_attr($intent->id); ?>"
2527 + min="70"
2528 + max="95"
2529 + value="<?php echo esc_attr($threshold_value); ?>"
2530 + class="mxchat-intent-slider"
2531 + oninput="document.getElementById('threshold_output_<?php echo esc_attr($intent->id); ?>').value = this.value + '%'">
2532 + <output id="threshold_output_<?php echo esc_attr($intent->id); ?>"
2533 + class="mxchat-intent-output">
2534 + <?php echo esc_html($threshold_value); ?>%
2535 + </output>
2536 + </div>
2537 + <button type="submit" class="mxchat-button-icon">
2538 + <span class="dashicons dashicons-saved"></span>
2539 + </button>
2540 + </form>
2541 + </td>
2542 + <td class="mxchat-actions-cell">
2543 + <button type="button"
2544 + class="mxchat-button-icon mxchat-edit-button"
2545 + data-intent-id="<?php echo esc_attr($intent->id); ?>"
2546 + data-phrases="<?php echo esc_attr($intent->phrases); ?>">
2547 + <span class="dashicons dashicons-edit"></span>
2548 + </button>
2549 + <form method="post"
2550 + action="<?php echo esc_url(admin_url('admin-post.php')); ?>"
2551 + class="mxchat-delete-form"
2552 + onsubmit="return confirm('<?php esc_attr_e('Are you sure you want to delete this intent?', 'mxchat'); ?>');">
2553 + <?php wp_nonce_field('mxchat_delete_intent_nonce'); ?>
2554 + <input type="hidden" name="action" value="mxchat_delete_intent">
2555 + <input type="hidden" name="intent_id"
2556 + value="<?php echo esc_attr($intent->id); ?>">
2557 + <button type="submit" class="mxchat-button-icon">
2558 + <span class="dashicons dashicons-trash"></span>
2559 + </button>
2560 + </form>
2561 + </td>
2980 2562 </tr>
2981 - <?php endif; ?>
2982 - </tbody>
2563 + <?php endforeach;
2564 + else : ?>
2565 + <tr>
2566 + <td colspan="5" class="mxchat-no-records">
2567 + <?php esc_html_e('No intents found.', 'mxchat'); ?>
2568 + </td>
2569 + </tr>
2570 + <?php endif; ?>
2571 + </tbody>
2983 2572 </table>
2984 2573 </div>
2985 2574
2986 2575 <?php if ($total_pages > 1) : ?>
@@ -3242,8 +2831,18 @@
3242 2831 'label' => __('Email Capture', 'mxchat'),
3243 2832 'pro_only' => false,
3244 2833 'group' => __('Customer Engagement', 'mxchat'),
3245 2834 ],
2835 + 'mxchat_handle_product_inquiry' => [
2836 + 'label' => __('Show Product Card', 'mxchat'),
2837 + 'pro_only' => true,
2838 + 'group' => __('WooCommerce Features', 'mxchat'),
2839 + ],
2840 + 'mxchat_handle_order_history' => [
2841 + 'label' => __('Order History', 'mxchat'),
2842 + 'pro_only' => true,
2843 + 'group' => __('WooCommerce Features', 'mxchat'),
2844 + ],
3246 2845 'mxchat_generate_image' => [
3247 2846 'label' => __('Generate Image', 'mxchat'),
3248 2847 'pro_only' => true,
3249 2848 'group' => __('Other Features', 'mxchat'),
@@ -3257,13 +2856,28 @@
3257 2856 'label' => __('Brave Image Search', 'mxchat'),
3258 2857 'pro_only' => false,
3259 2858 'group' => __('Search Features', 'mxchat'),
3260 2859 ],
2860 + 'mxchat_handle_add_to_cart_intent' => [
2861 + 'label' => __('Add to Cart', 'mxchat'),
2862 + 'pro_only' => true,
2863 + 'group' => __('WooCommerce Features', 'mxchat'),
2864 + ],
2865 + 'mxchat_handle_checkout_intent' => [
2866 + 'label' => __('Proceed to Checkout', 'mxchat'),
2867 + 'pro_only' => true,
2868 + 'group' => __('WooCommerce Features', 'mxchat'),
2869 + ],
3261 2870 'mxchat_handle_pdf_discussion' => [
3262 2871 'label' => __('Chat with PDF', 'mxchat'),
3263 2872 'pro_only' => true,
3264 2873 'group' => __('Other Features', 'mxchat'),
3265 2874 ],
2875 + 'mxchat_handle_product_recommendations' => [
2876 + 'label' => __('Product Recommendations', 'mxchat'),
2877 + 'pro_only' => true,
2878 + 'group' => __('WooCommerce Features', 'mxchat'),
2879 + ],
3266 2880 'mxchat_live_agent_handover' => [
3267 2881 'label' => __('Live Agent', 'mxchat'),
3268 2882 'pro_only' => true,
3269 2883 'group' => __('Customer Engagement', 'mxchat'),
@@ -3274,11 +2888,8 @@
3274 2888 'group' => __('Customer Engagement', 'mxchat'),
3275 2889 ],
3276 2890 ];
3277 2891
3278 - // Allow other plugins to add their callbacks
3279 - $callbacks = apply_filters('mxchat_available_callbacks', $callbacks);
3280 -
3281 2892 // Return grouped structure if requested
3282 2893 if ($grouped) {
3283 2894 $grouped_callbacks = [];
3284 2895 foreach ($callbacks as $key => $data) {
@@ -3289,12 +2900,14 @@
3289 2900 ];
3290 2901 }
3291 2902 return $grouped_callbacks;
3292 2903 }
2904 +
3293 2905 return $callbacks;
3294 2906 }
3295 2907
3296 2908
2909 +
3297 2910 private function mxchat_average_vectors($vectors) {
3298 2911 $vector_length = count($vectors[0]);
3299 2912 $sum_vector = array_fill(0, $vector_length, 0);
3300 2913
@@ -3412,44 +3025,25 @@
3412 3025 'mxchat-chatbot',
3413 3026 'mxchat_chatbot_section'
3414 3027 );
3415 3028
3416 - add_settings_field(
3417 - 'voyage_api_key',
3418 - esc_html__('Voyage AI API Key', 'mxchat'),
3419 - array($this, 'voyage_api_key_callback'),
3420 - 'mxchat-chatbot',
3421 - 'mxchat_chatbot_section'
3422 - );
3423 -
3424 -
3425 3029 add_settings_field(
3426 - 'model',
3427 - esc_html__('Chat Model', 'mxchat'),
3428 - array($this, 'mxchat_model_callback'),
3030 + 'system_prompt_instructions',
3031 + esc_html__('AI Instructions (Behavior)', 'mxchat'),
3032 + array($this, 'system_prompt_instructions_callback'),
3429 3033 'mxchat-chatbot',
3430 3034 'mxchat_chatbot_section'
3431 3035 );
3432 3036
3433 - // Add the settings field
3434 3037 add_settings_field(
3435 - 'embedding_model',
3436 - esc_html__('Embedding Model', 'mxchat'),
3437 - array($this, 'embedding_model_callback'),
3038 + 'model',
3039 + esc_html__('Model', 'mxchat'),
3040 + array($this, 'mxchat_model_callback'),
3438 3041 'mxchat-chatbot',
3439 3042 'mxchat_chatbot_section'
3440 3043 );
3441 3044
3442 3045 add_settings_field(
3443 - 'system_prompt_instructions',
3444 - esc_html__('AI Instructions (Behavior)', 'mxchat'),
3445 - array($this, 'system_prompt_instructions_callback'),
3446 - 'mxchat-chatbot',
3447 - 'mxchat_chatbot_section'
3448 - );
3449 -
3450 -
3451 - add_settings_field(
3452 3046 'top_bar_title',
3453 3047 esc_html__('Top Bar Title', 'mxchat'),
3454 3048 array($this, 'mxchat_top_bar_title_callback'),
3455 3049 'mxchat-chatbot',
@@ -3561,9 +3155,9 @@
3561 3155 );
3562 3156
3563 3157 add_settings_field(
3564 3158 'popular_question_1',
3565 - esc_html__('Quick Question 1', 'mxchat'),
3159 + esc_html__('Popular Question 1', 'mxchat'),
3566 3160 array($this, 'mxchat_popular_question_1_callback'),
3567 3161 'mxchat-chatbot',
3568 3162 'mxchat_chatbot_section'
3569 3163 );
@@ -3569,9 +3163,9 @@
3569 3163 );
3570 3164
3571 3165 add_settings_field(
3572 3166 'popular_question_2',
3573 - esc_html__('Quick Question 2', 'mxchat'),
3167 + esc_html__('Popular Question 2', 'mxchat'),
3574 3168 array($this, 'mxchat_popular_question_2_callback'),
3575 3169 'mxchat-chatbot',
3576 3170 'mxchat_chatbot_section'
3577 3171 );
@@ -3577,9 +3171,9 @@
3577 3171 );
3578 3172
3579 3173 add_settings_field(
3580 3174 'popular_question_3',
3581 - esc_html__('Quick Question 3', 'mxchat'),
3175 + esc_html__('Popular Question 3', 'mxchat'),
3582 3176 array($this, 'mxchat_popular_question_3_callback'),
3583 3177 'mxchat-chatbot',
3584 3178 'mxchat_chatbot_section'
3585 3179 );
@@ -3585,14 +3179,21 @@
3585 3179 );
3586 3180
3587 3181 add_settings_field(
3588 3182 'additional_popular_questions',
3589 - esc_html__('Additional Quick Questions', 'mxchat'),
3183 + esc_html__('Additional Popular Questions', 'mxchat'),
3590 3184 array($this, 'mxchat_additional_popular_questions_callback'),
3591 3185 'mxchat-chatbot',
3592 3186 'mxchat_chatbot_section'
3593 3187 );
3594 3188
3189 + // WooCommerce Settings Section
3190 + add_settings_section(
3191 + 'mxchat_woocommerce_section',
3192 + esc_html__('WooCommerce Settings', 'mxchat'),
3193 + null,
3194 + 'mxchat-embed'
3195 + );
3595 3196
3596 3197 // Loops Settings Section
3597 3198 add_settings_section(
3598 3199 'mxchat_loops_section',
@@ -3600,8 +3201,33 @@
3600 3201 null,
3601 3202 'mxchat-embed'
3602 3203 );
3603 3204
3205 + // WooCommerce Settings Fields
3206 + add_settings_field(
3207 + 'enable_woocommerce_integration',
3208 + esc_html__('Automatically Embed Products', 'mxchat'),
3209 + array($this, 'mxchat_enable_woocommerce_integration_callback'),
3210 + 'mxchat-embed',
3211 + 'mxchat_woocommerce_section'
3212 + );
3213 +
3214 + add_settings_field(
3215 + 'woocommerce_consumer_key',
3216 + esc_html__('WooCommerce Consumer Key', 'mxchat'),
3217 + array($this, 'mxchat_woocommerce_consumer_key_callback'),
3218 + 'mxchat-embed',
3219 + 'mxchat_woocommerce_section'
3220 + );
3221 +
3222 + add_settings_field(
3223 + 'woocommerce_consumer_secret',
3224 + esc_html__('WooCommerce Consumer Secret', 'mxchat'),
3225 + array($this, 'mxchat_woocommerce_consumer_secret_callback'),
3226 + 'mxchat-embed',
3227 + 'mxchat_woocommerce_section'
3228 + );
3229 +
3604 3230 // Loops Settings Fields
3605 3231 add_settings_field(
3606 3232 'loops_api_key',
3607 3233 esc_html__('Loops API Key', 'mxchat'),
@@ -3796,11 +3422,162 @@
3796 3422 'mxchat-embed',
3797 3423 'mxchat_live_agent_section'
3798 3424 );
3799 3425
3426 + // Theme Settings Section
3427 + add_settings_section(
3428 + 'mxchat_theme_section',
3429 + esc_html__('Theme Settings', 'mxchat'),
3430 + null,
3431 + 'mxchat-theme'
3432 + );
3800 3433
3434 + add_settings_field(
3435 + 'close_button_color',
3436 + esc_html__('Close Button & Title Color', 'mxchat'),
3437 + array($this, 'mxchat_close_button_color_callback'),
3438 + 'mxchat-theme',
3439 + 'mxchat_theme_section'
3440 + );
3801 3441
3442 + add_settings_field(
3443 + 'chatbot_bg_color',
3444 + esc_html__('Chatbot Background Color', 'mxchat'),
3445 + array($this, 'mxchat_chatbot_bg_color_callback'),
3446 + 'mxchat-theme',
3447 + 'mxchat_theme_section'
3448 + );
3802 3449
3450 + add_settings_field(
3451 + 'user_message_bg_color',
3452 + esc_html__('User Message Background Color', 'mxchat'),
3453 + array($this, 'mxchat_user_message_bg_color_callback'),
3454 + 'mxchat-theme',
3455 + 'mxchat_theme_section'
3456 + );
3457 +
3458 + add_settings_field(
3459 + 'user_message_font_color',
3460 + esc_html__('User Message Font Color', 'mxchat'),
3461 + array($this, 'mxchat_user_message_font_color_callback'),
3462 + 'mxchat-theme',
3463 + 'mxchat_theme_section'
3464 + );
3465 +
3466 + add_settings_field(
3467 + 'bot_message_bg_color',
3468 + esc_html__('Bot Message Background Color', 'mxchat'),
3469 + array($this, 'mxchat_bot_message_bg_color_callback'),
3470 + 'mxchat-theme',
3471 + 'mxchat_theme_section'
3472 + );
3473 +
3474 + add_settings_field(
3475 + 'bot_message_font_color',
3476 + esc_html__('Bot Message Font Color', 'mxchat'),
3477 + array($this, 'mxchat_bot_message_font_color_callback'),
3478 + 'mxchat-theme',
3479 + 'mxchat_theme_section'
3480 + );
3481 +
3482 + add_settings_field(
3483 + 'top_bar_bg_color',
3484 + esc_html__('Top Bar Background Color', 'mxchat'),
3485 + array($this, 'mxchat_top_bar_bg_color_callback'),
3486 + 'mxchat-theme',
3487 + 'mxchat_theme_section'
3488 + );
3489 +
3490 + add_settings_field(
3491 + 'send_button_font_color',
3492 + esc_html__('Send Button Color', 'mxchat'),
3493 + array($this, 'mxchat_send_button_font_color_callback'),
3494 + 'mxchat-theme',
3495 + 'mxchat_theme_section'
3496 + );
3497 +
3498 + add_settings_field(
3499 + 'chat_input_font_color',
3500 + esc_html__('Chat Input Font Color', 'mxchat'),
3501 + array($this, 'mxchat_chat_input_font_color_callback'),
3502 + 'mxchat-theme',
3503 + 'mxchat_theme_section'
3504 + );
3505 +
3506 + add_settings_field(
3507 + 'chatbot_background_color',
3508 + esc_html__('Floating Widget Background Color', 'mxchat'),
3509 + array($this, 'mxchat_chatbot_background_color_callback'),
3510 + 'mxchat-theme',
3511 + 'mxchat_theme_section'
3512 + );
3513 +
3514 + add_settings_field(
3515 + 'icon_color',
3516 + esc_html__('Chatbot Icon Color', 'mxchat'),
3517 + array($this, 'mxchat_icon_color_callback'),
3518 + 'mxchat-theme',
3519 + 'mxchat_theme_section'
3520 + );
3521 +
3522 + add_settings_field(
3523 + 'custom_icon',
3524 + esc_html__('Custom Chatbot Icon (PNG)', 'mxchat'),
3525 + array($this, 'mxchat_custom_icon_callback'),
3526 + 'mxchat-theme',
3527 + 'mxchat_theme_section'
3528 + );
3529 +
3530 + add_settings_field(
3531 + 'title_icon',
3532 + esc_html__('Title Bar Icon (PNG)', 'mxchat'),
3533 + array($this, 'mxchat_title_icon_callback'),
3534 + 'mxchat-theme',
3535 + 'mxchat_theme_section'
3536 + );
3537 +
3538 + add_settings_field(
3539 + 'live_agent_message_bg_color',
3540 + esc_html__('Live Agent Background Color', 'mxchat'),
3541 + array($this, 'mxchat_live_agent_message_bg_color_callback'),
3542 + 'mxchat-theme',
3543 + 'mxchat_theme_section'
3544 + );
3545 +
3546 + add_settings_field(
3547 + 'live_agent_message_font_color',
3548 + esc_html__('Live Agent Font Color', 'mxchat'),
3549 + array($this, 'mxchat_live_agent_message_font_color_callback'),
3550 + 'mxchat-theme',
3551 + 'mxchat_theme_section'
3552 + );
3553 +
3554 + // Mode Indicator Background Color
3555 + add_settings_field(
3556 + 'mode_indicator_bg_color',
3557 + esc_html__('Mode Indicator Background Color', 'mxchat'),
3558 + array($this, 'mxchat_mode_indicator_bg_color_callback'),
3559 + 'mxchat-theme',
3560 + 'mxchat_theme_section'
3561 + );
3562 +
3563 + // Mode Indicator Font Color
3564 + add_settings_field(
3565 + 'mode_indicator_font_color',
3566 + esc_html__('Mode Indicator Font Color', 'mxchat'),
3567 + array($this, 'mxchat_mode_indicator_font_color_callback'),
3568 + 'mxchat-theme',
3569 + 'mxchat_theme_section'
3570 + );
3571 +
3572 + add_settings_field(
3573 + 'toolbar_icon_color',
3574 + esc_html__('Toolbar Icon Color', 'mxchat'),
3575 + array($this, 'mxchat_toolbar_icon_color_callback'),
3576 + 'mxchat-theme',
3577 + 'mxchat_theme_section'
3578 + );
3579 +
3803 3580 // General Settings Section
3804 3581 add_settings_section(
3805 3582 'mxchat_general_section',
3806 3583 esc_html__('Frequently Asked Questions (FAQ)', 'mxchat'),
@@ -4047,8 +3824,52 @@
4047 3824 echo '</div>';
4048 3825 }
4049 3826
4050 3827
3828 +public function mxchat_enable_woocommerce_integration_callback() {
3829 + // Load from mxchat_options array
3830 + $options = get_option('mxchat_options', []);
3831 +
3832 + // Get WooCommerce integration status with backwards compatibility
3833 + $woo_integration = isset($options['enable_woocommerce_integration'])
3834 + ? $options['enable_woocommerce_integration']
3835 + : '';
3836 +
3837 + // Support both old ('1') and new ('on') values
3838 + $checked = ($woo_integration === 'on' || $woo_integration === '1') ? 'checked' : '';
3839 +
3840 + // Check if the feature is activated (paid feature)
3841 + $disabled = $this->is_activated ? '' : 'disabled';
3842 + $class = $this->is_activated ? 'pro-feature-wrapper active' : 'pro-feature-wrapper inactive';
3843 +
3844 + echo '<div class="' . esc_attr($class) . '">';
3845 +
3846 + echo '<label class="toggle-switch">';
3847 + echo sprintf(
3848 + '<input type="checkbox" id="enable_woocommerce_integration" name="enable_woocommerce_integration" value="on" %s %s />',
3849 + esc_attr($checked),
3850 + esc_attr($disabled)
3851 + );
3852 + echo '<span class="slider"></span>';
3853 + echo '</label>';
3854 +
3855 + echo '<p class="description">' . esc_html__('Automatically syncs new product additions, updates, and removals to the knowledge base. For existing products, submit your product sitemap in the Knowledge Base section to add them initially.', 'mxchat') . '</p>';
3856 +
3857 + // Pro feature overlay for non-activated users
3858 + if (!$this->is_activated) {
3859 + echo '<div class="pro-feature-overlay">';
3860 + echo '<a href="https://mxchat.ai/" target="_blank">';
3861 + echo '<img src="' . esc_url(plugin_dir_url(__FILE__) . '../images/pro-only-dark.png') . '" alt="' . esc_attr__('Pro Only', 'mxchat') . '" />';
3862 + echo '</a>';
3863 + echo '</div>';
3864 + }
3865 +
3866 + echo '</div>';
3867 +}
3868 +
3869 +
3870 +
3871 +
4051 3872 private function mxchat_add_option_field($id, $title, $callback = '') {
4052 3873 add_settings_field(
4053 3874 $id,
4054 3875 __($title, 'mxchat'),
@@ -4065,8 +3886,9 @@
4065 3886
4066 3887 // Notice we changed the name to "api_key" (no array notation).
4067 3888 echo '<input type="password" id="api_key" name="api_key" value="' . $apiKey . '" class="regular-text" />';
4068 3889 echo '<button type="button" id="toggleApiKeyVisibility">' . esc_html__('Show', 'mxchat') . '</button>';
3890 + echo '<p class="description">' . esc_html__('The OpenAI API key is required even when using other models as it is used for vector embedding functionality. You must add credits to your OpenAI billing account before use.', 'mxchat') . '</p>';
4069 3891 }
4070 3892 public function xai_api_key_callback() {
4071 3893 // Check if the feature is activated (paid feature)
4072 3894 $disabled = $this->is_activated ? '' : 'disabled'; // Disable input if not activated
@@ -4094,15 +3916,15 @@
4094 3916 echo '</div>';
4095 3917 }
4096 3918 public function claude_api_key_callback() {
4097 3919 // Check if the feature is activated (paid feature)
4098 - $disabled = $this->is_activated ? '' : 'disabled';
4099 - $class = $this->is_activated ? 'pro-feature-wrapper active' : 'pro-feature-wrapper inactive';
3920 + $disabled = $this->is_activated ? '' : 'disabled'; // Disable input if not activated
3921 + $class = $this->is_activated ? 'pro-feature-wrapper active' : 'pro-feature-wrapper inactive'; // CSS class to style the wrapper based on activation status
4100 3922
4101 - // Retrieve the Claude API key value directly like the others
3923 + // Retrieve the Claude API key value
4102 3924 $claudeApiKey = isset($this->options['claude_api_key']) ? esc_attr($this->options['claude_api_key']) : '';
4103 3925
4104 - // Use direct name field like the other working API keys
3926 + // Render the input field for the Claude API key
4105 3927 echo '<div class="' . esc_attr($class) . '">';
4106 3928 printf(
4107 3929 '<input type="password" id="claude_api_key" name="claude_api_key" value="%s" class="regular-text" %s />',
4108 3930 $claudeApiKey,
@@ -4109,13 +3931,15 @@
4109 3931 $disabled
4110 3932 );
4111 3933 echo '<button type="button" id="toggleClaudeApiKeyVisibility">' . esc_html__('Show', 'mxchat') . '</button>';
4112 3934
3935 + // If the feature is not activated, show the overlay with a "Pro Only" message
4113 3936 if (!$this->is_activated) {
4114 3937 echo '<div class="pro-feature-overlay">';
4115 3938 echo '<a href="https://mxchat.ai/" target="_blank"><img src="' . plugin_dir_url(__FILE__) . '../images/pro-only-dark.png" alt="' . esc_attr__('Pro Only', 'mxchat') . '" /></a>';
4116 3939 echo '</div>';
4117 3940 }
3941 +
4118 3942 echo '</div>';
4119 3943 }
4120 3944 public function deepseek_api_key_callback() {
4121 3945 // Retrieve from your stored 'deepseek_api_key' in the mxchat_options array
@@ -4126,11 +3950,79 @@
4126 3950 echo '<button type="button" id="toggleDeepSeekApiKeyVisibility">' . esc_html__('Show', 'mxchat') . '</button>';
4127 3951 }
4128 3952
4129 3953
3954 +public function mxchat_woocommerce_consumer_key_callback() {
3955 + // Load the entire 'mxchat_options' array
3956 + $all_options = get_option('mxchat_options', []);
4130 3957
3958 + // Retrieve the WooCommerce consumer key or set a default
3959 + $consumer_key = isset($all_options['woocommerce_consumer_key']) ? $all_options['woocommerce_consumer_key'] : '';
4131 3960
3961 + // Check if the feature is activated (paid feature)
3962 + $disabled = $this->is_activated ? '' : 'disabled';
3963 + $class = $this->is_activated ? 'pro-feature-wrapper active' : 'pro-feature-wrapper inactive';
4132 3964
3965 + echo '<div class="' . esc_attr($class) . '">';
3966 +
3967 + // Render the input field
3968 + printf(
3969 + '<input type="text" id="woocommerce_consumer_key" name="woocommerce_consumer_key" value="%s" class="regular-text" %s />',
3970 + esc_attr($consumer_key),
3971 + esc_attr($disabled)
3972 + );
3973 +
3974 + // Description for the input field
3975 + echo '<p class="description">' . esc_html__('Enter your WooCommerce consumer key for integration.', 'mxchat') . '</p>';
3976 +
3977 + // Pro feature overlay for non-activated users
3978 + if (!$this->is_activated) {
3979 + echo '<div class="pro-feature-overlay">';
3980 + echo '<a href="https://mxchat.ai/" target="_blank"><img src="' . plugin_dir_url(__FILE__) . '../images/pro-only-dark.png" alt="' . esc_attr__('Pro Only', 'mxchat') . '" /></a>';
3981 + echo '</div>';
3982 + }
3983 +
3984 + echo '</div>';
3985 +}
3986 +
3987 +public function mxchat_woocommerce_consumer_secret_callback() {
3988 + // Get value with fallback
3989 + $consumer_secret = isset($this->options['woocommerce_consumer_secret'])
3990 + ? esc_attr($this->options['woocommerce_consumer_secret'])
3991 + : '';
3992 +
3993 + // Check if the feature is activated (paid feature)
3994 + $disabled = $this->is_activated ? '' : 'disabled';
3995 + $class = $this->is_activated ? 'pro-feature-wrapper active' : 'pro-feature-wrapper inactive';
3996 +
3997 + echo '<div class="' . esc_attr($class) . '">';
3998 +
3999 + // Output the password input
4000 + echo sprintf(
4001 + '<input type="password"
4002 + id="woocommerce_consumer_secret"
4003 + name="woocommerce_consumer_secret"
4004 + value="%s"
4005 + class="regular-text"
4006 + %s />',
4007 + $consumer_secret,
4008 + esc_attr($disabled)
4009 + );
4010 +
4011 + // Add show/hide button
4012 + echo '<button type="button" id="toggleWooCommerceSecretVisibility">' . esc_html__('Show', 'mxchat') . '</button>';
4013 +
4014 + // Pro feature overlay
4015 + if (!$this->is_activated) {
4016 + echo '<div class="pro-feature-overlay">';
4017 + echo '<a href="https://mxchat.ai/" target="_blank">';
4018 + echo '<img src="' . esc_url(plugin_dir_url(__FILE__) . '../images/pro-only-dark.png') . '" alt="' . esc_attr__('Pro Only', 'mxchat') . '" />';
4019 + echo '</a>';
4020 + echo '</div>';
4021 + }
4022 +
4023 + echo '</div>';
4024 +}
4133 4025 public function mxchat_loops_api_key_callback() {
4134 4026 // Support both old and new format
4135 4027 $loops_api_key = isset($this->options['loops_api_key']) ? esc_attr($this->options['loops_api_key']) : '';
4136 4028
@@ -4291,46 +4183,13 @@
4291 4183 // Close the select dropdown
4292 4184 echo '</select>';
4293 4185
4294 4186 // Add a description below the dropdown
4295 - echo '<p class="description">' . esc_html__('Select the AI model your chatbot will use for chatting. Pro-only models are marked accordingly.', 'mxchat') . '</p>';
4187 + echo '<p class="description">' . esc_html__('Select the AI model to use for your chatbot. Pro-only models are marked accordingly.', 'mxchat') . '</p>';
4296 4188 }
4297 4189
4298 -public function voyage_api_key_callback() {
4299 - $apiKey = isset($this->options['voyage_api_key']) ? esc_attr($this->options['voyage_api_key']) : '';
4300 - echo '<input type="password" id="voyage_api_key" name="voyage_api_key" value="' . $apiKey . '" class="regular-text" />';
4301 - echo '<button type="button" id="toggleVoyageAPIKeyVisibility">' . esc_html__('Show', 'mxchat') . '</button>';
4302 -}
4303 4190
4304 -// Callback function for embedding model selection
4305 -public function embedding_model_callback() {
4306 - $models = array(
4307 - esc_html__('OpenAI Embeddings', 'mxchat') => array(
4308 - 'text-embedding-3-small' => esc_html__('TE3 Small (1536, Efficient)', 'mxchat'),
4309 - 'text-embedding-ada-002' => esc_html__('Ada 2 (1536, Original)', 'mxchat'),
4310 - 'text-embedding-3-large' => esc_html__('TE3 Large (3072, Powerful)', 'mxchat'),
4311 - ),
4312 - esc_html__('Voyage AI Embeddings', 'mxchat') => array(
4313 - 'voyage-3-large' => esc_html__('Voyage-3 Large (2048, Most Capable)', 'mxchat'),
4314 - )
4315 - );
4316 4191
4317 - $selected_model = isset($this->options['embedding_model']) ? esc_attr($this->options['embedding_model']) : 'text-embedding-ada-002';
4318 -
4319 - echo '<select id="embedding_model" name="embedding_model">';
4320 - foreach ($models as $group_label => $group_models) {
4321 - echo '<optgroup label="' . esc_attr($group_label) . '">';
4322 - foreach ($group_models as $model_value => $model_label) {
4323 - echo '<option value="' . esc_attr($model_value) . '" ' . selected($selected_model, $model_value, false) . '>' . esc_html($model_label) . '</option>';
4324 - }
4325 - echo '</optgroup>';
4326 - }
4327 - echo '</select>';
4328 -echo '<p class="description"><span class="red-warning">IMPORTANT:</span> Select the model for vector embeddings. Changing models is not recommended; if you do, you must delete all existing knowledge & intent data and reconfigure them.</p>';
4329 -
4330 -}
4331 -
4332 -
4333 4192 public function mxchat_top_bar_title_callback() {
4334 4193 // Retrieve the current value of the top bar title from saved options
4335 4194 $top_bar_title = isset($this->options['top_bar_title']) ? esc_attr($this->options['top_bar_title']) : '';
4336 4195
@@ -4443,8 +4302,91 @@
4443 4302 }
4444 4303
4445 4304
4446 4305
4306 +
4307 +
4308 +public function mxchat_close_button_color_callback() {
4309 + $disabled = $this->is_activated ? '' : 'disabled';
4310 + $class = $this->is_activated ? 'pro-feature-wrapper active' : 'pro-feature-wrapper inactive';
4311 +
4312 + echo '<div class="' . esc_attr($class) . '">';
4313 + echo sprintf(
4314 + '<input type="text"
4315 + id="close_button_color"
4316 + name="close_button_color"
4317 + value="%s"
4318 + class="my-color-field"
4319 + data-default-color="#4a4a4a"
4320 + %s />',
4321 + isset($this->options['close_button_color']) ? esc_attr($this->options['close_button_color']) : '#4a4a4a',
4322 + esc_attr($disabled)
4323 + );
4324 +
4325 + if (!$this->is_activated) {
4326 + echo '<div class="pro-feature-overlay">';
4327 + echo '<a href="https://mxchat.ai/" target="_blank">';
4328 + echo '<img src="' . esc_url(plugin_dir_url(__FILE__) . '../images/pro-only-dark.png') . '" alt="' . esc_attr__('Pro Only', 'mxchat') . '" />';
4329 + echo '</a>';
4330 + echo '</div>';
4331 + }
4332 + echo '</div>';
4333 +}
4334 +
4335 +public function mxchat_chatbot_bg_color_callback() {
4336 + $disabled = $this->is_activated ? '' : 'disabled';
4337 + $class = $this->is_activated ? 'pro-feature-wrapper active' : 'pro-feature-wrapper inactive';
4338 +
4339 + echo '<div class="' . esc_attr($class) . '">';
4340 + echo sprintf(
4341 + '<input type="text"
4342 + id="chatbot_bg_color"
4343 + name="chatbot_bg_color"
4344 + value="%s"
4345 + class="my-color-field"
4346 + data-default-color="#f9f9f9"
4347 + %s />',
4348 + isset($this->options['chatbot_bg_color']) ? esc_attr($this->options['chatbot_bg_color']) : '#f9f9f9',
4349 + esc_attr($disabled)
4350 + );
4351 +
4352 + if (!$this->is_activated) {
4353 + echo '<div class="pro-feature-overlay">';
4354 + echo '<a href="https://mxchat.ai/" target="_blank">';
4355 + echo '<img src="' . esc_url(plugin_dir_url(__FILE__) . '../images/pro-only-dark.png') . '" alt="' . esc_attr__('Pro Only', 'mxchat') . '" />';
4356 + echo '</a>';
4357 + echo '</div>';
4358 + }
4359 + echo '</div>';
4360 +}
4361 +
4362 +public function mxchat_user_message_bg_color_callback() {
4363 + $disabled = $this->is_activated ? '' : 'disabled';
4364 + $class = $this->is_activated ? 'pro-feature-wrapper active' : 'pro-feature-wrapper inactive';
4365 +
4366 + echo '<div class="' . esc_attr($class) . '">';
4367 + echo sprintf(
4368 + '<input type="text"
4369 + id="user_message_bg_color"
4370 + name="user_message_bg_color"
4371 + value="%s"
4372 + class="my-color-field"
4373 + data-default-color="#0078d7"
4374 + %s />',
4375 + isset($this->options['user_message_bg_color']) ? esc_attr($this->options['user_message_bg_color']) : '#0078d7',
4376 + esc_attr($disabled)
4377 + );
4378 +
4379 + if (!$this->is_activated) {
4380 + echo '<div class="pro-feature-overlay">';
4381 + echo '<a href="https://mxchat.ai/" target="_blank">';
4382 + echo '<img src="' . esc_url(plugin_dir_url(__FILE__) . '../images/pro-only-dark.png') . '" alt="' . esc_attr__('Pro Only', 'mxchat') . '" />';
4383 + echo '</a>';
4384 + echo '</div>';
4385 + }
4386 + echo '</div>';
4387 +}
4388 +
4447 4389 public function mxchat_user_message_font_color_callback() {
4448 4390 $disabled = $this->is_activated ? '' : 'disabled';
4449 4391 $class = $this->is_activated ? 'pro-feature-wrapper active' : 'pro-feature-wrapper inactive';
4450 4392
@@ -4931,20 +4873,39 @@
4931 4873 // Get complianz toggle value with fallback
4932 4874 $complianz_toggle = isset($options['complianz_toggle']) ? $options['complianz_toggle'] : 'off';
4933 4875 $checked = ($complianz_toggle === 'on') ? 'checked' : '';
4934 4876
4877 + // Check if the plugin is activated (paid feature)
4878 + $disabled = $this->is_activated ? '' : 'disabled';
4879 + $class = $this->is_activated ? 'pro-feature-wrapper active' : 'pro-feature-wrapper inactive';
4880 +
4881 + echo '<div class="' . esc_attr($class) . '">';
4882 +
4935 4883 // Output the toggle switch
4936 4884 echo '<label class="toggle-switch">';
4937 4885 echo sprintf(
4938 - '<input type="checkbox" id="complianz_toggle" name="complianz_toggle" value="on" %s />',
4939 - esc_attr($checked)
4886 + '<input type="checkbox" id="complianz_toggle" name="complianz_toggle" value="on" %s %s />',
4887 + esc_attr($checked),
4888 + esc_attr($disabled)
4940 4889 );
4941 4890 echo '<span class="slider"></span>';
4942 4891 echo '</label>';
4943 4892
4944 4893 echo '<p class="description">' . esc_html__('Enable this option to apply Complianz consent logic to the chatbot (must have Complianz Plugin).', 'mxchat') . '</p>';
4894 +
4895 + // If the feature is not activated, show the Pro feature overlay
4896 + if (!$this->is_activated) {
4897 + echo '<div class="pro-feature-overlay">';
4898 + echo '<a href="https://mxchat.ai/" target="_blank">';
4899 + echo '<img src="' . esc_url(plugin_dir_url(__FILE__) . '../images/pro-only-dark.png') . '" alt="' . esc_attr__('Pro Only', 'mxchat') . '" />';
4900 + echo '</a>';
4901 + echo '</div>';
4902 + }
4903 +
4904 + echo '</div>';
4945 4905 }
4946 4906
4907 +
4947 4908 public function mxchat_link_target_toggle_callback() {
4948 4909 // Load from mxchat_options array
4949 4910 $options = get_option('mxchat_options', []);
4950 4911
@@ -4970,20 +4931,39 @@
4970 4931 // Get chat persistence toggle value with fallback
4971 4932 $chat_persistence_toggle = isset($options['chat_persistence_toggle']) ? $options['chat_persistence_toggle'] : 'off';
4972 4933 $checked = ($chat_persistence_toggle === 'on') ? 'checked' : '';
4973 4934
4935 + // Check if the plugin is activated (paid feature)
4936 + $disabled = $this->is_activated ? '' : 'disabled';
4937 + $class = $this->is_activated ? 'pro-feature-wrapper active' : 'pro-feature-wrapper inactive';
4938 +
4939 + echo '<div class="' . esc_attr($class) . '">';
4940 +
4974 4941 // Output the toggle switch
4975 4942 echo '<label class="toggle-switch">';
4976 4943 echo sprintf(
4977 - '<input type="checkbox" id="chat_persistence_toggle" name="chat_persistence_toggle" value="on" %s />',
4978 - esc_attr($checked)
4944 + '<input type="checkbox" id="chat_persistence_toggle" name="chat_persistence_toggle" value="on" %s %s />',
4945 + esc_attr($checked),
4946 + esc_attr($disabled)
4979 4947 );
4980 4948 echo '<span class="slider"></span>';
4981 4949 echo '</label>';
4982 4950
4983 4951 echo '<p class="description">' . esc_html__('Enable to keep chat history when users navigate tabs or return to the site within 24 hours.', 'mxchat') . '</p>';
4952 +
4953 + // If not activated, show Pro feature overlay
4954 + if (!$this->is_activated) {
4955 + echo '<div class="pro-feature-overlay">';
4956 + echo '<a href="https://mxchat.ai/" target="_blank">';
4957 + echo '<img src="' . esc_url(plugin_dir_url(__FILE__) . '../images/pro-only-dark.png') . '" alt="' . esc_attr__('Pro Only', 'mxchat') . '" />';
4958 + echo '</a>';
4959 + echo '</div>';
4960 + }
4961 +
4962 + echo '</div>';
4984 4963 }
4985 4964
4965 +
4986 4966 public function mxchat_popular_question_1_callback() {
4987 4967 // Load the full plugin options array
4988 4968 $all_options = get_option('mxchat_options', []);
4989 4969
@@ -4993,13 +4973,13 @@
4993 4973 // Render the input field
4994 4974 printf(
4995 4975 '<input type="text" id="popular_question_1" name="popular_question_1" value="%s" placeholder="%s" class="regular-text" />',
4996 4976 esc_attr($popular_question_1),
4997 - esc_attr__('Enter Quick Question 1', 'mxchat')
4977 + esc_attr__('Enter Popular Question 1', 'mxchat')
4998 4978 );
4999 4979
5000 4980 // Add a description for the field
5001 - echo '<p class="description">' . esc_html__('This will be the first Quick Question in the chatbot, displayed above the input field.', 'mxchat') . '</p>';
4981 + echo '<p class="description">' . esc_html__('This will be the first popular question in the chatbot.', 'mxchat') . '</p>';
5002 4982 }
5003 4983
5004 4984
5005 4985 public function mxchat_popular_question_2_callback() {
@@ -5008,38 +4988,72 @@
5008 4988
5009 4989 // Retrieve the specific option for popular_question_2
5010 4990 $popular_question_2 = isset($all_options['popular_question_2']) ? $all_options['popular_question_2'] : '';
5011 4991
4992 + // Check if the plugin is activated (paid feature)
4993 + $disabled = $this->is_activated ? '' : 'disabled';
4994 + $class = $this->is_activated ? 'pro-feature-wrapper active' : 'pro-feature-wrapper inactive';
4995 +
4996 + echo '<div class="' . esc_attr($class) . '">';
4997 +
5012 4998 // Render the input field
5013 4999 printf(
5014 - '<input type="text" id="popular_question_2" name="popular_question_2" value="%s" placeholder="%s" class="regular-text" />',
5000 + '<input type="text" id="popular_question_2" name="popular_question_2" value="%s" placeholder="%s" class="regular-text" %s />',
5015 5001 esc_attr($popular_question_2),
5016 - esc_attr__('Enter Quick Question 2', 'mxchat')
5002 + esc_attr__('Enter Popular Question 2', 'mxchat'),
5003 + esc_attr($disabled)
5017 5004 );
5018 5005
5019 5006 // Add a description for the field
5020 - echo '<p class="description">' . esc_html__('This will be the second Quick Question in the chatbot.', 'mxchat') . '</p>';
5007 + echo '<p class="description">' . esc_html__('This will be the second popular question in the chatbot.', 'mxchat') . '</p>';
5008 +
5009 + // If not activated, show Pro feature overlay
5010 + if (!$this->is_activated) {
5011 + echo '<div class="pro-feature-overlay">';
5012 + echo '<a href="https://mxchat.ai/" target="_blank"><img src="' . plugin_dir_url(__FILE__) . '../images/pro-only-dark.png" alt="' . esc_attr__('Pro Only', 'mxchat') . '" /></a>';
5013 + echo '</div>';
5014 + }
5015 +
5016 + echo '</div>';
5021 5017 }
5022 5018
5023 5019
5020 +
5024 5021 public function mxchat_popular_question_3_callback() {
5025 - // Load the full plugin options array
5026 - $all_options = get_option('mxchat_options', []);
5022 + // Load the full plugin options array
5023 + $all_options = get_option('mxchat_options', []);
5027 5024
5028 - // Retrieve the specific option for popular_question_3
5029 - $popular_question_3 = isset($all_options['popular_question_3']) ? $all_options['popular_question_3'] : '';
5025 + // Retrieve the specific option for popular_question_3
5026 + $popular_question_3 = isset($all_options['popular_question_3']) ? $all_options['popular_question_3'] : '';
5030 5027
5031 - // Render the input field
5032 - printf(
5033 - '<input type="text" id="popular_question_3" name="popular_question_3" value="%s" placeholder="%s" class="regular-text" />',
5034 - esc_attr($popular_question_3),
5035 - esc_attr(__('Enter Quick Question 3', 'mxchat'))
5036 - );
5028 + // Check if the plugin is activated (paid feature)
5029 + $disabled = $this->is_activated ? '' : 'disabled';
5030 + $class = $this->is_activated ? 'pro-feature-wrapper active' : 'pro-feature-wrapper inactive';
5037 5031
5038 - // Add a description for the field
5039 - echo '<p class="description">' . esc_html__('This will be the third Quick Question in the chatbot.', 'mxchat') . '</p>';
5032 + echo '<div class="' . esc_attr($class) . '">';
5033 +
5034 + // Render the input field
5035 + printf(
5036 + '<input type="text" id="popular_question_3" name="popular_question_3" value="%s" placeholder="%s" class="regular-text" %s />',
5037 + esc_attr($popular_question_3),
5038 + esc_attr(__('Enter Popular Question 3', 'mxchat')),
5039 + esc_attr($disabled)
5040 + );
5041 +
5042 + // Add a description for the field
5043 + echo '<p class="description">' . esc_html__('This will be the third popular question in the chatbot.', 'mxchat') . '</p>';
5044 +
5045 + // If not activated, show Pro feature overlay
5046 + if (!$this->is_activated) {
5047 + echo '<div class="pro-feature-overlay">';
5048 + echo '<a href="https://mxchat.ai/" target="_blank"><img src="' . plugin_dir_url(__FILE__) . '../images/pro-only-dark.png" alt="' . esc_attr__('Pro Only', 'mxchat') . '" /></a>';
5049 + echo '</div>';
5050 + }
5051 +
5052 + echo '</div>';
5040 5053 }
5041 5054
5055 +
5042 5056 public function mxchat_additional_popular_questions_callback() {
5043 5057 $options = get_option('mxchat_options', []);
5044 5058 $additional_questions = isset($options['additional_popular_questions'])
5045 5059 ? $options['additional_popular_questions']
@@ -5058,9 +5072,9 @@
5058 5072 <button type="button" class="button mxchat-remove-question"
5059 5073 aria-label="%s">%s</button>
5060 5074 </div>',
5061 5075 esc_attr($question),
5062 - esc_attr(sprintf(__('Enter Additional Quick Question %d', 'mxchat'), $index + 4)),
5076 + esc_attr(sprintf(__('Enter Additional Popular Question %d', 'mxchat'), $index + 4)),
5063 5077 $index,
5064 5078 esc_attr(__('Remove question', 'mxchat')),
5065 5079 esc_html__('Remove', 'mxchat')
5066 5080 );
@@ -5075,9 +5089,9 @@
5075 5089 data-question-index="0" />
5076 5090 <button type="button" class="button mxchat-remove-question"
5077 5091 aria-label="%s">%s</button>
5078 5092 </div>',
5079 - esc_attr(__('Enter Additional Quick Question 4', 'mxchat')),
5093 + esc_attr(__('Enter Additional Popular Question 4', 'mxchat')),
5080 5094 esc_attr(__('Remove question', 'mxchat')),
5081 5095 esc_html__('Remove', 'mxchat')
5082 5096 );
5083 5097 }
@@ -5086,9 +5100,9 @@
5086 5100 '<button type="button" class="button mxchat-add-question" aria-label="%s">%s</button>',
5087 5101 esc_attr(__('Add question', 'mxchat')),
5088 5102 esc_html__('Add Question', 'mxchat')
5089 5103 );
5090 - echo '<p class="description">' . esc_html__('Add as many Quick Questions as you need.', 'mxchat') . '</p>';
5104 + echo '<p class="description">' . esc_html__('Add as many popular questions as you need.', 'mxchat') . '</p>';
5091 5105 echo '</div>';
5092 5106 }
5093 5107
5094 5108 public function mxchat_brave_api_key_callback() {
@@ -5524,9 +5538,9 @@
5524 5538 public function mxchat_enqueue_admin_assets() {
5525 5539 wp_enqueue_style('wp-color-picker');
5526 5540
5527 5541 // Get the plugin version or file modification time for cache busting
5528 - $plugin_version = '2.0.6'; // Replace this with your plugin's version
5542 + $plugin_version = '2.0.1'; // Replace this with your plugin's version
5529 5543
5530 5544 // File paths
5531 5545 $color_picker_js_path = plugin_dir_path(__FILE__) . '../js/my-color-picker.js';
5532 5546 $embedding_check_js_path = plugin_dir_path(__FILE__) . '../js/embedding-check.js';
@@ -5532,12 +5546,10 @@
5532 5546 $embedding_check_js_path = plugin_dir_path(__FILE__) . '../js/embedding-check.js';
5533 5547 $admin_css_path = plugin_dir_path(__FILE__) . '../css/admin-style.css';
5534 5548 $knowledge_css_path = plugin_dir_path(__FILE__) . '../css/knowledge-style.css';
5535 5549 $intent_css_path = plugin_dir_path(__FILE__) . '../css/intent-style.css';
5536 - $transcripts_css_path = plugin_dir_path(__FILE__) . '../css/chat-transcripts.css';
5537 5550 $transcripts_js_path = plugin_dir_path(__FILE__) . '../js/mxchat_transcripts.js';
5538 5551
5539 -
5540 5552 // Check if files exist and get modification times
5541 5553 $color_picker_version = file_exists($color_picker_js_path) ? filemtime($color_picker_js_path) : $plugin_version;
5542 5554 $embedding_check_version = file_exists($embedding_check_js_path) ? filemtime($embedding_check_js_path) : $plugin_version;
5543 5555 $admin_css_version = file_exists($admin_css_path) ? filemtime($admin_css_path) : $plugin_version;
@@ -5542,12 +5554,10 @@
5542 5554 $embedding_check_version = file_exists($embedding_check_js_path) ? filemtime($embedding_check_js_path) : $plugin_version;
5543 5555 $admin_css_version = file_exists($admin_css_path) ? filemtime($admin_css_path) : $plugin_version;
5544 5556 $knowledge_css_version = file_exists($knowledge_css_path) ? filemtime($knowledge_css_path) : $plugin_version;
5545 5557 $intent_css_version = file_exists($intent_css_path) ? filemtime($intent_css_path) : $plugin_version;
5546 - $transcripts_css_version = file_exists($transcripts_css_path) ? filemtime($transcripts_css_path) : $plugin_version;
5547 5558 $transcripts_js_version = file_exists($transcripts_js_path) ? filemtime($transcripts_js_path) : $plugin_version;
5548 5559
5549 -
5550 5560 // Enqueue scripts and styles with corrected paths
5551 5561 wp_enqueue_script(
5552 5562 'mxchat-color-picker',
5553 5563 plugin_dir_url(__FILE__) . '../js/my-color-picker.js',
@@ -5564,8 +5574,16 @@
5564 5574 true
5565 5575 );
5566 5576
5567 5577 wp_enqueue_script(
5578 + 'mxchat-transcripts-js',
5579 + plugin_dir_url(__FILE__) . '../js/mxchat_transcripts.js',
5580 + array('jquery'),
5581 + $transcripts_js_version,
5582 + true
5583 + );
5584 +
5585 + wp_enqueue_script(
5568 5586 'mxchat-admin-js',
5569 5587 plugin_dir_url(__FILE__) . '../js/mxchat-admin.js',
5570 5588 array('jquery'),
5571 5589 $plugin_version,
@@ -5576,9 +5594,8 @@
5576 5594 'ajax_url' => admin_url('admin-ajax.php'),
5577 5595 'license_nonce' => wp_create_nonce('mxchat_activate_license_nonce'),
5578 5596 'inline_edit_nonce' => wp_create_nonce('mxchat_save_inline_nonce'),
5579 5597 'setting_nonce' => wp_create_nonce('mxchat_save_setting_nonce'),
5580 - 'export_nonce' => wp_create_nonce('mxchat_export_transcripts'),
5581 5598 ));
5582 5599
5583 5600 // Enqueue the admin CSS
5584 5601 wp_enqueue_style(
@@ -5587,25 +5604,8 @@
5587 5604 array(),
5588 5605 $admin_css_version
5589 5606 );
5590 5607
5591 - if (isset($_GET['page']) && $_GET['page'] === 'mxchat-transcripts') {
5592 - wp_enqueue_style(
5593 - 'mxchat-chat-transcripts-css',
5594 - plugin_dir_url(__FILE__) . '../css/chat-transcripts.css',
5595 - array(),
5596 - $transcripts_css_version
5597 - );
5598 -
5599 - wp_enqueue_script(
5600 - 'mxchat-transcripts-js',
5601 - plugin_dir_url(__FILE__) . '../js/mxchat_transcripts.js',
5602 - array('jquery'),
5603 - $transcripts_js_version,
5604 - true
5605 - );
5606 - }
5607 -
5608 5608 wp_enqueue_style(
5609 5609 'mxchat-knowledge-css',
5610 5610 plugin_dir_url(__FILE__) . '../css/knowledge-style.css',
5611 5611 array(),
@@ -5778,25 +5778,8 @@
5778 5778 if (isset($input['pre_chat_message'])) {
5779 5779 $new_input['pre_chat_message'] = sanitize_textarea_field($input['pre_chat_message']);
5780 5780 }
5781 5781
5782 - if (isset($input['voyage_api_key'])) {
5783 - $new_input['voyage_api_key'] = sanitize_text_field($input['voyage_api_key']);
5784 - }
5785 -
5786 - // Add to your sanitize function
5787 - if (isset($input['embedding_model'])) {
5788 - $allowed_models = array(
5789 - 'text-embedding-ada-002',
5790 - 'text-embedding-3-small',
5791 - 'text-embedding-3-large',
5792 - 'voyage-3-large'
5793 - );
5794 - if (in_array($input['embedding_model'], $allowed_models)) {
5795 - $new_input['embedding_model'] = sanitize_text_field($input['embedding_model']);
5796 - }
5797 - }
5798 -
5799 5782 if (isset($input['model'])) {
5800 5783 $allowed_models = array(
5801 5784 'grok-beta',
5802 5785 'grok-2',
@@ -5815,8 +5798,9 @@
5815 5798 $new_input['model'] = sanitize_text_field($input['model']);
5816 5799 }
5817 5800 }
5818 5801
5802 + // Sanitize new pro features
5819 5803 if (isset($input['close_button_color'])) {
5820 5804 $new_input['close_button_color'] = sanitize_hex_color($input['close_button_color']);
5821 5805 }
5822 5806
@@ -6028,9 +6012,9 @@
6028 6012
6029 6013
6030 6014 private static function mxchat_extract_main_content($html) {
6031 6015 if (empty($html)) {
6032 - //error_log('mxchat_extract_main_content: Empty HTML content received');
6016 + error_log('mxchat_extract_main_content: Empty HTML content received');
6033 6017 return '';
6034 6018 }
6035 6019
6036 6020 try {
@@ -6072,9 +6056,9 @@
6072 6056 // Last resort: return the original HTML
6073 6057 return $html;
6074 6058
6075 6059 } catch (Exception $e) {
6076 - //error_log('mxchat_extract_main_content error: ' . $e->getMessage());
6060 + error_log('mxchat_extract_main_content error: ' . $e->getMessage());
6077 6061 return $html; // Return original HTML if parsing fails
6078 6062 } finally {
6079 6063 libxml_clear_errors();
6080 6064 }