PluginProbe
MxChat – AI Chatbot & Content Generation for WordPress / 2.0.0
MxChat – AI Chatbot & Content Generation for WordPress v2.0.0
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 +890 -775 2.0.52.0.0 View file →
@@ -43,16 +43,14 @@
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')) {
54 -
52 +
55 53 //error_log('MxChat Admin: WooCommerce integration is enabled, adding hooks');
56 54 add_action('wp_insert_post', array($this, 'mxchat_handle_product_change'), 10, 3);
57 55 add_action('wp_trash_post', array($this, 'mxchat_handle_product_delete'));
58 56 add_action('before_delete_post', array($this, 'mxchat_handle_product_delete'));
@@ -74,9 +72,9 @@
74 72 'deepseek_api_key' => '',
75 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:
76 74 - Your name is [Chatbot Name].
77 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.
78 - - 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.
79 77 - Keep your responses short, concise, and to the point. Provide clear and direct answers suitable for a chatbot interaction.
80 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'),
81 79 'model' => esc_html__('gpt-4o', 'mxchat'),
82 80 'rate_limit_logged_out' => esc_html__('100', 'mxchat'),
@@ -174,26 +172,28 @@
174 172 'mxchat-prompts',
175 173 array($this, 'mxchat_create_prompts_page')
176 174 );
177 175
176 + // Submenu page for Chat Transcripts
178 177 add_submenu_page(
179 - 'mxchat-max',
178 + 'mxchat-max', // Corrected parent slug to match the main menu
180 179 esc_html__('Chat Transcripts', 'mxchat'),
181 180 esc_html__('Transcripts', 'mxchat'),
182 181 'manage_options',
183 182 'mxchat-transcripts',
184 - array($this, 'mxchat_create_transcripts_page')
183 + array($this, 'mxchat_create_transcripts_page') // Prefixed function name with mxchat_
185 184 );
186 185
186 + // Submenu page for Intents
187 187 add_submenu_page(
188 - 'mxchat-max',
189 - esc_html__('MxChat Intents', 'mxchat'),
190 - esc_html__('Intents', 'mxchat'),
191 - 'manage_options',
192 - 'mxchat-intents',
193 - 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
194 194 );
195 -
195 +
196 196 add_submenu_page(
197 197 'mxchat-max',
198 198 esc_html__('Add Ons', 'mxchat'),
199 199 esc_html__('Add Ons', 'mxchat'),
@@ -241,8 +241,9 @@
241 241 // Also update old option for backwards compatibility
242 242 update_option('additional_popular_questions', $questions);
243 243 }
244 244 break;
245 + case 'close_button_color':
245 246 case 'user_message_bg_color':
246 247 case 'user_message_font_color':
247 248 case 'bot_message_bg_color':
248 249 case 'bot_message_font_color':
@@ -409,15 +410,16 @@
409 410 <?php endif; ?>
410 411
411 412 <div class="mxchat-agents-banner">
412 413 <p>
413 - <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'); ?>
414 - </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>
415 416 </div>
416 417
417 418 <h2 class="mxchat-nav-tab-wrapper">
418 419 <a href="#chatbot" class="mxchat-nav-tab mxchat-nav-tab-active" data-tab="chatbot"><?php echo esc_html__('Chatbot', 'mxchat'); ?></a>
419 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>
420 422 <a href="#general" class="mxchat-nav-tab" data-tab="general"><?php echo esc_html__('FAQ', 'mxchat'); ?></a>
421 423 </h2>
422 424
423 425 <div id="chatbot" class="mxchat-tab-content active">
@@ -427,8 +429,15 @@
427 429 </div>
428 430
429 431 <div id="embed" class="mxchat-tab-content">
430 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>
431 440
432 441 <div class="mxchat-settings-section">
433 442 <h2><?php echo esc_html__('Loops Settings', 'mxchat'); ?></h2>
434 443 <table class="form-table">
@@ -466,8 +475,13 @@
466 475 </div>
467 476 </div>
468 477 </div>
469 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>
470 484
471 485 <div id="general" class="mxchat-tab-content">
472 486 <?php do_settings_sections('mxchat-general'); ?>
473 487 <p>
@@ -576,348 +590,73 @@
576 590 <?php
577 591 }
578 592
579 593
594 +
580 595 public function mxchat_create_transcripts_page() {
581 596 global $wpdb;
582 597 $table_name = $wpdb->prefix . 'mxchat_chat_transcripts';
583 -
598 +
584 599 // Get basic stats
585 600 $total_chats = $wpdb->get_var("SELECT COUNT(DISTINCT session_id) FROM $table_name");
586 601 $total_messages = $wpdb->get_var("SELECT COUNT(*) FROM $table_name");
587 -
588 - // Count unique users with detailed breakdown
589 - $total_users = $wpdb->get_var("
590 - SELECT COUNT(DISTINCT
591 - CASE
592 - WHEN user_email != '' AND user_email IS NOT NULL THEN user_email
593 - WHEN user_id != 0 THEN CONCAT('user_', user_id)
594 - WHEN user_identifier NOT LIKE 'Tech-Savvy User'
595 - AND user_identifier NOT LIKE 'Detail-Oriented User'
596 - AND user_identifier NOT LIKE 'Language Learner'
597 - AND user_identifier NOT LIKE 'Casual Browser'
598 - AND user_identifier NOT LIKE 'Policy Enforcer'
599 - AND user_identifier NOT LIKE 'Researcher'
600 - AND user_identifier NOT LIKE 'Loyalty Member'
601 - AND user_identifier NOT LIKE 'Gift Buyer'
602 - AND user_identifier NOT LIKE 'Parent or Caregiver'
603 - THEN user_identifier
604 - ELSE session_id
605 - END
606 - )
607 - FROM $table_name
608 - WHERE role != 'assistant'
609 - ");
610 -
611 - // Get user type breakdown
612 - $registered_users = $wpdb->get_var("
613 - SELECT COUNT(DISTINCT user_email)
614 - FROM $table_name
615 - WHERE user_email != '' AND user_email IS NOT NULL
616 - ");
617 -
618 - $guest_users = $wpdb->get_var("
619 - SELECT COUNT(DISTINCT user_identifier)
620 - FROM $table_name
621 - WHERE (user_email = '' OR user_email IS NULL)
622 - AND role != 'assistant'
623 - AND user_identifier NOT LIKE 'Tech-Savvy User'
624 - AND user_identifier NOT LIKE 'Detail-Oriented User'
625 - AND user_identifier NOT LIKE 'Language Learner'
626 - AND user_identifier NOT LIKE 'Casual Browser'
627 - AND user_identifier NOT LIKE 'Policy Enforcer'
628 - AND user_identifier NOT LIKE 'Researcher'
629 - AND user_identifier NOT LIKE 'Loyalty Member'
630 - AND user_identifier NOT LIKE 'Gift Buyer'
631 - AND user_identifier NOT LIKE 'Parent or Caregiver'
632 - ");
633 -
634 - // Get agent test messages count
635 - $agent_tests = $wpdb->get_var("
636 - SELECT COUNT(DISTINCT session_id)
637 - FROM $table_name
638 - WHERE user_identifier IN (
639 - 'Tech-Savvy User',
640 - 'Detail-Oriented User',
641 - 'Language Learner',
642 - 'Casual Browser',
643 - 'Policy Enforcer',
644 - 'Researcher',
645 - 'Loyalty Member',
646 - 'Gift Buyer',
647 - 'Parent or Caregiver'
648 - )
649 - ");
602 + $total_users = $wpdb->get_var("SELECT COUNT(DISTINCT user_email) FROM $table_name WHERE user_email != ''");
650 603 ?>
651 - <div class="wrap mxchat-transcripts-wrapper">
652 - <!-- Hero Section -->
653 - <div class="mxchat-transcripts-hero">
654 - <h1 class="mxchat-main-title">
655 - Chat <span class="mxchat-gradient-text">Transcripts</span>
656 - </h1>
657 - <p class="mxchat-hero-subtitle">
658 - <?php esc_html_e('Review and manage your chatbot conversations with detailed message history.', 'mxchat'); ?>
659 - </p>
660 - </div>
661 - <div class="mxchat-content">
662 - <!-- Stats Cards -->
663 - <div class="mxchat-stats-grid">
664 - <div class="mxchat-stat-card">
665 - <div class="stat-icon">💬</div>
666 - <div class="stat-content">
667 - <span class="stat-value"><?php echo esc_html($total_chats); ?></span>
668 - <span class="stat-label"><?php esc_html_e('Total Chats', 'mxchat'); ?></span>
669 - </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>
670 612 </div>
671 - <div class="mxchat-stat-card">
672 - <div class="stat-icon">📝</div>
673 - <div class="stat-content">
674 - <span class="stat-value"><?php echo esc_html($total_messages); ?></span>
675 - <span class="stat-label"><?php esc_html_e('Total Messages', 'mxchat'); ?></span>
676 - </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>
677 619 </div>
678 - <div class="mxchat-stat-card">
679 - <div class="stat-icon">👥</div>
680 - <div class="stat-content">
681 - <span class="stat-value"><?php echo esc_html($total_users); ?></span>
682 - <span class="stat-label"><?php esc_html_e('Unique Users', 'mxchat'); ?></span>
683 - <span class="stat-sublabel">
684 - <?php
685 - echo sprintf(
686 - esc_html__('%d registered, %d guests, %d agent tests', 'mxchat'),
687 - $registered_users,
688 - $guest_users,
689 - $agent_tests
690 - );
691 - ?>
692 - </span>
693 - </div>
694 - </div>
695 620 </div>
696 - <!-- Search and Filter Controls -->
697 - <div class="mxchat-controls-wrapper">
698 - <div class="mxchat-search-box">
699 - <input type="text" id="mxchat-search-transcripts"
700 - placeholder="<?php esc_attr_e('Search transcripts...', 'mxchat'); ?>"
701 - 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>
702 626 </div>
703 - <form id="mxchat-delete-form" method="post">
704 - <?php wp_nonce_field('mxchat_delete_chat_history', 'mxchat_delete_chat_nonce'); ?>
705 - <div class="mxchat-controls">
706 - <button type="button" id="mxchat-export-transcripts" class="mxchat-action-button">
707 - <span class="dashicons dashicons-download"></span>
708 - <?php esc_html_e('Export All Chats', 'mxchat'); ?>
709 - </button>
710 - <button type="button" id="mxchat-select-all-transcripts" class="mxchat-select-button">
711 - <span class="dashicons dashicons-yes-alt"></span>
712 - <span class="button-text"><?php esc_html_e('Select All', 'mxchat'); ?></span>
713 - </button>
714 - <button type="submit" class="button delete-chats-button">
715 - <span class="dashicons dashicons-trash"></span>
716 - <?php esc_html_e('Delete Selected', 'mxchat'); ?>
717 - </button>
718 - </div>
719 - </form>
720 627 </div>
721 - <!-- Transcripts Container -->
722 - <div id="mxchat-transcripts"></div>
723 628 </div>
724 - </div>
725 - <?php
726 -}
727 629
728 -public function export_chat_transcripts() {
729 - if (!current_user_can('manage_options')) {
730 - wp_die(esc_html__('You do not have sufficient permissions to access this page.', 'mxchat'));
731 - }
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>
732 637
733 - 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>
734 652
735 - global $wpdb;
736 - $table_name = $wpdb->prefix . 'mxchat_chat_transcripts';
737 -
738 - // Get all transcripts ordered by session and timestamp
739 - $results = $wpdb->get_results(
740 - "SELECT session_id, user_email, user_identifier, role, message, timestamp
741 - FROM {$table_name}
742 - ORDER BY session_id, timestamp ASC"
743 - );
744 -
745 - if (empty($results)) {
746 - wp_send_json_error(array('message' => 'No transcripts found.'));
747 - wp_die();
748 - }
749 -
750 - // Set headers for CSV download
751 - header('Content-Type: text/csv');
752 - header('Content-Disposition: attachment; filename="chat-transcripts-' . date('Y-m-d') . '.csv"');
753 - header('Pragma: no-cache');
754 - header('Expires: 0');
755 -
756 - // Create output stream
757 - $output = fopen('php://output', 'w');
758 -
759 - // Add UTF-8 BOM for proper Excel encoding
760 - fputs($output, "\xEF\xBB\xBF");
761 -
762 - // Add CSV headers
763 - fputcsv($output, array(
764 - 'Session ID',
765 - 'Email',
766 - 'User Identifier',
767 - 'Role',
768 - 'Message',
769 - 'Timestamp'
770 - ));
771 -
772 - // Add data rows
773 - foreach ($results as $row) {
774 - fputcsv($output, array(
775 - $row->session_id,
776 - $row->user_email,
777 - $row->user_identifier,
778 - $row->role,
779 - $row->message,
780 - $row->timestamp
781 - ));
782 - }
783 -
784 - fclose($output);
785 - wp_die();
653 + <!-- Transcripts Container -->
654 + <div id="mxchat-transcripts"></div>
655 + </div>
656 + <?php
786 657 }
787 658
788 -public function mxchat_fetch_chat_history() {
789 - global $wpdb;
790 - $table_name = $wpdb->prefix . 'mxchat_chat_transcripts';
791 -
792 - if (!current_user_can('manage_options')) {
793 - wp_die(esc_html__('You do not have sufficient permissions to view this page.', 'mxchat'));
794 - }
795 -
796 - // First get unique session IDs ordered by most recent message in each session
797 - $session_ids = $wpdb->get_col(
798 - $wpdb->prepare(
799 - "SELECT DISTINCT session_id
800 - FROM {$table_name}
801 - GROUP BY session_id
802 - ORDER BY MAX(timestamp) DESC"
803 - )
804 - );
805 -
806 - if (empty($session_ids)) {
807 - wp_die(esc_html__('No chat history available.', 'mxchat'));
808 - }
809 -
810 - ob_start();
811 - echo '<div class="mxchat-transcript">';
812 -
813 - // Iterate through sessions from newest to oldest
814 - foreach ($session_ids as $session_id) {
815 - // Get the email associated with this session (if available)
816 - $email = $wpdb->get_var(
817 - $wpdb->prepare(
818 - "SELECT user_email
819 - FROM {$table_name}
820 - WHERE session_id = %s AND user_email != ''
821 - ORDER BY timestamp ASC
822 - LIMIT 1",
823 - $session_id
824 - )
825 - );
826 -
827 - // Debug: Check email retrieval
828 - if (empty($email)) {
829 - //error_log("No email found for session {$session_id}");
830 - } else {
831 - //error_log("Email for session {$session_id}: " . $email);
832 - }
833 -
834 - // Get messages for this session ordered by timestamp
835 - $messages = $wpdb->get_results(
836 - $wpdb->prepare(
837 - "SELECT * FROM {$table_name}
838 - WHERE session_id = %s
839 - ORDER BY timestamp ASC",
840 - $session_id
841 - )
842 - );
843 -
844 - // Start session block
845 - echo '<div class="mxchat-session">';
846 - echo '<div class="mxchat-session-header">';
847 - // Wrap checkbox and session ID in one block
848 - echo '<div class="mxchat-session-id">';
849 - echo '<input type="checkbox" name="delete_session_ids[]" value="' . esc_attr($session_id) . '"> ';
850 - echo '<strong>' . esc_html__('Session ID:', 'mxchat') . '</strong> ' . esc_html($session_id);
851 - echo '</div>';
852 -
853 - // Place email directly below the session ID block
854 - if (!empty($email)) {
855 - echo '<div class="mxchat-session-email">';
856 - echo '<strong>' . esc_html__('Email:', 'mxchat') . '</strong> ' . esc_html($email);
857 - echo '</div>';
858 - }
859 - echo '</div>';
860 -
861 - echo '<div class="mxchat-messages">';
862 -
863 - // Display messages for this session
864 - foreach ($messages as $transcript) {
865 - $formatted_timestamp = date_i18n('F j, Y g:i a', strtotime($transcript->timestamp));
866 -
867 - // Determine message styling
868 - switch ($transcript->role) {
869 - case 'assistant':
870 - case 'bot':
871 - $message_class = 'bot-message';
872 - $display_role = esc_html__('Chatbot', 'mxchat');
873 - break;
874 - case 'user':
875 - $message_class = 'user-message';
876 - $display_role = !empty($transcript->user_identifier)
877 - ? sanitize_text_field($transcript->user_identifier)
878 - : esc_html__('User', 'mxchat');
879 - break;
880 - case 'agent':
881 - $message_class = 'agent-message';
882 - $display_role = esc_html__('Agent', 'mxchat');
883 - break;
884 - default:
885 - $message_class = 'unknown-message';
886 - $display_role = esc_html__('Unknown', 'mxchat');
887 - }
888 -
889 - // Process message content
890 - $message_content = wp_kses(
891 - stripslashes($transcript->message),
892 - [
893 - 'b' => [], 'strong' => [], 'i' => [], 'em' => [], 'u' => [],
894 - 'br' => [], 'p' => [], 'ul' => [], 'ol' => [], 'li' => [],
895 - 'a' => ['href' => [], 'title' => []]
896 - ]
897 - );
898 - $message_content = nl2br($message_content);
899 -
900 - // Render message
901 - echo '<div class="mxchat-message ' . esc_attr($message_class) . '">';
902 - echo '<div class="mxchat-message-header">' . esc_html($display_role) . '</div>';
903 - echo '<div class="mxchat-message-content">' . $message_content . '</div>';
904 - echo '<div class="mxchat-timestamp">' . esc_html($formatted_timestamp) . '</div>';
905 - echo '</div>';
906 - }
907 -
908 - // Close session block
909 - echo '</div></div>';
910 - }
911 -
912 - echo '</div>';
913 - $output = ob_get_clean();
914 - echo $output;
915 - wp_die();
916 -}
917 -
918 -
919 -
920 659 public function mxchat_create_prompts_page() {
921 660 global $wpdb;
922 661 $table_name = $wpdb->prefix . 'mxchat_system_prompt_content';
923 662
@@ -950,9 +689,9 @@
950 689 $per_page,
951 690 $offset
952 691 )
953 692 );
954 -
693 +
955 694 // Add the pagination links generation here
956 695 $page_links = paginate_links(array(
957 696 'base' => add_query_arg(array(
958 697 'paged' => '%#%',
@@ -1008,9 +747,9 @@
1008 747 <!-- Auto-Sync Settings -->
1009 748 <div class="mxchat-settings-section">
1010 749 <h3><?php esc_html_e('Auto-Sync Settings', 'mxchat'); ?></h3>
1011 750 <p class="mxchat-description">
1012 - <?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'); ?>
1013 752 </p>
1014 753 <div class="mxchat-autosave-section"> <!-- Add this wrapper -->
1015 754 <div class="mxchat-toggle-group">
1016 755 <div class="mxchat-toggle-container">
@@ -1016,11 +755,11 @@
1016 755 <div class="mxchat-toggle-container">
1017 756 <label class="mxchat-toggle-switch">
1018 757 <input type="checkbox"
1019 758 name="mxchat_auto_sync_posts"
1020 - class="mxchat-autosave-field"
759 + class="mxchat-autosave-field"
1021 760 value="1"
1022 - data-nonce="<?php echo wp_create_nonce('mxchat_prompts_setting_nonce'); ?>"
761 + data-nonce="<?php echo wp_create_nonce('mxchat_prompts_setting_nonce'); ?>"
1023 762 <?php checked(get_option('mxchat_auto_sync_posts', '0'), '1'); ?>>
1024 763 <span class="mxchat-toggle-slider"></span>
1025 764 </label>
1026 765 <span class="mxchat-toggle-label">
@@ -1032,9 +771,9 @@
1032 771 <input type="checkbox"
1033 772 name="mxchat_auto_sync_pages"
1034 773 class="mxchat-autosave-field"
1035 774 value="1"
1036 - data-nonce="<?php echo wp_create_nonce('mxchat_prompts_setting_nonce'); ?>"
775 + data-nonce="<?php echo wp_create_nonce('mxchat_prompts_setting_nonce'); ?>"
1037 776 <?php checked(get_option('mxchat_auto_sync_pages', '0'), '1'); ?>>
1038 777 <span class="mxchat-toggle-slider"></span>
1039 778 </label>
1040 779 <span class="mxchat-toggle-label">
@@ -1048,9 +787,9 @@
1048 787 <!-- Import Methods -->
1049 788 <div class="mxchat-import-methods">
1050 789 <div class="mxchat-method-card">
1051 790 <h4><?php esc_html_e('Sitemap Import', 'mxchat'); ?></h4>
1052 - <p><?php esc_html_e('Import all content from your sitemap automatically. Use a content-specific sub-sitemap, not the sitemap index.', 'mxchat'); ?></p>
791 + <p><?php esc_html_e('Import all content from your sitemap automatically.', 'mxchat'); ?></p>
1053 792 </div>
1054 793 <div class="mxchat-method-card">
1055 794 <h4><?php esc_html_e('PDF Import', 'mxchat'); ?></h4>
1056 795 <p><?php esc_html_e('Import knowledge directly from PDF documents.', 'mxchat'); ?></p>
@@ -1067,9 +806,9 @@
1067 806
1068 807 <!-- Import Form -->
1069 808 <?php if (!$is_processing) : ?>
1070 809 <div class="mxchat-import-form">
1071 - <form id="mxchat-sitemap-form" method="post"
810 + <form id="mxchat-sitemap-form" method="post"
1072 811 action="<?php echo esc_url(admin_url('admin-post.php?action=mxchat_submit_sitemap')); ?>">
1073 812 <?php wp_nonce_field('mxchat_submit_sitemap_action', 'mxchat_submit_sitemap_nonce'); ?>
1074 813 <div class="mxchat-url-input-group">
1075 814 <input type="url"
@@ -1126,9 +865,9 @@
1126 865
1127 866 <?php if ($sitemap_status && $sitemap_status['status'] !== 'complete') : ?>
1128 867 <div class="mxchat-status-card">
1129 868 <div class="mxchat-status-header">
1130 - <h4><?php esc_html_e('Sitemap Processing Status (Refresh for update)', 'mxchat'); ?></h4>
869 + <h4><?php esc_html_e('Sitemap Processing Status', 'mxchat'); ?></h4>
1131 870 <?php if ($is_processing) : ?>
1132 871 <form method="post" class="mxchat-stop-form"
1133 872 action="<?php echo esc_url(admin_url('admin-post.php?action=mxchat_stop_processing')); ?>">
1134 873 <?php wp_nonce_field('mxchat_stop_processing_action', 'mxchat_stop_processing_nonce'); ?>
@@ -1171,19 +910,19 @@
1171 910 <div class="mxchat-card">
1172 911 <div class="mxchat-card-header">
1173 912 <h2><?php esc_html_e('Submit Direct Content', 'mxchat'); ?></h2>
1174 913 </div>
1175 - <form id="mxchat-content-form" method="post"
914 + <form id="mxchat-content-form" method="post"
1176 915 action="<?php echo esc_url(admin_url('admin-post.php?action=mxchat_submit_content')); ?>">
1177 916 <?php wp_nonce_field('mxchat_submit_content_action', 'mxchat_submit_content_nonce'); ?>
1178 917 <div class="mxchat-form-group">
1179 918 <label for="article_content"><?php esc_html_e('Content:', 'mxchat'); ?></label>
1180 - <textarea name="article_content" id="article_content" required
919 + <textarea name="article_content" id="article_content" required
1181 920 placeholder="<?php esc_attr_e('Enter your content here...', 'mxchat'); ?>"></textarea>
1182 921 </div>
1183 922 <div class="mxchat-form-group">
1184 923 <label for="article_url"><?php esc_html_e('Source URL (Optional):', 'mxchat'); ?></label>
1185 - <input type="url" name="article_url" id="article_url"
924 + <input type="url" name="article_url" id="article_url"
1186 925 placeholder="<?php esc_attr_e('Enter source URL', 'mxchat'); ?>">
1187 926 </div>
1188 927 <button type="submit" name="submit_content" class="mxchat-button-primary">
1189 928 <?php esc_html_e('Submit Content', 'mxchat'); ?>
@@ -1257,13 +996,13 @@
1257 996 <span class="mxchat-na"><?php esc_html_e('N/A', 'mxchat'); ?></span>
1258 997 <?php endif; ?>
1259 998 </td>
1260 999 <td class="mxchat-actions-cell">
1261 - <button class="mxchat-button-icon edit-button"
1000 + <button class="mxchat-button-icon edit-button"
1262 1001 data-id="<?php echo esc_attr($prompt->id); ?>">
1263 1002 <span class="dashicons dashicons-edit"></span>
1264 1003 </button>
1265 - <button class="mxchat-button-icon save-button"
1004 + <button class="mxchat-button-icon save-button"
1266 1005 data-id="<?php echo esc_attr($prompt->id); ?>"
1267 1006 style="display:none;"
1268 1007 data-nonce="<?php echo wp_create_nonce('mxchat_save_inline_nonce'); ?>">
1269 1008 <span class="dashicons dashicons-saved"></span>
@@ -1270,9 +1009,9 @@
1270 1009 </button>
1271 1010 <a href="<?php echo esc_url(admin_url(
1272 1011 'admin-post.php?action=mxchat_delete_prompt&id=' . esc_attr($prompt->id)
1273 1012 . '&_wpnonce=' . wp_create_nonce('mxchat_delete_prompt_nonce')
1274 - )); ?>"
1013 + )); ?>"
1275 1014 class="mxchat-button-icon delete-button"
1276 1015 onclick="return confirm('<?php esc_attr_e('Are you sure you want to delete this entry?', 'mxchat'); ?>');">
1277 1016 <span class="dashicons dashicons-trash"></span>
1278 1017 </a>
@@ -1509,9 +1248,9 @@
1509 1248
1510 1249 if ($pinecone_settings && is_array($pinecone_settings)) {
1511 1250 // Check if Pinecone is enabled and all required settings are present
1512 1251 $use_pinecone = (
1513 - isset($pinecone_settings['mxchat_use_pinecone']) &&
1252 + isset($pinecone_settings['mxchat_use_pinecone']) &&
1514 1253 $pinecone_settings['mxchat_use_pinecone'] === '1' &&
1515 1254 !empty($pinecone_settings['mxchat_pinecone_api_key']) &&
1516 1255 !empty($pinecone_settings['mxchat_pinecone_host']) &&
1517 1256 !empty($pinecone_settings['mxchat_pinecone_index']) &&
@@ -1530,9 +1269,9 @@
1530 1269 $pinecone_settings['mxchat_pinecone_index']
1531 1270 );
1532 1271
1533 1272 if (!$pinecone_result['success']) {
1534 - //error_log('MXChat: Pinecone sync failed - falling back to WordPress DB');
1273 + error_log('MXChat: Pinecone sync failed - falling back to WordPress DB');
1535 1274 $this->store_in_wordpress_db($content, $url, $embedding_vector);
1536 1275 }
1537 1276 } else {
1538 1277 // Fallback to WordPress DB storage
@@ -1538,25 +1277,28 @@
1538 1277 // Fallback to WordPress DB storage
1539 1278 $this->store_in_wordpress_db($content, $url, $embedding_vector);
1540 1279 }
1541 1280 }
1542 -// Modified storage function to add type field
1281 +
1543 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
1544 1284 $vector_id = $vector_id ?: md5($url);
1285 +
1286 + // Get the Pinecone host from options
1545 1287 $options = get_option('mxchat_pinecone_addon_options');
1546 1288 $host = $options['mxchat_pinecone_host'] ?? '';
1547 -
1289 +
1548 1290 if (empty($host)) {
1291 + //error_log('Pinecone host is not configured');
1549 1292 return array(
1550 1293 'success' => false,
1551 1294 'message' => 'Pinecone host is not configured. Please set the host in your settings.'
1552 1295 );
1553 1296 }
1554 -
1555 - // Determine if this is a product URL
1556 - $is_product = (strpos($url, '/product/') !== false || strpos($url, '/shop/') !== false);
1557 -
1297 +
1298 + // Build API endpoint using the configured host
1558 1299 $api_endpoint = "https://{$host}/vectors/upsert";
1300 +
1559 1301 $request_body = array(
1560 1302 'vectors' => array(
1561 1303 array(
1562 1304 'id' => $vector_id,
@@ -1563,15 +1305,14 @@
1563 1305 'values' => $embedding_vector,
1564 1306 'metadata' => array(
1565 1307 'text' => $content,
1566 1308 'source_url' => $url,
1567 - 'type' => $is_product ? 'product' : 'content',
1568 1309 'last_updated' => time()
1569 1310 )
1570 1311 )
1571 1312 )
1572 1313 );
1573 -
1314 +
1574 1315 $response = wp_remote_post($api_endpoint, array(
1575 1316 'headers' => array(
1576 1317 'Api-Key' => $api_key,
1577 1318 'accept' => 'application/json',
@@ -1580,24 +1321,27 @@
1580 1321 'body' => wp_json_encode($request_body),
1581 1322 'timeout' => 30,
1582 1323 'data_format' => 'body'
1583 1324 ));
1584 -
1325 +
1585 1326 if (is_wp_error($response)) {
1327 + //error_log('Pinecone API WP Error: ' . $response->get_error_message());
1586 1328 return array(
1587 1329 'success' => false,
1588 1330 'message' => $response->get_error_message()
1589 1331 );
1590 1332 }
1591 -
1333 +
1592 1334 $response_code = wp_remote_retrieve_response_code($response);
1593 1335 if ($response_code !== 200) {
1594 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));
1595 1339 return array(
1596 1340 'success' => false,
1597 1341 'message' => sprintf(
1598 - 'Pinecone API error (HTTP %d): %s',
1599 - $response_code,
1342 + 'Pinecone API error (HTTP %d): %s',
1343 + $response_code,
1600 1344 $body
1601 1345 )
1602 1346 );
1603 1347 }
@@ -1606,8 +1350,10 @@
1606 1350 'success' => true,
1607 1351 'message' => 'Successfully stored in Pinecone'
1608 1352 );
1609 1353 }
1354 +
1355 +
1610 1356 // Helper method for WordPress DB storage
1611 1357 private function store_in_wordpress_db($content, $url, $embedding_vector) {
1612 1358 global $wpdb;
1613 1359 $table_name = $wpdb->prefix . 'mxchat_system_prompt_content';
@@ -1639,109 +1385,16 @@
1639 1385 array('%s', '%s', '%s', '%s')
1640 1386 );
1641 1387 }
1642 1388 }
1643 -/**
1644 - * Handle deletion of posts and pages from both Pinecone and WordPress DB
1645 - *
1646 - * @param int $post_id The ID of the post being deleted
1647 - * @return void
1648 - */
1649 -public function mxchat_handle_post_delete($post_id) {
1650 - // Get post data before it's deleted
1651 - $post = get_post($post_id);
1652 1389
1653 - // Basic validation
1654 - if (!$post || wp_is_post_revision($post_id)) {
1655 - return;
1656 - }
1657 1390
1658 - // Check post type
1659 - $post_type = $post->post_type;
1660 - if (!in_array($post_type, array('post', 'page'))) {
1661 - return;
1662 - }
1663 -
1664 - // Check if sync is enabled for this post type
1665 - $sync_option = ($post_type === 'post') ? 'mxchat_auto_sync_posts' : 'mxchat_auto_sync_pages';
1666 - if (get_option($sync_option) != '1') {
1667 - return;
1668 - }
1669 -
1670 - // Get the URL before post is deleted
1671 - $source_url = get_permalink($post_id);
1672 - if (!$source_url) {
1673 - //error_log('MXChat: Failed to get permalink for post ' . $post_id);
1674 - return;
1675 - }
1676 -
1677 - // Check for Pinecone addon and its settings
1678 - $pinecone_settings = get_option('mxchat_pinecone_addon_options');
1679 - $use_pinecone = false;
1680 - if ($pinecone_settings && is_array($pinecone_settings)) {
1681 - $use_pinecone = (
1682 - isset($pinecone_settings['mxchat_use_pinecone']) &&
1683 - $pinecone_settings['mxchat_use_pinecone'] === '1' &&
1684 - !empty($pinecone_settings['mxchat_pinecone_api_key']) &&
1685 - !empty($pinecone_settings['mxchat_pinecone_host']) &&
1686 - !empty($pinecone_settings['mxchat_pinecone_index']) &&
1687 - !empty($pinecone_settings['mxchat_pinecone_environment'])
1688 - );
1689 - }
1690 -
1691 - $deletion_successful = false;
1692 -
1693 - if ($use_pinecone) {
1694 - try {
1695 - $pinecone_result = $this->delete_from_pinecone(
1696 - array($source_url),
1697 - $pinecone_settings['mxchat_pinecone_api_key'],
1698 - $pinecone_settings['mxchat_pinecone_environment'],
1699 - $pinecone_settings['mxchat_pinecone_index']
1700 - );
1701 -
1702 - if (!$pinecone_result['success']) {
1703 - //error_log('MXChat: Pinecone deletion failed for URL: ' . $source_url . ' - ' . $pinecone_result['message']);
1704 - } else {
1705 - $deletion_successful = true;
1706 - }
1707 - } catch (Exception $e) {
1708 - //error_log('MXChat: Exception during Pinecone deletion - ' . $e->getMessage());
1709 - }
1710 - }
1711 -
1712 - // Always attempt WordPress DB deletion, regardless of Pinecone status
1713 - try {
1714 - global $wpdb;
1715 - $table_name = $wpdb->prefix . 'mxchat_system_prompt_content';
1716 -
1717 - $result = $wpdb->delete(
1718 - $table_name,
1719 - array('source_url' => $source_url),
1720 - array('%s')
1721 - );
1722 -
1723 - if ($result === false) {
1724 - //error_log('MXChat: WordPress DB deletion failed for URL: ' . $source_url);
1725 - } else {
1726 - $deletion_successful = true;
1727 - }
1728 - } catch (Exception $e) {
1729 - //error_log('MXChat: Exception during WordPress DB deletion - ' . $e->getMessage());
1730 - }
1731 -
1732 - if (!$deletion_successful) {
1733 - //error_log('MXChat: Complete deletion failure for post ID: ' . $post_id . ' URL: ' . $source_url);
1734 - }
1735 -}
1736 -
1737 -
1738 1391 public function mxchat_handle_content_submission() {
1739 1392 // Check if the form was submitted and the user has permission.
1740 1393 if (!isset($_POST['submit_content']) || !current_user_can('manage_options')) {
1741 1394 return;
1742 1395 }
1743 -
1396 +
1744 1397 // Verify the nonce.
1745 1398 $nonce = isset($_POST['mxchat_submit_content_nonce']) ? sanitize_text_field(wp_unslash($_POST['mxchat_submit_content_nonce'])) : '';
1746 1399 if (!wp_verify_nonce($nonce, 'mxchat_submit_content_action')) {
1747 1400 wp_die(esc_html__('Nonce verification failed.', 'mxchat'));
@@ -1753,10 +1406,10 @@
1753 1406
1754 1407 // Generate the embedding vector.
1755 1408 $embedding_vector = $this->mxchat_generate_embedding($article_content);
1756 1409 if (!is_array($embedding_vector)) {
1757 - set_transient('mxchat_admin_notice_error',
1758 - esc_html__('Embedding generation failed. Please ensure your API key is correct and try again.', 'mxchat'),
1410 + set_transient('mxchat_admin_notice_error',
1411 + esc_html__('Embedding generation failed. Please ensure your API key is correct and try again.', 'mxchat'),
1759 1412 30
1760 1413 );
1761 1414 wp_safe_redirect(esc_url(admin_url('admin.php?page=mxchat-prompts')));
1762 1415 exit;
@@ -1783,15 +1436,15 @@
1783 1436 array('%s', '%s', '%s')
1784 1437 );
1785 1438
1786 1439 if ($inserted === false) {
1787 - set_transient('mxchat_admin_notice_error',
1788 - esc_html__('Error inserting content into the database. Please try again.', 'mxchat'),
1440 + set_transient('mxchat_admin_notice_error',
1441 + esc_html__('Error inserting content into the database. Please try again.', 'mxchat'),
1789 1442 30
1790 1443 );
1791 1444 } else {
1792 - set_transient('mxchat_admin_notice_success',
1793 - esc_html__('Content successfully submitted!', 'mxchat'),
1445 + set_transient('mxchat_admin_notice_success',
1446 + esc_html__('Content successfully submitted!', 'mxchat'),
1794 1447 30
1795 1448 );
1796 1449 }
1797 1450
@@ -1976,11 +1629,9 @@
1976 1629
1977 1630 return array(
1978 1631 'total_pages' => absint($status['total_pages']),
1979 1632 'processed_pages' => absint($status['processed_pages']),
1980 - 'percentage' => ($status['total_pages'] > 0)
1981 - ? round((absint($status['processed_pages']) / absint($status['total_pages'])) * 100)
1982 - : 0,
1633 + 'percentage' => round((absint($status['processed_pages']) / absint($status['total_pages'])) * 100),
1983 1634 'status' => sanitize_text_field($status['status']),
1984 1635 'last_update' => human_time_diff(absint($status['last_update']), time()) . ' ' . esc_html__('ago', 'mxchat')
1985 1636 );
1986 1637 }
@@ -2189,25 +1840,25 @@
2189 1840 $sitemap_url = esc_url_raw($sitemap_url);
2190 1841 $total_urls = absint($total_urls);
2191 1842 $batch_size = absint($batch_size);
2192 1843 $batch_pause = absint($batch_pause);
2193 -
1844 +
2194 1845 if (!is_array($urls) || empty($urls)) {
2195 1846 return;
2196 1847 }
2197 -
1848 +
2198 1849 try {
2199 1850 $status_key = sanitize_key('mxchat_sitemap_status_' . md5($sitemap_url));
2200 1851 $status = get_transient($status_key);
2201 -
1852 +
2202 1853 if (!$status || !is_array($status)) {
2203 1854 throw new Exception('Invalid status data retrieved from transient');
2204 1855 }
2205 -
1856 +
2206 1857 $start_url = absint($status['processed_urls']);
2207 1858 $end_url = min($start_url + $batch_size, $total_urls);
2208 1859 $instance = new self();
2209 -
1860 +
2210 1861 // Track failures in batch
2211 1862 $batch_stats = [
2212 1863 'processed' => 0,
2213 1864 'failed' => 0,
@@ -2216,31 +1867,31 @@
2216 1867
2217 1868 for ($i = $start_url; $i < $end_url; $i++) {
2218 1869 $page_url = esc_url_raw($urls[$i]);
2219 1870 $page_response = wp_remote_get($page_url);
2220 -
1871 +
2221 1872 if (is_wp_error($page_response) || wp_remote_retrieve_response_code($page_response) !== 200) {
2222 1873 $batch_stats['failed']++;
2223 1874 continue;
2224 1875 }
2225 -
1876 +
2226 1877 $page_html = wp_remote_retrieve_body($page_response);
2227 1878 $page_content = $instance->mxchat_extract_main_content($page_html);
2228 1879 $sanitized_content = $instance->mxchat_sanitize_content_for_api($page_content);
2229 -
1880 +
2230 1881 if (!empty($sanitized_content)) {
2231 1882 $embedding_vector = $instance->mxchat_generate_embedding($sanitized_content);
2232 -
1883 +
2233 1884 if (is_array($embedding_vector)) {
2234 1885 $options = get_option('mxchat_options');
2235 1886 $submission_result = MxChat_Utils::submit_content_to_db($sanitized_content, $page_url, $options['api_key']);
2236 -
1887 +
2237 1888 if (is_wp_error($submission_result)) {
2238 1889 $batch_stats['failed']++;
2239 1890 $batch_stats['last_error'] = $submission_result->get_error_message();
2240 1891 continue;
2241 1892 }
2242 -
1893 +
2243 1894 $batch_stats['processed']++;
2244 1895 } else {
2245 1896 $batch_stats['failed']++;
2246 1897 $batch_stats['last_error'] = 'Failed to generate embedding. Please check OpenAI API key.';
@@ -2245,14 +1896,14 @@
2245 1896 $batch_stats['failed']++;
2246 1897 $batch_stats['last_error'] = 'Failed to generate embedding. Please check OpenAI API key.';
2247 1898 }
2248 1899 }
2249 -
1900 +
2250 1901 $status['processed_urls'] = absint($i + 1);
2251 1902 $status['last_update'] = time();
2252 1903 $status['failed_urls'] = absint($status['failed_urls'] ?? 0) + $batch_stats['failed'];
2253 1904 $status['last_error'] = $batch_stats['last_error'];
2254 -
1905 +
2255 1906 set_transient($status_key, array_map('sanitize_text_field', $status), DAY_IN_SECONDS);
2256 1907 }
2257 1908
2258 1909 // If all URLs in this batch failed, stop processing
@@ -2288,20 +1939,18 @@
2288 1939
2289 1940 public function get_sitemap_processing_status($sitemap_url) {
2290 1941 $sitemap_url = esc_url_raw($sitemap_url);
2291 1942 $status = get_transient(sanitize_key('mxchat_sitemap_status_' . md5($sitemap_url)));
2292 -
1943 +
2293 1944 if (!$status || !is_array($status)) {
2294 1945 return false;
2295 1946 }
2296 -
1947 +
2297 1948 return array(
2298 1949 'total_urls' => absint($status['total_urls']),
2299 1950 'processed_urls' => absint($status['processed_urls']),
2300 1951 'failed_urls' => absint($status['failed_urls'] ?? 0),
2301 - 'percentage' => ($status['total_urls'] > 0)
2302 - ? round((absint($status['processed_urls']) / absint($status['total_urls'])) * 100)
2303 - : 0,
1952 + 'percentage' => round((absint($status['processed_urls']) / absint($status['total_urls'])) * 100),
2304 1953 'status' => sanitize_text_field($status['status']),
2305 1954 'last_update' => human_time_diff(absint($status['last_update']), time()) . ' ' . esc_html__('ago', 'mxchat'),
2306 1955 'error' => isset($status['error']) ? sanitize_text_field($status['error']) : '',
2307 1956 'last_error' => isset($status['last_error']) ? sanitize_text_field($status['last_error']) : ''
@@ -2407,9 +2056,9 @@
2407 2056 $use_pinecone = false;
2408 2057
2409 2058 if ($pinecone_settings && is_array($pinecone_settings)) {
2410 2059 $use_pinecone = (
2411 - isset($pinecone_settings['mxchat_use_pinecone']) &&
2060 + isset($pinecone_settings['mxchat_use_pinecone']) &&
2412 2061 $pinecone_settings['mxchat_use_pinecone'] === '1' &&
2413 2062 !empty($pinecone_settings['mxchat_pinecone_api_key']) &&
2414 2063 !empty($pinecone_settings['mxchat_pinecone_host']) &&
2415 2064 !empty($pinecone_settings['mxchat_pinecone_index']) &&
@@ -2440,11 +2089,11 @@
2440 2089 public function mxchat_handle_product_delete($post_id) {
2441 2090 if (get_post_type($post_id) !== 'product') {
2442 2091 return;
2443 2092 }
2444 -
2093 +
2445 2094 $source_url = get_permalink($post_id);
2446 -
2095 +
2447 2096 // Check for Pinecone addon and its settings
2448 2097 $pinecone_settings = get_option('mxchat_pinecone_addon_options');
2449 2098 $use_pinecone = false;
2450 2099
@@ -2449,9 +2098,9 @@
2449 2098 $use_pinecone = false;
2450 2099
2451 2100 if ($pinecone_settings && is_array($pinecone_settings)) {
2452 2101 $use_pinecone = (
2453 - isset($pinecone_settings['mxchat_use_pinecone']) &&
2102 + isset($pinecone_settings['mxchat_use_pinecone']) &&
2454 2103 $pinecone_settings['mxchat_use_pinecone'] === '1' &&
2455 2104 !empty($pinecone_settings['mxchat_pinecone_api_key']) &&
2456 2105 !empty($pinecone_settings['mxchat_pinecone_host']) &&
2457 2106 !empty($pinecone_settings['mxchat_pinecone_index']) &&
@@ -2473,102 +2122,139 @@
2473 2122 $wpdb->delete($table_name, array('source_url' => $source_url), array('%s'));
2474 2123 }
2475 2124 }
2476 2125
2126 +public function mxchat_fetch_chat_history() {
2127 + global $wpdb;
2128 + $table_name = $wpdb->prefix . 'mxchat_chat_transcripts';
2477 2129
2478 -/**
2479 - * Delete vectors from Pinecone by source URL
2480 - *
2481 - * @param array $urls Array of source URLs to delete
2482 - * @param string $api_key Pinecone API key
2483 - * @param string $environment Pinecone environment
2484 - * @param string $index_name Pinecone index name
2485 - * @return array Associative array with 'success' boolean and 'message' string
2486 - */
2487 -private function delete_from_pinecone($urls, $api_key, $environment, $index_name) {
2488 - // Get the Pinecone host from options (matching your store_in_pinecone_main pattern)
2489 - $options = get_option('mxchat_pinecone_addon_options');
2490 - $host = $options['mxchat_pinecone_host'] ?? '';
2491 -
2492 - if (empty($host)) {
2493 - return array(
2494 - 'success' => false,
2495 - 'message' => 'Pinecone host is not configured. Please set the host in your settings.'
2496 - );
2130 + if (!current_user_can('manage_options')) {
2131 + wp_die(esc_html__('You do not have sufficient permissions to view this page.', 'mxchat'));
2497 2132 }
2498 2133
2499 - // Build API endpoint using the configured host
2500 - $api_endpoint = "https://{$host}/vectors/delete";
2501 -
2502 - // Create vector IDs from URLs (matching your store method's ID generation)
2503 - $vector_ids = array_map('md5', $urls);
2504 -
2505 - // Prepare the delete request body
2506 - $request_body = array(
2507 - 'ids' => $vector_ids,
2508 - 'filter' => array(
2509 - 'source_url' => array(
2510 - '$in' => $urls
2511 - )
2134 + // First get unique session IDs ordered by most recent message in each session
2135 + $session_ids = $wpdb->get_col(
2136 + $wpdb->prepare(
2137 + "SELECT DISTINCT session_id
2138 + FROM {$table_name}
2139 + GROUP BY session_id
2140 + ORDER BY MAX(timestamp) DESC"
2512 2141 )
2513 2142 );
2514 2143
2515 - // Make the deletion request
2516 - $response = wp_remote_post($api_endpoint, array(
2517 - 'headers' => array(
2518 - 'Api-Key' => $api_key,
2519 - 'accept' => 'application/json',
2520 - 'content-type' => 'application/json'
2521 - ),
2522 - 'body' => wp_json_encode($request_body),
2523 - 'timeout' => 30,
2524 - 'data_format' => 'body'
2525 - ));
2144 + if (empty($session_ids)) {
2145 + wp_die(esc_html__('No chat history available.', 'mxchat'));
2146 + }
2526 2147
2527 - // Handle WordPress HTTP API errors
2528 - if (is_wp_error($response)) {
2529 - return array(
2530 - 'success' => false,
2531 - 'message' => $response->get_error_message()
2148 + ob_start();
2149 + echo '<div class="mxchat-transcript">';
2150 +
2151 + // Iterate through sessions from newest to oldest
2152 + foreach ($session_ids as $session_id) {
2153 + // Get the email associated with this session (if available)
2154 + $email = $wpdb->get_var(
2155 + $wpdb->prepare(
2156 + "SELECT user_email
2157 + FROM {$table_name}
2158 + WHERE session_id = %s AND user_email != ''
2159 + ORDER BY timestamp ASC
2160 + LIMIT 1",
2161 + $session_id
2162 + )
2532 2163 );
2533 - }
2534 2164
2535 - // Check response status
2536 - $response_code = wp_remote_retrieve_response_code($response);
2537 - if ($response_code !== 200) {
2538 - $body = wp_remote_retrieve_body($response);
2539 - return array(
2540 - 'success' => false,
2541 - 'message' => sprintf(
2542 - 'Pinecone API error (HTTP %d): %s',
2543 - $response_code,
2544 - $body
2165 + // Debug: Check email retrieval
2166 + if (empty($email)) {
2167 + //error_log("No email found for session {$session_id}");
2168 + } else {
2169 + //error_log("Email for session {$session_id}: " . $email);
2170 + }
2171 +
2172 + // Get messages for this session ordered by timestamp
2173 + $messages = $wpdb->get_results(
2174 + $wpdb->prepare(
2175 + "SELECT * FROM {$table_name}
2176 + WHERE session_id = %s
2177 + ORDER BY timestamp ASC",
2178 + $session_id
2545 2179 )
2546 2180 );
2547 - }
2548 2181
2549 - // Parse response body
2550 - $body = wp_remote_retrieve_body($response);
2551 - $response_data = json_decode($body, true);
2182 + // Start session block
2183 + echo '<div class="mxchat-session">';
2184 + echo '<div class="mxchat-session-header">';
2185 + // Wrap checkbox and session ID in one block
2186 + echo '<div class="mxchat-session-id">';
2187 + echo '<input type="checkbox" name="delete_session_ids[]" value="' . esc_attr($session_id) . '"> ';
2188 + echo '<strong>' . esc_html__('Session ID:', 'mxchat') . '</strong> ' . esc_html($session_id);
2189 + echo '</div>';
2552 2190
2553 - // Final validation of the response
2554 - if (json_last_error() !== JSON_ERROR_NONE) {
2555 - return array(
2556 - 'success' => false,
2557 - 'message' => 'Failed to parse Pinecone response: ' . json_last_error_msg()
2558 - );
2559 - }
2191 + // Place email directly below the session ID block
2192 + if (!empty($email)) {
2193 + echo '<div class="mxchat-session-email">';
2194 + echo '<strong>' . esc_html__('Email:', 'mxchat') . '</strong> ' . esc_html($email);
2195 + echo '</div>';
2196 + }
2197 + echo '</div>';
2560 2198
2561 - return array(
2562 - 'success' => true,
2563 - 'message' => sprintf('Successfully deleted %d vectors from Pinecone', count($vector_ids))
2564 - );
2565 -}
2199 + echo '<div class="mxchat-messages">';
2566 2200
2201 + // Display messages for this session
2202 + foreach ($messages as $transcript) {
2203 + $formatted_timestamp = date_i18n('F j, Y g:i a', strtotime($transcript->timestamp));
2567 2204
2205 + // Determine message styling
2206 + switch ($transcript->role) {
2207 + case 'assistant':
2208 + case 'bot':
2209 + $message_class = 'bot-message';
2210 + $display_role = esc_html__('Chatbot', 'mxchat');
2211 + break;
2212 + case 'user':
2213 + $message_class = 'user-message';
2214 + $display_role = !empty($transcript->user_identifier)
2215 + ? sanitize_text_field($transcript->user_identifier)
2216 + : esc_html__('User', 'mxchat');
2217 + break;
2218 + case 'agent':
2219 + $message_class = 'agent-message';
2220 + $display_role = esc_html__('Agent', 'mxchat');
2221 + break;
2222 + default:
2223 + $message_class = 'unknown-message';
2224 + $display_role = esc_html__('Unknown', 'mxchat');
2225 + }
2568 2226
2227 + // Process message content
2228 + $message_content = wp_kses(
2229 + stripslashes($transcript->message),
2230 + [
2231 + 'b' => [], 'strong' => [], 'i' => [], 'em' => [], 'u' => [],
2232 + 'br' => [], 'p' => [], 'ul' => [], 'ol' => [], 'li' => [],
2233 + 'a' => ['href' => [], 'title' => []]
2234 + ]
2235 + );
2236 + $message_content = nl2br($message_content);
2569 2237
2238 + // Render message
2239 + echo '<div class="mxchat-message ' . esc_attr($message_class) . '">';
2240 + echo '<div class="mxchat-message-header">' . esc_html($display_role) . '</div>';
2241 + echo '<div class="mxchat-message-content">' . $message_content . '</div>';
2242 + echo '<div class="mxchat-timestamp">' . esc_html($formatted_timestamp) . '</div>';
2243 + echo '</div>';
2244 + }
2570 2245
2246 + // Close session block
2247 + echo '</div></div>';
2248 + }
2249 +
2250 + echo '</div>';
2251 + $output = ob_get_clean();
2252 + echo $output;
2253 + wp_die();
2254 +}
2255 +
2256 +
2571 2257 public function mxchat_create_activation_page() {
2572 2258 $license_status = get_option('mxchat_license_status', 'inactive');
2573 2259 $license_error = get_option('mxchat_license_error', '');
2574 2260 ?>
@@ -2613,15 +2299,15 @@
2613 2299 </div>
2614 2300 </form>
2615 2301 <!-- License Status Display -->
2616 2302 <div class="mxchat-pro-status">
2617 - <h3><?php esc_html_e('License Status:', 'mxchat'); ?>
2303 + <h3><?php esc_html_e('License Status:', 'mxchat'); ?>
2618 2304 <span id="mxchat-license-status" class="mxchat-status-badge <?php echo $license_status; ?>">
2619 2305 <?php echo $license_status === 'active' ? esc_html__('Active', 'mxchat') : esc_html__('Inactive', 'mxchat'); ?>
2620 2306 </span>
2621 2307 </h3>
2622 2308 </div>
2623 -
2309 +
2624 2310 </div>
2625 2311 <?php
2626 2312 }
2627 2313
@@ -2650,9 +2336,9 @@
2650 2336 $callback_filter = isset($_GET['callback_filter']) ? sanitize_text_field($_GET['callback_filter']) : '';
2651 2337
2652 2338 if ($search_term) {
2653 2339 $search_term_like = '%' . $wpdb->esc_like($search_term) . '%';
2654 - $where .= $wpdb->prepare(' AND (intent_label LIKE %s OR phrases LIKE %s)',
2340 + $where .= $wpdb->prepare(' AND (intent_label LIKE %s OR phrases LIKE %s)',
2655 2341 $search_term_like, $search_term_like);
2656 2342 }
2657 2343
2658 2344 if ($callback_filter) {
@@ -2664,9 +2350,9 @@
2664 2350 $total_pages = ceil($total_intents / $per_page);
2665 2351
2666 2352 // Get intents
2667 2353 $intents = $wpdb->get_results($wpdb->prepare(
2668 - "SELECT * FROM $table_name WHERE $where LIMIT %d OFFSET %d",
2354 + "SELECT * FROM $table_name WHERE $where LIMIT %d OFFSET %d",
2669 2355 $per_page, $offset
2670 2356 ));
2671 2357
2672 2358 // Get callbacks
@@ -2689,9 +2375,9 @@
2689 2375 <div class="mxchat-card">
2690 2376 <div class="mxchat-card-header">
2691 2377 <h2><?php esc_html_e('Add New Intent', 'mxchat'); ?></h2>
2692 2378 </div>
2693 -
2379 +
2694 2380 <div class="mxchat-intent-documentation">
2695 2381 <p>
2696 2382 <?php esc_html_e('We highly encourage users to quickly read our ', 'mxchat'); ?>
2697 2383 <a href="https://mxchat.ai/documentation/#intents" target="_blank" rel="noopener noreferrer">
@@ -2700,9 +2386,9 @@
2700 2386 <?php esc_html_e(' to better understand intents. Some intents require setup in the Integration tab. If your intent is not triggering lower similarity threshold test.', 'mxchat'); ?>
2701 2387 </p>
2702 2388 </div>
2703 2389
2704 - <form id="mxchat-add-intent-form" method="post"
2390 + <form id="mxchat-add-intent-form" method="post"
2705 2391 action="<?php echo esc_url(admin_url('admin-post.php')); ?>">
2706 2392 <input type="hidden" name="action" value="mxchat_add_intent">
2707 2393 <?php wp_nonce_field('mxchat_add_intent_nonce'); ?>
2708 2394
@@ -2727,9 +2413,9 @@
2727 2413 <div class="mxchat-form-group">
2728 2414 <label for="callback_function">
2729 2415 <?php esc_html_e('Callback Function', 'mxchat'); ?>
2730 2416 </label>
2731 - <select name="callback_function" id="callback_function"
2417 + <select name="callback_function" id="callback_function"
2732 2418 class="mxchat-intent-select" required>
2733 2419 <option value="">
2734 2420 <?php esc_html_e('Select a Callback', 'mxchat'); ?>
2735 2421 </option>
@@ -2742,9 +2428,9 @@
2742 2428 $pro_only = $data['pro_only'];
2743 2429 $disabled = (!$this->is_activated && $pro_only) ? 'disabled' : '';
2744 2430 $label_suffix = (!$this->is_activated && $pro_only) ? ' (Pro Only)' : '';
2745 2431 ?>
2746 - <option value="<?php echo esc_attr($function); ?>"
2432 + <option value="<?php echo esc_attr($function); ?>"
2747 2433 <?php echo $disabled; ?>>
2748 2434 <?php echo esc_html($label . $label_suffix); ?>
2749 2435 </option>
2750 2436 <?php
@@ -2769,9 +2455,9 @@
2769 2455 <form method="get" class="mxchat-search-form">
2770 2456 <input type="hidden" name="page" value="mxchat-intents">
2771 2457 <div class="mxchat-search-group">
2772 2458 <span class="dashicons dashicons-search"></span>
2773 - <input type="text" name="s"
2459 + <input type="text" name="s"
2774 2460 placeholder="<?php esc_attr_e('Search Intents', 'mxchat'); ?>"
2775 2461 value="<?php echo esc_attr($search_term); ?>">
2776 2462 <select name="callback_filter" class="mxchat-intent-filter">
2777 2463 <option value="">
@@ -2778,9 +2464,9 @@
2778 2464 <?php esc_html_e('All Callbacks', 'mxchat'); ?>
2779 2465 </option>
2780 2466 <?php foreach ($available_callbacks as $function => $callback_data) :
2781 2467 $label = $callback_data['label']; ?>
2782 - <option value="<?php echo esc_attr($function); ?>"
2468 + <option value="<?php echo esc_attr($function); ?>"
2783 2469 <?php selected($callback_filter, $function); ?>>
2784 2470 <?php echo esc_html($label); ?>
2785 2471 </option>
2786 2472 <?php endforeach; ?>
@@ -2803,123 +2489,83 @@
2803 2489 <th><?php esc_html_e('Similarity Threshold', 'mxchat'); ?></th>
2804 2490 <th><?php esc_html_e('Actions', 'mxchat'); ?></th>
2805 2491 </tr>
2806 2492 </thead>
2807 - <tbody>
2808 - <?php if ($intents) :
2809 - foreach ($intents as $intent) :
2810 - $callback_function = $intent->callback_function;
2811 - $callback_label = isset($available_callbacks[$callback_function]['label'])
2812 - ? $available_callbacks[$callback_function]['label']
2813 - : $callback_function;
2814 - $threshold_value = isset($intent->similarity_threshold)
2815 - ? round($intent->similarity_threshold * 100)
2816 - : 85;
2817 -
2818 - // Check if this is a form intent (its intent_label starts with "Form ")
2819 - $is_form_intent = strpos($intent->intent_label, 'Form ') === 0;
2820 - ?>
2821 - <tr<?php echo $is_form_intent ? ' class="mxchat-form-intent"' : ''; ?>>
2822 - <td>
2823 - <?php
2824 - if ($is_form_intent) {
2825 - // Attempt to extract the form ID from the intent_label.
2826 - preg_match('/Form (\d+)/', $intent->intent_label, $matches);
2827 - $form_id = isset($matches[1]) ? intval($matches[1]) : 0;
2828 - if ($form_id) {
2829 - global $wpdb;
2830 - $forms_table = $wpdb->prefix . 'mxchat_forms';
2831 - $form = $wpdb->get_row($wpdb->prepare("SELECT title FROM $forms_table WHERE id = %d", $form_id));
2832 - if ($form && !empty($form->title)) {
2833 - echo esc_html($form->title);
2834 - } else {
2835 - echo esc_html($intent->intent_label);
2836 - }
2837 - } else {
2838 - echo esc_html($intent->intent_label);
2839 - }
2840 - echo ' <span class="mxchat-badge">Form Intent</span>';
2841 - } else {
2842 - echo esc_html($intent->intent_label);
2843 - }
2844 - ?>
2845 - </td>
2846 - <td class="mxchat-content-cell">
2847 - <?php echo esc_html($intent->phrases); ?>
2848 - </td>
2849 - <td><?php echo esc_html($callback_label); ?></td>
2850 - <td>
2851 - <!-- Similarity threshold adjustment (shown for all intents) -->
2852 - <form method="post"
2853 - action="<?php echo esc_url(admin_url('admin-post.php')); ?>"
2854 - class="mxchat-threshold-form">
2855 - <?php wp_nonce_field('mxchat_update_intent_threshold_nonce'); ?>
2856 - <input type="hidden" name="action"
2857 - value="mxchat_update_intent_threshold">
2858 - <input type="hidden" name="intent_id"
2859 - value="<?php echo esc_attr($intent->id); ?>">
2860 - <div class="mxchat-slider-group">
2861 - <input type="range"
2862 - name="intent_threshold"
2863 - id="intent_threshold_<?php echo esc_attr($intent->id); ?>"
2864 - min="70"
2865 - max="95"
2866 - value="<?php echo esc_attr($threshold_value); ?>"
2867 - class="mxchat-intent-slider"
2868 - oninput="document.getElementById('threshold_output_<?php echo esc_attr($intent->id); ?>').value = this.value + '%'">
2869 - <output id="threshold_output_<?php echo esc_attr($intent->id); ?>"
2870 - class="mxchat-intent-output">
2871 - <?php echo esc_html($threshold_value); ?>%
2872 - </output>
2873 - </div>
2874 - <button type="submit" class="mxchat-button-icon">
2875 - <span class="dashicons dashicons-saved"></span>
2876 - </button>
2877 - </form>
2878 - </td>
2879 - <td class="mxchat-actions-cell">
2880 - <?php if (!$is_form_intent) : ?>
2881 - <!-- Standard intents: allow edit and delete -->
2882 - <button type="button"
2883 - class="mxchat-button-icon mxchat-edit-button"
2884 - data-intent-id="<?php echo esc_attr($intent->id); ?>"
2885 - data-phrases="<?php echo esc_attr($intent->phrases); ?>">
2886 - <span class="dashicons dashicons-edit"></span>
2887 - </button>
2888 - <form method="post"
2889 - action="<?php echo esc_url(admin_url('admin-post.php')); ?>"
2890 - class="mxchat-delete-form"
2891 - onsubmit="return confirm('<?php esc_attr_e('Are you sure you want to delete this intent?', 'mxchat'); ?>');">
2892 - <?php wp_nonce_field('mxchat_delete_intent_nonce'); ?>
2893 - <input type="hidden" name="action" value="mxchat_delete_intent">
2894 - <input type="hidden" name="intent_id"
2895 - value="<?php echo esc_attr($intent->id); ?>">
2896 - <button type="submit" class="mxchat-button-icon">
2897 - <span class="dashicons dashicons-trash"></span>
2898 - </button>
2899 - </form>
2900 - <?php else : ?>
2901 - <!-- Form intents: show manage in forms button -->
2902 - <?php
2903 - preg_match('/Form (\d+)/', $intent->intent_label, $matches);
2904 - $form_id = isset($matches[1]) ? $matches[1] : '';
2905 - ?>
2906 - <a href="<?php echo esc_url(admin_url('admin.php?page=mxchat-forms&action=edit&form_id=' . $form_id)); ?>"
2907 - class="mxchat-button-secondary">
2908 - <?php esc_html_e('Manage in Forms', 'mxchat'); ?>
2909 - </a>
2910 - <?php endif; ?>
2911 - </td>
2912 - </tr>
2913 - <?php endforeach;
2914 - else : ?>
2493 + <tbody>
2494 + <?php if ($intents) :
2495 + foreach ($intents as $intent) :
2496 + $callback_function = $intent->callback_function;
2497 + $callback_label = isset($available_callbacks[$callback_function]['label'])
2498 + ? $available_callbacks[$callback_function]['label']
2499 + : $callback_function;
2500 + $threshold_value = isset($intent->similarity_threshold)
2501 + ? round($intent->similarity_threshold * 100)
2502 + : 85;
2503 + ?>
2915 2504 <tr>
2916 - <td colspan="5" class="mxchat-no-records">
2917 - <?php esc_html_e('No intents found.', 'mxchat'); ?>
2505 + <td><?php echo esc_html($intent->intent_label); ?></td>
2506 + <td class="mxchat-content-cell">
2507 + <?php echo esc_html($intent->phrases); ?>
2918 2508 </td>
2509 + <td><?php echo esc_html($callback_label); ?></td>
2510 + <td>
2511 + <form method="post"
2512 + action="<?php echo esc_url(admin_url('admin-post.php')); ?>"
2513 + class="mxchat-threshold-form">
2514 + <?php wp_nonce_field('mxchat_update_intent_threshold_nonce'); ?>
2515 + <input type="hidden" name="action"
2516 + value="mxchat_update_intent_threshold">
2517 + <input type="hidden" name="intent_id"
2518 + value="<?php echo esc_attr($intent->id); ?>">
2519 + <div class="mxchat-slider-group">
2520 + <input type="range"
2521 + name="intent_threshold"
2522 + id="intent_threshold_<?php echo esc_attr($intent->id); ?>"
2523 + min="70"
2524 + max="95"
2525 + value="<?php echo esc_attr($threshold_value); ?>"
2526 + class="mxchat-intent-slider"
2527 + oninput="document.getElementById('threshold_output_<?php echo esc_attr($intent->id); ?>').value = this.value + '%'">
2528 + <output id="threshold_output_<?php echo esc_attr($intent->id); ?>"
2529 + class="mxchat-intent-output">
2530 + <?php echo esc_html($threshold_value); ?>%
2531 + </output>
2532 + </div>
2533 + <button type="submit" class="mxchat-button-icon">
2534 + <span class="dashicons dashicons-saved"></span>
2535 + </button>
2536 + </form>
2537 + </td>
2538 + <td class="mxchat-actions-cell">
2539 + <button type="button"
2540 + class="mxchat-button-icon mxchat-edit-button"
2541 + data-intent-id="<?php echo esc_attr($intent->id); ?>"
2542 + data-phrases="<?php echo esc_attr($intent->phrases); ?>">
2543 + <span class="dashicons dashicons-edit"></span>
2544 + </button>
2545 + <form method="post"
2546 + action="<?php echo esc_url(admin_url('admin-post.php')); ?>"
2547 + class="mxchat-delete-form"
2548 + onsubmit="return confirm('<?php esc_attr_e('Are you sure you want to delete this intent?', 'mxchat'); ?>');">
2549 + <?php wp_nonce_field('mxchat_delete_intent_nonce'); ?>
2550 + <input type="hidden" name="action" value="mxchat_delete_intent">
2551 + <input type="hidden" name="intent_id"
2552 + value="<?php echo esc_attr($intent->id); ?>">
2553 + <button type="submit" class="mxchat-button-icon">
2554 + <span class="dashicons dashicons-trash"></span>
2555 + </button>
2556 + </form>
2557 + </td>
2919 2558 </tr>
2920 - <?php endif; ?>
2921 - </tbody>
2559 + <?php endforeach;
2560 + else : ?>
2561 + <tr>
2562 + <td colspan="5" class="mxchat-no-records">
2563 + <?php esc_html_e('No intents found.', 'mxchat'); ?>
2564 + </td>
2565 + </tr>
2566 + <?php endif; ?>
2567 + </tbody>
2922 2568 </table>
2923 2569 </div>
2924 2570
2925 2571 <?php if ($total_pages > 1) : ?>
@@ -2945,26 +2591,26 @@
2945 2591 <span class="mxchat-modal-close">&times;</span>
2946 2592 <div class="mxchat-card-header">
2947 2593 <h2><?php esc_html_e('Edit Intent Phrases', 'mxchat'); ?></h2>
2948 2594 </div>
2949 -
2950 - <form id="mxchat-edit-intent-form" method="post"
2595 +
2596 + <form id="mxchat-edit-intent-form" method="post"
2951 2597 action="<?php echo esc_url(admin_url('admin-post.php')); ?>">
2952 2598 <?php wp_nonce_field('mxchat_edit_intent_nonce'); ?>
2953 2599 <input type="hidden" name="action" value="mxchat_edit_intent">
2954 2600 <input type="hidden" name="intent_id" id="edit_intent_id">
2955 -
2601 +
2956 2602 <div class="mxchat-form-group">
2957 2603 <label for="edit_phrases">
2958 2604 <?php esc_html_e('Phrases (comma-separated)', 'mxchat'); ?>
2959 2605 </label>
2960 - <textarea name="phrases"
2961 - id="edit_phrases"
2962 - rows="5"
2963 - class="mxchat-intent-textarea"
2606 + <textarea name="phrases"
2607 + id="edit_phrases"
2608 + rows="5"
2609 + class="mxchat-intent-textarea"
2964 2610 required></textarea>
2965 2611 </div>
2966 -
2612 +
2967 2613 <div class="mxchat-modal-actions">
2968 2614 <button type="submit" class="mxchat-button-primary">
2969 2615 <?php esc_html_e('Update Phrases', 'mxchat'); ?>
2970 2616 </button>
@@ -3181,8 +2827,18 @@
3181 2827 'label' => __('Email Capture', 'mxchat'),
3182 2828 'pro_only' => false,
3183 2829 'group' => __('Customer Engagement', 'mxchat'),
3184 2830 ],
2831 + 'mxchat_handle_product_inquiry' => [
2832 + 'label' => __('Show Product Card', 'mxchat'),
2833 + 'pro_only' => true,
2834 + 'group' => __('WooCommerce Features', 'mxchat'),
2835 + ],
2836 + 'mxchat_handle_order_history' => [
2837 + 'label' => __('Order History', 'mxchat'),
2838 + 'pro_only' => true,
2839 + 'group' => __('WooCommerce Features', 'mxchat'),
2840 + ],
3185 2841 'mxchat_generate_image' => [
3186 2842 'label' => __('Generate Image', 'mxchat'),
3187 2843 'pro_only' => true,
3188 2844 'group' => __('Other Features', 'mxchat'),
@@ -3196,13 +2852,28 @@
3196 2852 'label' => __('Brave Image Search', 'mxchat'),
3197 2853 'pro_only' => false,
3198 2854 'group' => __('Search Features', 'mxchat'),
3199 2855 ],
2856 + 'mxchat_handle_add_to_cart_intent' => [
2857 + 'label' => __('Add to Cart', 'mxchat'),
2858 + 'pro_only' => true,
2859 + 'group' => __('WooCommerce Features', 'mxchat'),
2860 + ],
2861 + 'mxchat_handle_checkout_intent' => [
2862 + 'label' => __('Proceed to Checkout', 'mxchat'),
2863 + 'pro_only' => true,
2864 + 'group' => __('WooCommerce Features', 'mxchat'),
2865 + ],
3200 2866 'mxchat_handle_pdf_discussion' => [
3201 2867 'label' => __('Chat with PDF', 'mxchat'),
3202 2868 'pro_only' => true,
3203 2869 'group' => __('Other Features', 'mxchat'),
3204 2870 ],
2871 + 'mxchat_handle_product_recommendations' => [
2872 + 'label' => __('Product Recommendations', 'mxchat'),
2873 + 'pro_only' => true,
2874 + 'group' => __('WooCommerce Features', 'mxchat'),
2875 + ],
3205 2876 'mxchat_live_agent_handover' => [
3206 2877 'label' => __('Live Agent', 'mxchat'),
3207 2878 'pro_only' => true,
3208 2879 'group' => __('Customer Engagement', 'mxchat'),
@@ -3213,11 +2884,8 @@
3213 2884 'group' => __('Customer Engagement', 'mxchat'),
3214 2885 ],
3215 2886 ];
3216 2887
3217 - // Allow other plugins to add their callbacks
3218 - $callbacks = apply_filters('mxchat_available_callbacks', $callbacks);
3219 -
3220 2888 // Return grouped structure if requested
3221 2889 if ($grouped) {
3222 2890 $grouped_callbacks = [];
3223 2891 foreach ($callbacks as $key => $data) {
@@ -3228,12 +2896,14 @@
3228 2896 ];
3229 2897 }
3230 2898 return $grouped_callbacks;
3231 2899 }
2900 +
3232 2901 return $callbacks;
3233 2902 }
3234 2903
3235 2904
2905 +
3236 2906 private function mxchat_average_vectors($vectors) {
3237 2907 $vector_length = count($vectors[0]);
3238 2908 $sum_vector = array_fill(0, $vector_length, 0);
3239 2909
@@ -3481,9 +3151,9 @@
3481 3151 );
3482 3152
3483 3153 add_settings_field(
3484 3154 'popular_question_1',
3485 - esc_html__('Quick Question 1', 'mxchat'),
3155 + esc_html__('Popular Question 1', 'mxchat'),
3486 3156 array($this, 'mxchat_popular_question_1_callback'),
3487 3157 'mxchat-chatbot',
3488 3158 'mxchat_chatbot_section'
3489 3159 );
@@ -3489,9 +3159,9 @@
3489 3159 );
3490 3160
3491 3161 add_settings_field(
3492 3162 'popular_question_2',
3493 - esc_html__('Quick Question 2', 'mxchat'),
3163 + esc_html__('Popular Question 2', 'mxchat'),
3494 3164 array($this, 'mxchat_popular_question_2_callback'),
3495 3165 'mxchat-chatbot',
3496 3166 'mxchat_chatbot_section'
3497 3167 );
@@ -3497,9 +3167,9 @@
3497 3167 );
3498 3168
3499 3169 add_settings_field(
3500 3170 'popular_question_3',
3501 - esc_html__('Quick Question 3', 'mxchat'),
3171 + esc_html__('Popular Question 3', 'mxchat'),
3502 3172 array($this, 'mxchat_popular_question_3_callback'),
3503 3173 'mxchat-chatbot',
3504 3174 'mxchat_chatbot_section'
3505 3175 );
@@ -3505,14 +3175,21 @@
3505 3175 );
3506 3176
3507 3177 add_settings_field(
3508 3178 'additional_popular_questions',
3509 - esc_html__('Additional Quick Questions', 'mxchat'),
3179 + esc_html__('Additional Popular Questions', 'mxchat'),
3510 3180 array($this, 'mxchat_additional_popular_questions_callback'),
3511 3181 'mxchat-chatbot',
3512 3182 'mxchat_chatbot_section'
3513 3183 );
3514 3184
3185 + // WooCommerce Settings Section
3186 + add_settings_section(
3187 + 'mxchat_woocommerce_section',
3188 + esc_html__('WooCommerce Settings', 'mxchat'),
3189 + null,
3190 + 'mxchat-embed'
3191 + );
3515 3192
3516 3193 // Loops Settings Section
3517 3194 add_settings_section(
3518 3195 'mxchat_loops_section',
@@ -3520,8 +3197,33 @@
3520 3197 null,
3521 3198 'mxchat-embed'
3522 3199 );
3523 3200
3201 + // WooCommerce Settings Fields
3202 + add_settings_field(
3203 + 'enable_woocommerce_integration',
3204 + esc_html__('Automatically Embed Products', 'mxchat'),
3205 + array($this, 'mxchat_enable_woocommerce_integration_callback'),
3206 + 'mxchat-embed',
3207 + 'mxchat_woocommerce_section'
3208 + );
3209 +
3210 + add_settings_field(
3211 + 'woocommerce_consumer_key',
3212 + esc_html__('WooCommerce Consumer Key', 'mxchat'),
3213 + array($this, 'mxchat_woocommerce_consumer_key_callback'),
3214 + 'mxchat-embed',
3215 + 'mxchat_woocommerce_section'
3216 + );
3217 +
3218 + add_settings_field(
3219 + 'woocommerce_consumer_secret',
3220 + esc_html__('WooCommerce Consumer Secret', 'mxchat'),
3221 + array($this, 'mxchat_woocommerce_consumer_secret_callback'),
3222 + 'mxchat-embed',
3223 + 'mxchat_woocommerce_section'
3224 + );
3225 +
3524 3226 // Loops Settings Fields
3525 3227 add_settings_field(
3526 3228 'loops_api_key',
3527 3229 esc_html__('Loops API Key', 'mxchat'),
@@ -3716,11 +3418,162 @@
3716 3418 'mxchat-embed',
3717 3419 'mxchat_live_agent_section'
3718 3420 );
3719 3421
3422 + // Theme Settings Section
3423 + add_settings_section(
3424 + 'mxchat_theme_section',
3425 + esc_html__('Theme Settings', 'mxchat'),
3426 + null,
3427 + 'mxchat-theme'
3428 + );
3720 3429
3430 + add_settings_field(
3431 + 'close_button_color',
3432 + esc_html__('Close Button & Title Color', 'mxchat'),
3433 + array($this, 'mxchat_close_button_color_callback'),
3434 + 'mxchat-theme',
3435 + 'mxchat_theme_section'
3436 + );
3721 3437
3438 + add_settings_field(
3439 + 'chatbot_bg_color',
3440 + esc_html__('Chatbot Background Color', 'mxchat'),
3441 + array($this, 'mxchat_chatbot_bg_color_callback'),
3442 + 'mxchat-theme',
3443 + 'mxchat_theme_section'
3444 + );
3722 3445
3446 + add_settings_field(
3447 + 'user_message_bg_color',
3448 + esc_html__('User Message Background Color', 'mxchat'),
3449 + array($this, 'mxchat_user_message_bg_color_callback'),
3450 + 'mxchat-theme',
3451 + 'mxchat_theme_section'
3452 + );
3453 +
3454 + add_settings_field(
3455 + 'user_message_font_color',
3456 + esc_html__('User Message Font Color', 'mxchat'),
3457 + array($this, 'mxchat_user_message_font_color_callback'),
3458 + 'mxchat-theme',
3459 + 'mxchat_theme_section'
3460 + );
3461 +
3462 + add_settings_field(
3463 + 'bot_message_bg_color',
3464 + esc_html__('Bot Message Background Color', 'mxchat'),
3465 + array($this, 'mxchat_bot_message_bg_color_callback'),
3466 + 'mxchat-theme',
3467 + 'mxchat_theme_section'
3468 + );
3469 +
3470 + add_settings_field(
3471 + 'bot_message_font_color',
3472 + esc_html__('Bot Message Font Color', 'mxchat'),
3473 + array($this, 'mxchat_bot_message_font_color_callback'),
3474 + 'mxchat-theme',
3475 + 'mxchat_theme_section'
3476 + );
3477 +
3478 + add_settings_field(
3479 + 'top_bar_bg_color',
3480 + esc_html__('Top Bar Background Color', 'mxchat'),
3481 + array($this, 'mxchat_top_bar_bg_color_callback'),
3482 + 'mxchat-theme',
3483 + 'mxchat_theme_section'
3484 + );
3485 +
3486 + add_settings_field(
3487 + 'send_button_font_color',
3488 + esc_html__('Send Button Color', 'mxchat'),
3489 + array($this, 'mxchat_send_button_font_color_callback'),
3490 + 'mxchat-theme',
3491 + 'mxchat_theme_section'
3492 + );
3493 +
3494 + add_settings_field(
3495 + 'chat_input_font_color',
3496 + esc_html__('Chat Input Font Color', 'mxchat'),
3497 + array($this, 'mxchat_chat_input_font_color_callback'),
3498 + 'mxchat-theme',
3499 + 'mxchat_theme_section'
3500 + );
3501 +
3502 + add_settings_field(
3503 + 'chatbot_background_color',
3504 + esc_html__('Floating Widget Background Color', 'mxchat'),
3505 + array($this, 'mxchat_chatbot_background_color_callback'),
3506 + 'mxchat-theme',
3507 + 'mxchat_theme_section'
3508 + );
3509 +
3510 + add_settings_field(
3511 + 'icon_color',
3512 + esc_html__('Chatbot Icon Color', 'mxchat'),
3513 + array($this, 'mxchat_icon_color_callback'),
3514 + 'mxchat-theme',
3515 + 'mxchat_theme_section'
3516 + );
3517 +
3518 + add_settings_field(
3519 + 'custom_icon',
3520 + esc_html__('Custom Chatbot Icon (PNG)', 'mxchat'),
3521 + array($this, 'mxchat_custom_icon_callback'),
3522 + 'mxchat-theme',
3523 + 'mxchat_theme_section'
3524 + );
3525 +
3526 + add_settings_field(
3527 + 'title_icon',
3528 + esc_html__('Title Bar Icon (PNG)', 'mxchat'),
3529 + array($this, 'mxchat_title_icon_callback'),
3530 + 'mxchat-theme',
3531 + 'mxchat_theme_section'
3532 + );
3533 +
3534 + add_settings_field(
3535 + 'live_agent_message_bg_color',
3536 + esc_html__('Live Agent Background Color', 'mxchat'),
3537 + array($this, 'mxchat_live_agent_message_bg_color_callback'),
3538 + 'mxchat-theme',
3539 + 'mxchat_theme_section'
3540 + );
3541 +
3542 + add_settings_field(
3543 + 'live_agent_message_font_color',
3544 + esc_html__('Live Agent Font Color', 'mxchat'),
3545 + array($this, 'mxchat_live_agent_message_font_color_callback'),
3546 + 'mxchat-theme',
3547 + 'mxchat_theme_section'
3548 + );
3549 +
3550 + // Mode Indicator Background Color
3551 + add_settings_field(
3552 + 'mode_indicator_bg_color',
3553 + esc_html__('Mode Indicator Background Color', 'mxchat'),
3554 + array($this, 'mxchat_mode_indicator_bg_color_callback'),
3555 + 'mxchat-theme',
3556 + 'mxchat_theme_section'
3557 + );
3558 +
3559 + // Mode Indicator Font Color
3560 + add_settings_field(
3561 + 'mode_indicator_font_color',
3562 + esc_html__('Mode Indicator Font Color', 'mxchat'),
3563 + array($this, 'mxchat_mode_indicator_font_color_callback'),
3564 + 'mxchat-theme',
3565 + 'mxchat_theme_section'
3566 + );
3567 +
3568 + add_settings_field(
3569 + 'toolbar_icon_color',
3570 + esc_html__('Toolbar Icon Color', 'mxchat'),
3571 + array($this, 'mxchat_toolbar_icon_color_callback'),
3572 + 'mxchat-theme',
3573 + 'mxchat_theme_section'
3574 + );
3575 +
3723 3576 // General Settings Section
3724 3577 add_settings_section(
3725 3578 'mxchat_general_section',
3726 3579 esc_html__('Frequently Asked Questions (FAQ)', 'mxchat'),
@@ -3755,9 +3608,9 @@
3755 3608 }
3756 3609
3757 3610 /**
3758 3611 * Sanitize all prompts options
3759 - *
3612 + *
3760 3613 * @param array $input The unsanitized options array
3761 3614 * @return array The sanitized options array
3762 3615 */
3763 3616 public function sanitize_prompts_options($input) {
@@ -3762,16 +3615,16 @@
3762 3615 */
3763 3616 public function sanitize_prompts_options($input) {
3764 3617 // Log the incoming input.
3765 3618 //error_log('Sanitizing inputs: ' . print_r($input, true));
3766 -
3619 +
3767 3620 $sanitized = array();
3768 -
3621 +
3769 3622 // Boolean options
3770 3623 $sanitized['mxchat_auto_sync_posts'] = isset($input['mxchat_auto_sync_posts']) ? 1 : 0;
3771 3624 $sanitized['mxchat_auto_sync_pages'] = isset($input['mxchat_auto_sync_pages']) ? 1 : 0;
3772 3625 $sanitized['mxchat_use_pinecone'] = !empty($input['mxchat_use_pinecone']) ? 1 : 0;
3773 -
3626 +
3774 3627 // API Key: if less than 32 characters, flag as invalid.
3775 3628 $api_key = sanitize_text_field($input['mxchat_pinecone_api_key'] ?? '');
3776 3629 if (!empty($api_key) && strlen($api_key) < 32) {
3777 3630 add_settings_error(
@@ -3783,13 +3636,13 @@
3783 3636 $sanitized['mxchat_pinecone_api_key'] = $existing_options['mxchat_pinecone_api_key'] ?? '';
3784 3637 } else {
3785 3638 $sanitized['mxchat_pinecone_api_key'] = $api_key;
3786 3639 }
3787 -
3640 +
3788 3641 // Environment and Index Name
3789 3642 $sanitized['mxchat_pinecone_environment'] = sanitize_text_field($input['mxchat_pinecone_environment'] ?? '');
3790 3643 $sanitized['mxchat_pinecone_index'] = sanitize_text_field($input['mxchat_pinecone_index'] ?? '');
3791 -
3644 +
3792 3645 // Host: Remove protocol and validate format.
3793 3646 $host = sanitize_text_field($input['mxchat_pinecone_host'] ?? '');
3794 3647 $host = preg_replace('#^https?://#', '', $host);
3795 3648 //error_log('Host after removing protocol: ' . $host);
@@ -3807,11 +3660,11 @@
3807 3660 }
3808 3661 } else {
3809 3662 $sanitized['mxchat_pinecone_host'] = '';
3810 3663 }
3811 -
3664 +
3812 3665 //error_log('Final sanitized array: ' . print_r($sanitized, true));
3813 -
3666 +
3814 3667 return $sanitized;
3815 3668 }
3816 3669
3817 3670
@@ -3967,8 +3820,52 @@
3967 3820 echo '</div>';
3968 3821 }
3969 3822
3970 3823
3824 +public function mxchat_enable_woocommerce_integration_callback() {
3825 + // Load from mxchat_options array
3826 + $options = get_option('mxchat_options', []);
3827 +
3828 + // Get WooCommerce integration status with backwards compatibility
3829 + $woo_integration = isset($options['enable_woocommerce_integration'])
3830 + ? $options['enable_woocommerce_integration']
3831 + : '';
3832 +
3833 + // Support both old ('1') and new ('on') values
3834 + $checked = ($woo_integration === 'on' || $woo_integration === '1') ? 'checked' : '';
3835 +
3836 + // Check if the feature is activated (paid feature)
3837 + $disabled = $this->is_activated ? '' : 'disabled';
3838 + $class = $this->is_activated ? 'pro-feature-wrapper active' : 'pro-feature-wrapper inactive';
3839 +
3840 + echo '<div class="' . esc_attr($class) . '">';
3841 +
3842 + echo '<label class="toggle-switch">';
3843 + echo sprintf(
3844 + '<input type="checkbox" id="enable_woocommerce_integration" name="enable_woocommerce_integration" value="on" %s %s />',
3845 + esc_attr($checked),
3846 + esc_attr($disabled)
3847 + );
3848 + echo '<span class="slider"></span>';
3849 + echo '</label>';
3850 +
3851 + 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>';
3852 +
3853 + // Pro feature overlay for non-activated users
3854 + if (!$this->is_activated) {
3855 + echo '<div class="pro-feature-overlay">';
3856 + echo '<a href="https://mxchat.ai/" target="_blank">';
3857 + echo '<img src="' . esc_url(plugin_dir_url(__FILE__) . '../images/pro-only-dark.png') . '" alt="' . esc_attr__('Pro Only', 'mxchat') . '" />';
3858 + echo '</a>';
3859 + echo '</div>';
3860 + }
3861 +
3862 + echo '</div>';
3863 +}
3864 +
3865 +
3866 +
3867 +
3971 3868 private function mxchat_add_option_field($id, $title, $callback = '') {
3972 3869 add_settings_field(
3973 3870 $id,
3974 3871 __($title, 'mxchat'),
@@ -3985,9 +3882,9 @@
3985 3882
3986 3883 // Notice we changed the name to "api_key" (no array notation).
3987 3884 echo '<input type="password" id="api_key" name="api_key" value="' . $apiKey . '" class="regular-text" />';
3988 3885 echo '<button type="button" id="toggleApiKeyVisibility">' . esc_html__('Show', 'mxchat') . '</button>';
3989 - echo '<p class="description">' . wp_kses_post(__('The <strong>OpenAI API key is required even when using other models</strong> as it is used for vector embedding functionality. You must add credits to your OpenAI billing account before use.', 'mxchat')) . '</p>';
3886 + 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>';
3990 3887 }
3991 3888 public function xai_api_key_callback() {
3992 3889 // Check if the feature is activated (paid feature)
3993 3890 $disabled = $this->is_activated ? '' : 'disabled'; // Disable input if not activated
@@ -4015,15 +3912,15 @@
4015 3912 echo '</div>';
4016 3913 }
4017 3914 public function claude_api_key_callback() {
4018 3915 // Check if the feature is activated (paid feature)
4019 - $disabled = $this->is_activated ? '' : 'disabled';
4020 - $class = $this->is_activated ? 'pro-feature-wrapper active' : 'pro-feature-wrapper inactive';
4021 -
4022 - // Retrieve the Claude API key value directly like the others
3916 + $disabled = $this->is_activated ? '' : 'disabled'; // Disable input if not activated
3917 + $class = $this->is_activated ? 'pro-feature-wrapper active' : 'pro-feature-wrapper inactive'; // CSS class to style the wrapper based on activation status
3918 +
3919 + // Retrieve the Claude API key value
4023 3920 $claudeApiKey = isset($this->options['claude_api_key']) ? esc_attr($this->options['claude_api_key']) : '';
4024 -
4025 - // Use direct name field like the other working API keys
3921 +
3922 + // Render the input field for the Claude API key
4026 3923 echo '<div class="' . esc_attr($class) . '">';
4027 3924 printf(
4028 3925 '<input type="password" id="claude_api_key" name="claude_api_key" value="%s" class="regular-text" %s />',
4029 3926 $claudeApiKey,
@@ -4029,14 +3926,16 @@
4029 3926 $claudeApiKey,
4030 3927 $disabled
4031 3928 );
4032 3929 echo '<button type="button" id="toggleClaudeApiKeyVisibility">' . esc_html__('Show', 'mxchat') . '</button>';
4033 -
3930 +
3931 + // If the feature is not activated, show the overlay with a "Pro Only" message
4034 3932 if (!$this->is_activated) {
4035 3933 echo '<div class="pro-feature-overlay">';
4036 3934 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>';
4037 3935 echo '</div>';
4038 3936 }
3937 +
4039 3938 echo '</div>';
4040 3939 }
4041 3940 public function deepseek_api_key_callback() {
4042 3941 // Retrieve from your stored 'deepseek_api_key' in the mxchat_options array
@@ -4047,11 +3946,79 @@
4047 3946 echo '<button type="button" id="toggleDeepSeekApiKeyVisibility">' . esc_html__('Show', 'mxchat') . '</button>';
4048 3947 }
4049 3948
4050 3949
3950 +public function mxchat_woocommerce_consumer_key_callback() {
3951 + // Load the entire 'mxchat_options' array
3952 + $all_options = get_option('mxchat_options', []);
4051 3953
3954 + // Retrieve the WooCommerce consumer key or set a default
3955 + $consumer_key = isset($all_options['woocommerce_consumer_key']) ? $all_options['woocommerce_consumer_key'] : '';
4052 3956
3957 + // Check if the feature is activated (paid feature)
3958 + $disabled = $this->is_activated ? '' : 'disabled';
3959 + $class = $this->is_activated ? 'pro-feature-wrapper active' : 'pro-feature-wrapper inactive';
4053 3960
3961 + echo '<div class="' . esc_attr($class) . '">';
3962 +
3963 + // Render the input field
3964 + printf(
3965 + '<input type="text" id="woocommerce_consumer_key" name="woocommerce_consumer_key" value="%s" class="regular-text" %s />',
3966 + esc_attr($consumer_key),
3967 + esc_attr($disabled)
3968 + );
3969 +
3970 + // Description for the input field
3971 + echo '<p class="description">' . esc_html__('Enter your WooCommerce consumer key for integration.', 'mxchat') . '</p>';
3972 +
3973 + // Pro feature overlay for non-activated users
3974 + if (!$this->is_activated) {
3975 + echo '<div class="pro-feature-overlay">';
3976 + 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>';
3977 + echo '</div>';
3978 + }
3979 +
3980 + echo '</div>';
3981 +}
3982 +
3983 +public function mxchat_woocommerce_consumer_secret_callback() {
3984 + // Get value with fallback
3985 + $consumer_secret = isset($this->options['woocommerce_consumer_secret'])
3986 + ? esc_attr($this->options['woocommerce_consumer_secret'])
3987 + : '';
3988 +
3989 + // Check if the feature is activated (paid feature)
3990 + $disabled = $this->is_activated ? '' : 'disabled';
3991 + $class = $this->is_activated ? 'pro-feature-wrapper active' : 'pro-feature-wrapper inactive';
3992 +
3993 + echo '<div class="' . esc_attr($class) . '">';
3994 +
3995 + // Output the password input
3996 + echo sprintf(
3997 + '<input type="password"
3998 + id="woocommerce_consumer_secret"
3999 + name="woocommerce_consumer_secret"
4000 + value="%s"
4001 + class="regular-text"
4002 + %s />',
4003 + $consumer_secret,
4004 + esc_attr($disabled)
4005 + );
4006 +
4007 + // Add show/hide button
4008 + echo '<button type="button" id="toggleWooCommerceSecretVisibility">' . esc_html__('Show', 'mxchat') . '</button>';
4009 +
4010 + // Pro feature overlay
4011 + if (!$this->is_activated) {
4012 + echo '<div class="pro-feature-overlay">';
4013 + echo '<a href="https://mxchat.ai/" target="_blank">';
4014 + echo '<img src="' . esc_url(plugin_dir_url(__FILE__) . '../images/pro-only-dark.png') . '" alt="' . esc_attr__('Pro Only', 'mxchat') . '" />';
4015 + echo '</a>';
4016 + echo '</div>';
4017 + }
4018 +
4019 + echo '</div>';
4020 +}
4054 4021 public function mxchat_loops_api_key_callback() {
4055 4022 // Support both old and new format
4056 4023 $loops_api_key = isset($this->options['loops_api_key']) ? esc_attr($this->options['loops_api_key']) : '';
4057 4024
@@ -4331,8 +4298,91 @@
4331 4298 }
4332 4299
4333 4300
4334 4301
4302 +
4303 +
4304 +public function mxchat_close_button_color_callback() {
4305 + $disabled = $this->is_activated ? '' : 'disabled';
4306 + $class = $this->is_activated ? 'pro-feature-wrapper active' : 'pro-feature-wrapper inactive';
4307 +
4308 + echo '<div class="' . esc_attr($class) . '">';
4309 + echo sprintf(
4310 + '<input type="text"
4311 + id="close_button_color"
4312 + name="close_button_color"
4313 + value="%s"
4314 + class="my-color-field"
4315 + data-default-color="#4a4a4a"
4316 + %s />',
4317 + isset($this->options['close_button_color']) ? esc_attr($this->options['close_button_color']) : '#4a4a4a',
4318 + esc_attr($disabled)
4319 + );
4320 +
4321 + if (!$this->is_activated) {
4322 + echo '<div class="pro-feature-overlay">';
4323 + echo '<a href="https://mxchat.ai/" target="_blank">';
4324 + echo '<img src="' . esc_url(plugin_dir_url(__FILE__) . '../images/pro-only-dark.png') . '" alt="' . esc_attr__('Pro Only', 'mxchat') . '" />';
4325 + echo '</a>';
4326 + echo '</div>';
4327 + }
4328 + echo '</div>';
4329 +}
4330 +
4331 +public function mxchat_chatbot_bg_color_callback() {
4332 + $disabled = $this->is_activated ? '' : 'disabled';
4333 + $class = $this->is_activated ? 'pro-feature-wrapper active' : 'pro-feature-wrapper inactive';
4334 +
4335 + echo '<div class="' . esc_attr($class) . '">';
4336 + echo sprintf(
4337 + '<input type="text"
4338 + id="chatbot_bg_color"
4339 + name="chatbot_bg_color"
4340 + value="%s"
4341 + class="my-color-field"
4342 + data-default-color="#f9f9f9"
4343 + %s />',
4344 + isset($this->options['chatbot_bg_color']) ? esc_attr($this->options['chatbot_bg_color']) : '#f9f9f9',
4345 + esc_attr($disabled)
4346 + );
4347 +
4348 + if (!$this->is_activated) {
4349 + echo '<div class="pro-feature-overlay">';
4350 + echo '<a href="https://mxchat.ai/" target="_blank">';
4351 + echo '<img src="' . esc_url(plugin_dir_url(__FILE__) . '../images/pro-only-dark.png') . '" alt="' . esc_attr__('Pro Only', 'mxchat') . '" />';
4352 + echo '</a>';
4353 + echo '</div>';
4354 + }
4355 + echo '</div>';
4356 +}
4357 +
4358 +public function mxchat_user_message_bg_color_callback() {
4359 + $disabled = $this->is_activated ? '' : 'disabled';
4360 + $class = $this->is_activated ? 'pro-feature-wrapper active' : 'pro-feature-wrapper inactive';
4361 +
4362 + echo '<div class="' . esc_attr($class) . '">';
4363 + echo sprintf(
4364 + '<input type="text"
4365 + id="user_message_bg_color"
4366 + name="user_message_bg_color"
4367 + value="%s"
4368 + class="my-color-field"
4369 + data-default-color="#0078d7"
4370 + %s />',
4371 + isset($this->options['user_message_bg_color']) ? esc_attr($this->options['user_message_bg_color']) : '#0078d7',
4372 + esc_attr($disabled)
4373 + );
4374 +
4375 + if (!$this->is_activated) {
4376 + echo '<div class="pro-feature-overlay">';
4377 + echo '<a href="https://mxchat.ai/" target="_blank">';
4378 + echo '<img src="' . esc_url(plugin_dir_url(__FILE__) . '../images/pro-only-dark.png') . '" alt="' . esc_attr__('Pro Only', 'mxchat') . '" />';
4379 + echo '</a>';
4380 + echo '</div>';
4381 + }
4382 + echo '</div>';
4383 +}
4384 +
4335 4385 public function mxchat_user_message_font_color_callback() {
4336 4386 $disabled = $this->is_activated ? '' : 'disabled';
4337 4387 $class = $this->is_activated ? 'pro-feature-wrapper active' : 'pro-feature-wrapper inactive';
4338 4388
@@ -4819,20 +4869,39 @@
4819 4869 // Get complianz toggle value with fallback
4820 4870 $complianz_toggle = isset($options['complianz_toggle']) ? $options['complianz_toggle'] : 'off';
4821 4871 $checked = ($complianz_toggle === 'on') ? 'checked' : '';
4822 4872
4873 + // Check if the plugin is activated (paid feature)
4874 + $disabled = $this->is_activated ? '' : 'disabled';
4875 + $class = $this->is_activated ? 'pro-feature-wrapper active' : 'pro-feature-wrapper inactive';
4876 +
4877 + echo '<div class="' . esc_attr($class) . '">';
4878 +
4823 4879 // Output the toggle switch
4824 4880 echo '<label class="toggle-switch">';
4825 4881 echo sprintf(
4826 - '<input type="checkbox" id="complianz_toggle" name="complianz_toggle" value="on" %s />',
4827 - esc_attr($checked)
4882 + '<input type="checkbox" id="complianz_toggle" name="complianz_toggle" value="on" %s %s />',
4883 + esc_attr($checked),
4884 + esc_attr($disabled)
4828 4885 );
4829 4886 echo '<span class="slider"></span>';
4830 4887 echo '</label>';
4831 4888
4832 4889 echo '<p class="description">' . esc_html__('Enable this option to apply Complianz consent logic to the chatbot (must have Complianz Plugin).', 'mxchat') . '</p>';
4890 +
4891 + // If the feature is not activated, show the Pro feature overlay
4892 + if (!$this->is_activated) {
4893 + echo '<div class="pro-feature-overlay">';
4894 + echo '<a href="https://mxchat.ai/" target="_blank">';
4895 + echo '<img src="' . esc_url(plugin_dir_url(__FILE__) . '../images/pro-only-dark.png') . '" alt="' . esc_attr__('Pro Only', 'mxchat') . '" />';
4896 + echo '</a>';
4897 + echo '</div>';
4898 + }
4899 +
4900 + echo '</div>';
4833 4901 }
4834 4902
4903 +
4835 4904 public function mxchat_link_target_toggle_callback() {
4836 4905 // Load from mxchat_options array
4837 4906 $options = get_option('mxchat_options', []);
4838 4907
@@ -4858,20 +4927,39 @@
4858 4927 // Get chat persistence toggle value with fallback
4859 4928 $chat_persistence_toggle = isset($options['chat_persistence_toggle']) ? $options['chat_persistence_toggle'] : 'off';
4860 4929 $checked = ($chat_persistence_toggle === 'on') ? 'checked' : '';
4861 4930
4931 + // Check if the plugin is activated (paid feature)
4932 + $disabled = $this->is_activated ? '' : 'disabled';
4933 + $class = $this->is_activated ? 'pro-feature-wrapper active' : 'pro-feature-wrapper inactive';
4934 +
4935 + echo '<div class="' . esc_attr($class) . '">';
4936 +
4862 4937 // Output the toggle switch
4863 4938 echo '<label class="toggle-switch">';
4864 4939 echo sprintf(
4865 - '<input type="checkbox" id="chat_persistence_toggle" name="chat_persistence_toggle" value="on" %s />',
4866 - esc_attr($checked)
4940 + '<input type="checkbox" id="chat_persistence_toggle" name="chat_persistence_toggle" value="on" %s %s />',
4941 + esc_attr($checked),
4942 + esc_attr($disabled)
4867 4943 );
4868 4944 echo '<span class="slider"></span>';
4869 4945 echo '</label>';
4870 4946
4871 4947 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>';
4948 +
4949 + // If not activated, show Pro feature overlay
4950 + if (!$this->is_activated) {
4951 + echo '<div class="pro-feature-overlay">';
4952 + echo '<a href="https://mxchat.ai/" target="_blank">';
4953 + echo '<img src="' . esc_url(plugin_dir_url(__FILE__) . '../images/pro-only-dark.png') . '" alt="' . esc_attr__('Pro Only', 'mxchat') . '" />';
4954 + echo '</a>';
4955 + echo '</div>';
4956 + }
4957 +
4958 + echo '</div>';
4872 4959 }
4873 4960
4961 +
4874 4962 public function mxchat_popular_question_1_callback() {
4875 4963 // Load the full plugin options array
4876 4964 $all_options = get_option('mxchat_options', []);
4877 4965
@@ -4881,13 +4969,13 @@
4881 4969 // Render the input field
4882 4970 printf(
4883 4971 '<input type="text" id="popular_question_1" name="popular_question_1" value="%s" placeholder="%s" class="regular-text" />',
4884 4972 esc_attr($popular_question_1),
4885 - esc_attr__('Enter Quick Question 1', 'mxchat')
4973 + esc_attr__('Enter Popular Question 1', 'mxchat')
4886 4974 );
4887 4975
4888 4976 // Add a description for the field
4889 - echo '<p class="description">' . esc_html__('This will be the first Quick Question in the chatbot, displayed above the input field.', 'mxchat') . '</p>';
4977 + echo '<p class="description">' . esc_html__('This will be the first popular question in the chatbot.', 'mxchat') . '</p>';
4890 4978 }
4891 4979
4892 4980
4893 4981 public function mxchat_popular_question_2_callback() {
@@ -4896,38 +4984,72 @@
4896 4984
4897 4985 // Retrieve the specific option for popular_question_2
4898 4986 $popular_question_2 = isset($all_options['popular_question_2']) ? $all_options['popular_question_2'] : '';
4899 4987
4988 + // Check if the plugin is activated (paid feature)
4989 + $disabled = $this->is_activated ? '' : 'disabled';
4990 + $class = $this->is_activated ? 'pro-feature-wrapper active' : 'pro-feature-wrapper inactive';
4991 +
4992 + echo '<div class="' . esc_attr($class) . '">';
4993 +
4900 4994 // Render the input field
4901 4995 printf(
4902 - '<input type="text" id="popular_question_2" name="popular_question_2" value="%s" placeholder="%s" class="regular-text" />',
4996 + '<input type="text" id="popular_question_2" name="popular_question_2" value="%s" placeholder="%s" class="regular-text" %s />',
4903 4997 esc_attr($popular_question_2),
4904 - esc_attr__('Enter Quick Question 2', 'mxchat')
4998 + esc_attr__('Enter Popular Question 2', 'mxchat'),
4999 + esc_attr($disabled)
4905 5000 );
4906 5001
4907 5002 // Add a description for the field
4908 - echo '<p class="description">' . esc_html__('This will be the second Quick Question in the chatbot.', 'mxchat') . '</p>';
5003 + echo '<p class="description">' . esc_html__('This will be the second popular question in the chatbot.', 'mxchat') . '</p>';
5004 +
5005 + // If not activated, show Pro feature overlay
5006 + if (!$this->is_activated) {
5007 + echo '<div class="pro-feature-overlay">';
5008 + 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>';
5009 + echo '</div>';
5010 + }
5011 +
5012 + echo '</div>';
4909 5013 }
4910 5014
4911 5015
5016 +
4912 5017 public function mxchat_popular_question_3_callback() {
4913 - // Load the full plugin options array
4914 - $all_options = get_option('mxchat_options', []);
5018 + // Load the full plugin options array
5019 + $all_options = get_option('mxchat_options', []);
4915 5020
4916 - // Retrieve the specific option for popular_question_3
4917 - $popular_question_3 = isset($all_options['popular_question_3']) ? $all_options['popular_question_3'] : '';
5021 + // Retrieve the specific option for popular_question_3
5022 + $popular_question_3 = isset($all_options['popular_question_3']) ? $all_options['popular_question_3'] : '';
4918 5023
4919 - // Render the input field
4920 - printf(
4921 - '<input type="text" id="popular_question_3" name="popular_question_3" value="%s" placeholder="%s" class="regular-text" />',
4922 - esc_attr($popular_question_3),
4923 - esc_attr(__('Enter Quick Question 3', 'mxchat'))
4924 - );
5024 + // Check if the plugin is activated (paid feature)
5025 + $disabled = $this->is_activated ? '' : 'disabled';
5026 + $class = $this->is_activated ? 'pro-feature-wrapper active' : 'pro-feature-wrapper inactive';
4925 5027
4926 - // Add a description for the field
4927 - echo '<p class="description">' . esc_html__('This will be the third Quick Question in the chatbot.', 'mxchat') . '</p>';
5028 + echo '<div class="' . esc_attr($class) . '">';
5029 +
5030 + // Render the input field
5031 + printf(
5032 + '<input type="text" id="popular_question_3" name="popular_question_3" value="%s" placeholder="%s" class="regular-text" %s />',
5033 + esc_attr($popular_question_3),
5034 + esc_attr(__('Enter Popular Question 3', 'mxchat')),
5035 + esc_attr($disabled)
5036 + );
5037 +
5038 + // Add a description for the field
5039 + echo '<p class="description">' . esc_html__('This will be the third popular question in the chatbot.', 'mxchat') . '</p>';
5040 +
5041 + // If not activated, show Pro feature overlay
5042 + if (!$this->is_activated) {
5043 + echo '<div class="pro-feature-overlay">';
5044 + 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>';
5045 + echo '</div>';
5046 + }
5047 +
5048 + echo '</div>';
4928 5049 }
4929 5050
5051 +
4930 5052 public function mxchat_additional_popular_questions_callback() {
4931 5053 $options = get_option('mxchat_options', []);
4932 5054 $additional_questions = isset($options['additional_popular_questions'])
4933 5055 ? $options['additional_popular_questions']
@@ -4946,9 +5068,9 @@
4946 5068 <button type="button" class="button mxchat-remove-question"
4947 5069 aria-label="%s">%s</button>
4948 5070 </div>',
4949 5071 esc_attr($question),
4950 - esc_attr(sprintf(__('Enter Additional Quick Question %d', 'mxchat'), $index + 4)),
5072 + esc_attr(sprintf(__('Enter Additional Popular Question %d', 'mxchat'), $index + 4)),
4951 5073 $index,
4952 5074 esc_attr(__('Remove question', 'mxchat')),
4953 5075 esc_html__('Remove', 'mxchat')
4954 5076 );
@@ -4963,9 +5085,9 @@
4963 5085 data-question-index="0" />
4964 5086 <button type="button" class="button mxchat-remove-question"
4965 5087 aria-label="%s">%s</button>
4966 5088 </div>',
4967 - esc_attr(__('Enter Additional Quick Question 4', 'mxchat')),
5089 + esc_attr(__('Enter Additional Popular Question 4', 'mxchat')),
4968 5090 esc_attr(__('Remove question', 'mxchat')),
4969 5091 esc_html__('Remove', 'mxchat')
4970 5092 );
4971 5093 }
@@ -4974,9 +5096,9 @@
4974 5096 '<button type="button" class="button mxchat-add-question" aria-label="%s">%s</button>',
4975 5097 esc_attr(__('Add question', 'mxchat')),
4976 5098 esc_html__('Add Question', 'mxchat')
4977 5099 );
4978 - echo '<p class="description">' . esc_html__('Add as many Quick Questions as you need.', 'mxchat') . '</p>';
5100 + echo '<p class="description">' . esc_html__('Add as many popular questions as you need.', 'mxchat') . '</p>';
4979 5101 echo '</div>';
4980 5102 }
4981 5103
4982 5104 public function mxchat_brave_api_key_callback() {
@@ -5412,9 +5534,9 @@
5412 5534 public function mxchat_enqueue_admin_assets() {
5413 5535 wp_enqueue_style('wp-color-picker');
5414 5536
5415 5537 // Get the plugin version or file modification time for cache busting
5416 - $plugin_version = '2.0.5'; // Replace this with your plugin's version
5538 + $plugin_version = '2.0.0'; // Replace this with your plugin's version
5417 5539
5418 5540 // File paths
5419 5541 $color_picker_js_path = plugin_dir_path(__FILE__) . '../js/my-color-picker.js';
5420 5542 $embedding_check_js_path = plugin_dir_path(__FILE__) . '../js/embedding-check.js';
@@ -5420,8 +5542,9 @@
5420 5542 $embedding_check_js_path = plugin_dir_path(__FILE__) . '../js/embedding-check.js';
5421 5543 $admin_css_path = plugin_dir_path(__FILE__) . '../css/admin-style.css';
5422 5544 $knowledge_css_path = plugin_dir_path(__FILE__) . '../css/knowledge-style.css';
5423 5545 $intent_css_path = plugin_dir_path(__FILE__) . '../css/intent-style.css';
5546 + $transcripts_js_path = plugin_dir_path(__FILE__) . '../js/mxchat_transcripts.js';
5424 5547
5425 5548 // Check if files exist and get modification times
5426 5549 $color_picker_version = file_exists($color_picker_js_path) ? filemtime($color_picker_js_path) : $plugin_version;
5427 5550 $embedding_check_version = file_exists($embedding_check_js_path) ? filemtime($embedding_check_js_path) : $plugin_version;
@@ -5427,8 +5550,9 @@
5427 5550 $embedding_check_version = file_exists($embedding_check_js_path) ? filemtime($embedding_check_js_path) : $plugin_version;
5428 5551 $admin_css_version = file_exists($admin_css_path) ? filemtime($admin_css_path) : $plugin_version;
5429 5552 $knowledge_css_version = file_exists($knowledge_css_path) ? filemtime($knowledge_css_path) : $plugin_version;
5430 5553 $intent_css_version = file_exists($intent_css_path) ? filemtime($intent_css_path) : $plugin_version;
5554 + $transcripts_js_version = file_exists($transcripts_js_path) ? filemtime($transcripts_js_path) : $plugin_version;
5431 5555
5432 5556 // Enqueue scripts and styles with corrected paths
5433 5557 wp_enqueue_script(
5434 5558 'mxchat-color-picker',
@@ -5446,8 +5570,16 @@
5446 5570 true
5447 5571 );
5448 5572
5449 5573 wp_enqueue_script(
5574 + 'mxchat-transcripts-js',
5575 + plugin_dir_url(__FILE__) . '../js/mxchat_transcripts.js',
5576 + array('jquery'),
5577 + $transcripts_js_version,
5578 + true
5579 + );
5580 +
5581 + wp_enqueue_script(
5450 5582 'mxchat-admin-js',
5451 5583 plugin_dir_url(__FILE__) . '../js/mxchat-admin.js',
5452 5584 array('jquery'),
5453 5585 $plugin_version,
@@ -5458,11 +5590,10 @@
5458 5590 'ajax_url' => admin_url('admin-ajax.php'),
5459 5591 'license_nonce' => wp_create_nonce('mxchat_activate_license_nonce'),
5460 5592 'inline_edit_nonce' => wp_create_nonce('mxchat_save_inline_nonce'),
5461 5593 'setting_nonce' => wp_create_nonce('mxchat_save_setting_nonce'),
5462 - 'export_nonce' => wp_create_nonce('mxchat_export_transcripts'),
5463 5594 ));
5464 -
5595 +
5465 5596 // Enqueue the admin CSS
5466 5597 wp_enqueue_style(
5467 5598 'mxchat-admin-css',
5468 5599 plugin_dir_url(__FILE__) . '../css/admin-style.css',
@@ -5469,25 +5600,8 @@
5469 5600 array(),
5470 5601 $admin_css_version
5471 5602 );
5472 5603
5473 - if (isset($_GET['page']) && $_GET['page'] === 'mxchat-transcripts') {
5474 - wp_enqueue_style(
5475 - 'mxchat-chat-transcripts-css',
5476 - plugin_dir_url(__FILE__) . '../css/chat-transcripts.css',
5477 - array(),
5478 - $transcripts_css_version
5479 - );
5480 -
5481 - wp_enqueue_script(
5482 - 'mxchat-transcripts-js',
5483 - plugin_dir_url(__FILE__) . '../js/mxchat_transcripts.js',
5484 - array('jquery'),
5485 - $transcripts_js_version,
5486 - true
5487 - );
5488 - }
5489 -
5490 5604 wp_enqueue_style(
5491 5605 'mxchat-knowledge-css',
5492 5606 plugin_dir_url(__FILE__) . '../css/knowledge-style.css',
5493 5607 array(),
@@ -5492,10 +5606,10 @@
5492 5606 plugin_dir_url(__FILE__) . '../css/knowledge-style.css',
5493 5607 array(),
5494 5608 $knowledge_css_version
5495 5609 );
5496 -
5497 -
5610 +
5611 +
5498 5612 wp_enqueue_style(
5499 5613 'mxchat-intent-css',
5500 5614 plugin_dir_url(__FILE__) . '../css/intent-style.css',
5501 5615 array(),
@@ -5500,9 +5614,9 @@
5500 5614 plugin_dir_url(__FILE__) . '../css/intent-style.css',
5501 5615 array(),
5502 5616 $intent_css_version
5503 5617 );
5504 -
5618 +
5505 5619 // IMPORTANT: Use the same script handle as above for localizing mxchatPromptsAdmin
5506 5620 wp_localize_script( 'mxchat-admin-js', 'mxchatPromptsAdmin', array(
5507 5621 'ajax_url' => admin_url( 'admin-ajax.php' ),
5508 5622 'prompts_setting_nonce' => wp_create_nonce( 'mxchat_prompts_setting_nonce' ),
@@ -5680,8 +5794,9 @@
5680 5794 $new_input['model'] = sanitize_text_field($input['model']);
5681 5795 }
5682 5796 }
5683 5797
5798 + // Sanitize new pro features
5684 5799 if (isset($input['close_button_color'])) {
5685 5800 $new_input['close_button_color'] = sanitize_hex_color($input['close_button_color']);
5686 5801 }
5687 5802
@@ -5893,9 +6008,9 @@
5893 6008
5894 6009
5895 6010 private static function mxchat_extract_main_content($html) {
5896 6011 if (empty($html)) {
5897 - //error_log('mxchat_extract_main_content: Empty HTML content received');
6012 + error_log('mxchat_extract_main_content: Empty HTML content received');
5898 6013 return '';
5899 6014 }
5900 6015
5901 6016 try {
@@ -5900,14 +6015,14 @@
5900 6015
5901 6016 try {
5902 6017 $dom = new DOMDocument;
5903 6018 libxml_use_internal_errors(true); // Suppress HTML parsing errors
5904 -
6019 +
5905 6020 // Simple load of HTML, with @ to suppress warnings
5906 6021 @$dom->loadHTML($html, LIBXML_HTML_NOIMPLIED | LIBXML_HTML_NODEFDTD);
5907 -
6022 +
5908 6023 $xpath = new DOMXPath($dom);
5909 -
6024 +
5910 6025 // Simplified selectors focusing on common content areas
5911 6026 $selectors = [
5912 6027 '//article',
5913 6028 '//*[@id="content"]',
@@ -5913,9 +6028,9 @@
5913 6028 '//*[@id="content"]',
5914 6029 '//*[@class="entry-content"]',
5915 6030 '//main'
5916 6031 ];
5917 -
6032 +
5918 6033 foreach ($selectors as $selector) {
5919 6034 $nodes = $xpath->query($selector);
5920 6035 if ($nodes && $nodes->length > 0) {
5921 6036 $content = '';
@@ -5926,20 +6041,20 @@
5926 6041 return $content;
5927 6042 }
5928 6043 }
5929 6044 }
5930 -
6045 +
5931 6046 // Fallback: Return the entire body content if no specific selector matches
5932 6047 $body = $dom->getElementsByTagName('body');
5933 6048 if ($body->length > 0) {
5934 6049 return $dom->saveHTML($body->item(0));
5935 6050 }
5936 -
6051 +
5937 6052 // Last resort: return the original HTML
5938 6053 return $html;
5939 -
6054 +
5940 6055 } catch (Exception $e) {
5941 - //error_log('mxchat_extract_main_content error: ' . $e->getMessage());
6056 + error_log('mxchat_extract_main_content error: ' . $e->getMessage());
5942 6057 return $html; // Return original HTML if parsing fails
5943 6058 } finally {
5944 6059 libxml_clear_errors();
5945 6060 }