PluginProbe
MxChat – AI Chatbot & Content Generation for WordPress / 2.1.1
MxChat – AI Chatbot & Content Generation for WordPress v2.1.1
3.2.21 3.2.20 3.2.19 3.2.18 3.2.17 3.2.16 3.2.15 3.2.14 3.2.12 3.2.13 3.2.11 3.2.10 3.2.9 3.2.8 3.2.7 3.2.6 3.2.5 3.2.4 3.2.3 3.2.2 3.2.1 2.0.3 2.0.4 2.0.5 2.0.6 All 152 releases
← All changes | includes/class-mxchat-admin.php +1324 -677 2.0.32.1.1 View file →
@@ -45,8 +45,9 @@
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 47 add_action('wp_trash_post', array($this, 'mxchat_handle_post_delete'));
48 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'));
49 50 add_action('wp_ajax_mxchat_save_prompts_setting', array($this, 'mxchat_save_prompts_setting_callback'));
50 51 if (isset($this->options['enable_woocommerce_integration']) &&
51 52 ($this->options['enable_woocommerce_integration'] === '1' ||
52 53 $this->options['enable_woocommerce_integration'] === 'on')) {
@@ -55,8 +56,12 @@
55 56 add_action('wp_insert_post', array($this, 'mxchat_handle_product_change'), 10, 3);
56 57 add_action('wp_trash_post', array($this, 'mxchat_handle_product_delete'));
57 58 add_action('before_delete_post', array($this, 'mxchat_handle_product_delete'));
58 59 }
60 +
61 + add_action('wp_ajax_mxchat_get_status_updates', array($this, 'ajax_get_status_updates'));
62 + add_action('admin_notices', array($this, 'display_admin_notices'));
63 +
59 64 }
60 65
61 66 // Method to check if the license is active
62 67 private function is_license_active() {
@@ -70,8 +75,10 @@
70 75 'api_key' => '',
71 76 'xai_api_key' => '',
72 77 'claude_api_key' => '',
73 78 'deepseek_api_key' => '',
79 + 'voyage_api_key' => '',
80 + 'embedding_model' => 'text-embedding-ada-002',
74 81 '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:
75 82 - Your name is [Chatbot Name].
76 83 - 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.
77 84 - 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.
@@ -114,8 +121,10 @@
114 121 'pdf_intent_trigger_text' => esc_html__("Please provide the URL to the PDF you'd like to discuss.", 'mxchat'),
115 122 'pdf_intent_success_text' => esc_html__("I've processed the PDF. What questions do you have about it?", 'mxchat'),
116 123 'pdf_intent_error_text' => esc_html__("Sorry, I couldn't process the PDF. Please ensure it's a valid file.", 'mxchat'),
117 124 'pdf_max_pages' => 69,
125 + 'show_pdf_upload_button' => 'on',
126 + 'show_word_upload_button' => 'on',
118 127
119 128 // Live Agent Integration
120 129 'live_agent_webhook_url' => '',
121 130 'live_agent_secret_key' => '',
@@ -173,26 +182,24 @@
173 182 'mxchat-prompts',
174 183 array($this, 'mxchat_create_prompts_page')
175 184 );
176 185
177 - // Submenu page for Chat Transcripts
178 186 add_submenu_page(
179 - 'mxchat-max', // Corrected parent slug to match the main menu
187 + 'mxchat-max',
180 188 esc_html__('Chat Transcripts', 'mxchat'),
181 189 esc_html__('Transcripts', 'mxchat'),
182 190 'manage_options',
183 191 'mxchat-transcripts',
184 - array($this, 'mxchat_create_transcripts_page') // Prefixed function name with mxchat_
192 + array($this, 'mxchat_create_transcripts_page')
185 193 );
186 194
187 - // Submenu page for Intents
188 195 add_submenu_page(
189 - 'mxchat-max', // Parent slug
190 - esc_html__('MxChat Intents', 'mxchat'), // Page title
191 - esc_html__('Intents', 'mxchat'), // Menu title
192 - 'manage_options', // Capability
193 - 'mxchat-intents', // Menu slug
194 - array($this, 'mxchat_intents_page_html') // Callback function
196 + 'mxchat-max',
197 + esc_html__('MxChat Intents', 'mxchat'),
198 + esc_html__('Intents', 'mxchat'),
199 + 'manage_options',
200 + 'mxchat-intents',
201 + array($this, 'mxchat_intents_page_html')
195 202 );
196 203
197 204 add_submenu_page(
198 205 'mxchat-max',
@@ -224,16 +231,20 @@
224 231 check_ajax_referer('mxchat_save_setting_nonce');
225 232 if (!current_user_can('manage_options')) {
226 233 wp_send_json_error(['message' => esc_html__('Unauthorized', 'mxchat')]);
227 234 }
235 +
228 236 $name = isset($_POST['name']) ? $_POST['name'] : '';
229 237 // Strip slashes from the value before saving
230 238 $value = isset($_POST['value']) ? stripslashes($_POST['value']) : '';
239 +
231 240 if (empty($name)) {
232 241 wp_send_json_error(['message' => esc_html__('Invalid field name', 'mxchat')]);
233 242 }
243 +
234 244 // Load the full options array
235 245 $options = get_option('mxchat_options', []);
246 +
236 247 // Handle special cases
237 248 switch ($name) {
238 249 case 'additional_popular_questions':
239 250 $questions = json_decode($value, true); // No need for stripslashes here
@@ -242,8 +253,12 @@
242 253 // Also update old option for backwards compatibility
243 254 update_option('additional_popular_questions', $questions);
244 255 }
245 256 break;
257 + case 'similarity_threshold':
258 + // Save to the options array
259 + $options[$name] = $value;
260 + break;
246 261 case 'user_message_bg_color':
247 262 case 'user_message_font_color':
248 263 case 'bot_message_bg_color':
249 264 case 'bot_message_font_color':
@@ -288,9 +303,11 @@
288 303 if (strpos($name, 'toggle') !== false || in_array($name, [
289 304 'chat_persistence_toggle',
290 305 'privacy_toggle',
291 306 'complianz_toggle',
292 - 'chat_toolbar_toggle' // Removed live_agent_status from here
307 + 'chat_toolbar_toggle',
308 + 'show_pdf_upload_button',
309 + 'show_word_upload_button'
293 310 ])) {
294 311 $options[$name] = ($value === 'on') ? 'on' : 'off';
295 312 } else {
296 313 // Store all other values directly
@@ -297,17 +314,12 @@
297 314 $options[$name] = $value;
298 315 }
299 316 break;
300 317 }
301 - // Save all updates
318 +
319 + // Save all updates to the options array
302 320 $updated = update_option('mxchat_options', $options);
303 - // Handle backwards compatibility for certain fields
304 - $legacy_fields = ['brave_api_key', 'brave_image_count', 'brave_safe_search', 'brave_news_count',
305 - 'brave_country', 'brave_language', 'similarity_threshold'];
306 - if (in_array($name, $legacy_fields)) {
307 - // Also update the individual option for backwards compatibility
308 - update_option($name, $value);
309 - }
321 +
310 322 if ($updated) {
311 323 wp_send_json_success(['message' => esc_html__('Setting saved', 'mxchat')]);
312 324 } else {
313 325 wp_send_json_error(['message' => esc_html__('Update failed or no changes', 'mxchat')]);
@@ -312,9 +324,8 @@
312 324 } else {
313 325 wp_send_json_error(['message' => esc_html__('Update failed or no changes', 'mxchat')]);
314 326 }
315 327 }
316 -
317 328 /**
318 329 * Handles AJAX auto-save for prompts and auto-sync settings.
319 330 */
320 331 public function mxchat_save_prompts_setting_callback() {
@@ -398,188 +409,215 @@
398 409
399 410 public function mxchat_create_admin_page() {
400 411
401 412 ?>
402 - <div class="wrap mxchat-admin">
403 - <?php if (!$this->is_activated): ?>
404 - <div class="mxchat-pro-banner">
405 - <p>
406 - <?php echo esc_html__('For a limited time, get lifetime access and save $20 on MxChat Pro!', 'mxchat'); ?>
407 - <a href="https://mxchat.ai/" target="_blank"><?php echo esc_html__('Upgrade to Pro today', 'mxchat'); ?></a>
408 - </p>
413 + <div class="wrap mxchat-wrapper">
414 + <!-- Hero Section -->
415 + <div class="mxchat-hero">
416 + <h1 class="mxchat-main-title">
417 + <span class="mxchat-gradient-text">MxChat</span> Settings
418 + </h1>
419 + <p class="mxchat-hero-subtitle">
420 + <?php esc_html_e('Configure your AI chatbot, manage integrations and explore tutorials to get the most out of MxChat.', 'mxchat'); ?>
421 + </p>
409 422 </div>
410 - <?php endif; ?>
411 423
412 - <div class="mxchat-agents-banner">
413 - <p>
414 - <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'); ?>
415 - </p>
416 - </div>
424 + <div class="mxchat-content">
425 + <?php if (!$this->is_activated): ?>
426 + <div class="mxchat-pro-card">
427 + <div class="mxchat-pro-notification">
428 + <div class="mxchat-pro-content">
429 + <h3>🚀 Limited Time Offer: Save $20 on MxChat Pro Lifetime Access!</h3>
430 + <p>Unlock <strong>unlimited access</strong> to our growing collection of powerful add-ons including Forms Builder, Theme Customizer, WooCommerce, Perplexity, and more – all included with your lifetime license!</p>
431 + </div>
432 + <div class="mxchat-pro-cta">
433 + <a href="https://mxchat.ai/" target="_blank" class="mxchat-button"><?php echo esc_html__('Upgrade to Pro Today', 'mxchat'); ?></a>
434 + <a href="<?php echo admin_url('admin.php?page=mxchat-addons'); ?>" class="mxchat-link"><?php echo esc_html__('Preview Add-ons', 'mxchat'); ?></a>
435 + </div>
436 + </div>
437 + </div>
438 + <?php endif; ?>
417 439
418 - <h2 class="mxchat-nav-tab-wrapper">
419 - <a href="#chatbot" class="mxchat-nav-tab mxchat-nav-tab-active" data-tab="chatbot"><?php echo esc_html__('Chatbot', 'mxchat'); ?></a>
420 - <a href="#embed" class="mxchat-nav-tab" data-tab="embed"><?php echo esc_html__('Integrations', 'mxchat'); ?></a>
421 - <a href="#general" class="mxchat-nav-tab" data-tab="general"><?php echo esc_html__('FAQ', 'mxchat'); ?></a>
422 - </h2>
423 -
424 - <div id="chatbot" class="mxchat-tab-content active">
425 - <div class="mxchat-autosave-section">
426 - <?php do_settings_sections('mxchat-chatbot'); ?>
440 + <!-- Tabs Navigation -->
441 + <div class="mxchat-tabs">
442 + <button class="mxchat-tab-button active" data-tab="chatbot"><?php echo esc_html__('Chatbot', 'mxchat'); ?></button>
443 + <button class="mxchat-tab-button" data-tab="embed"><?php echo esc_html__('Integrations', 'mxchat'); ?></button>
444 + <button class="mxchat-tab-button" data-tab="general"><?php echo esc_html__('YouTube Tutorials', 'mxchat'); ?></button>
427 445 </div>
428 - </div>
429 446
430 - <div id="embed" class="mxchat-tab-content">
431 - <div class="mxchat-autosave-section">
432 - <div class="mxchat-settings-section">
433 - <h2><?php echo esc_html__('WooCommerce Settings', 'mxchat'); ?></h2>
434 - <table class="form-table">
435 - <?php do_settings_fields('mxchat-embed', 'mxchat_woocommerce_section'); ?>
436 - </table>
447 + <!-- Tab Contents -->
448 + <div id="chatbot" class="mxchat-tab-content active">
449 + <div class="mxchat-card">
450 + <div class="mxchat-autosave-section">
451 + <?php do_settings_sections('mxchat-chatbot'); ?>
452 + </div>
437 453 </div>
438 - <div class="section-divider"></div>
454 + </div>
439 455
440 - <div class="mxchat-settings-section">
441 - <h2><?php echo esc_html__('Loops Settings', 'mxchat'); ?></h2>
442 - <table class="form-table">
443 - <?php do_settings_fields('mxchat-embed', 'mxchat_loops_section'); ?>
444 - </table>
456 + <div id="embed" class="mxchat-tab-content">
457 + <div class="mxchat-card">
458 + <h2><?php esc_html_e('Loops Settings', 'mxchat'); ?></h2>
459 + <div class="mxchat-autosave-section">
460 + <table class="form-table">
461 + <?php do_settings_fields('mxchat-embed', 'mxchat_loops_section'); ?>
462 + </table>
463 + </div>
445 464 </div>
446 465
447 - <div class="section-divider"></div>
448 -
449 - <div class="mxchat-settings-section">
450 - <h2><?php echo esc_html__('Brave Search Settings', 'mxchat'); ?></h2>
451 - <table class="form-table">
452 - <?php do_settings_fields('mxchat-embed', 'mxchat_brave_section'); ?>
453 - </table>
466 + <div class="mxchat-card">
467 + <h2><?php esc_html_e('Brave Search Settings', 'mxchat'); ?></h2>
468 + <div class="mxchat-autosave-section">
469 + <table class="form-table">
470 + <?php do_settings_fields('mxchat-embed', 'mxchat_brave_section'); ?>
471 + </table>
472 + </div>
454 473 </div>
455 474
456 - <div class="section-divider"></div>
457 -
458 - <div class="mxchat-settings-section">
459 - <h2><?php echo esc_html__('Toolbar Settings & Intents', 'mxchat'); ?></h2>
460 - <table class="form-table">
461 - <?php do_settings_fields('mxchat-embed', 'mxchat_pdf_intent_section'); ?>
462 - </table>
475 + <div class="mxchat-card">
476 + <h2><?php esc_html_e('Toolbar Settings & Intents', 'mxchat'); ?></h2>
477 + <div class="mxchat-autosave-section">
478 + <table class="form-table">
479 + <?php do_settings_fields('mxchat-embed', 'mxchat_pdf_intent_section'); ?>
480 + </table>
481 + </div>
463 482 </div>
464 483
465 - <div class="section-divider"></div>
466 -
467 - <!-- Live Agent Settings Section -->
468 - <div class="mxchat-settings-section">
469 - <h2><?php echo esc_html__('Live Agent Settings', 'mxchat'); ?></h2>
470 - <p><?php echo esc_html__('Visit our', 'mxchat'); ?> <a href="https://mxchat.ai/documentation/#slack_integration" target="_blank"><?php echo esc_html__('documentation page', 'mxchat'); ?></a> <?php echo esc_html__('to set up live agent transfer via Slack.', 'mxchat'); ?></p>
471 - <table class="form-table">
472 - <?php do_settings_fields('mxchat-embed', 'mxchat_live_agent_section'); ?>
473 - </table>
484 + <div class="mxchat-card">
485 + <h2><?php esc_html_e('Live Agent Settings', 'mxchat'); ?></h2>
486 + <div class="mxchat-autosave-section">
487 + <p><?php echo esc_html__('Visit our', 'mxchat'); ?> <a href="https://mxchat.ai/documentation/#slack_integration" target="_blank"><?php echo esc_html__('documentation page', 'mxchat'); ?></a> <?php echo esc_html__('to set up live agent transfer via Slack.', 'mxchat'); ?></p>
488 + <table class="form-table">
489 + <?php do_settings_fields('mxchat-embed', 'mxchat_live_agent_section'); ?>
490 + </table>
491 + </div>
474 492 </div>
475 493 </div>
476 - </div>
477 494
495 + <div id="general" class="mxchat-tab-content">
496 + <div class="mxchat-card">
497 + <?php do_settings_sections('mxchat-general'); ?>
498 + <div class="video-tutorials-section">
478 499
479 - <div id="general" class="mxchat-tab-content">
480 - <?php do_settings_sections('mxchat-general'); ?>
481 - <p>
482 - <?php echo esc_html__('If you’re having trouble with setup or getting the responses you need, we encourage you to review our', 'mxchat'); ?>
483 - <a href="https://mxchat.ai/documentation/" target="_blank" rel="noopener noreferrer"><?php echo esc_html__('documentation', 'mxchat'); ?></a> <?php echo esc_html__('or', 'mxchat'); ?>
484 - <a href="https://wordpress.org/support/plugin/mxchat-basic/" target="_blank" rel="noopener noreferrer"><?php echo esc_html__('create a support ticket', 'mxchat'); ?></a>.
485 - </p>
486 - <p>
487 - <?php echo esc_html__('If you like our plugin, please consider', 'mxchat'); ?> <a href="https://wordpress.org/plugins/mxchat-basic/#reviews" target="_blank" rel="noopener noreferrer"><?php echo esc_html__('leaving us a review', 'mxchat'); ?></a>.
488 - </p>
489 -
490 - <div class="faq-item">
491 - <h3><?php echo esc_html__('How does the Claude API integration work?', 'mxchat'); ?></h3>
492 - <p>
493 - <?php echo esc_html__('The Claude API, provided by Anthropic, allows for intelligent, context-aware chatbot responses in MxChat. To use it, you will need both an OpenAI API key and a Claude API key. This is necessary because the system utilizes OpenAI for vector embedding in the Retrieval-Augmented Generation (RAG) process, as Claude does not currently offer an embedding API.', 'mxchat'); ?>
494 - </p>
495 - <p>
496 - <?php echo esc_html__('When using the Claude API, your custom content is sent to Claude for generating responses, while the embeddings are processed through OpenAI. This ensures your chatbot provides accurate and engaging responses while maintaining knowledge relevant to your website.', 'mxchat'); ?>
497 - </p>
498 - <p>
499 - <?php echo esc_html__('You can obtain your Claude API key by signing up on the', 'mxchat'); ?> <a href="https://www.anthropic.com/api" target="_blank" rel="noopener"><?php echo esc_html__('Anthropic API page', 'mxchat'); ?></a>.
500 - </p>
500 + <div class="tutorial-grid">
501 + <div class="tutorial-item">
502 + <h3><?php echo esc_html__('MxChat Forms Tutorial', 'mxchat'); ?></h3>
503 + <div class="video-description">
504 + <p><?php echo esc_html__('Learn how to create and manage smart forms that automatically trigger during chat conversations.', 'mxchat'); ?></p>
505 + <a href="https://www.youtube.com/watch?v=3MrWy5dRalA" target="_blank" rel="noopener" class="video-link">
506 + <span class="video-icon"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M12 19c-2.3 0-6.4-.2-8.1-.6-.7-.2-1.2-.7-1.4-1.4-.3-1.1-.5-3.4-.5-5s.2-3.9.5-5c.2-.7.7-1.2 1.4-1.4C5.6 5.2 9.7 5 12 5s6.4.2 8.1.6c.7.2 1.2.7 1.4 1.4.3 1.1.5 3.4.5 5s-.2 3.9-.5 5c-.2.7-.7 1.2-1.4 1.4-1.7.4-5.8.6-8.1.6z"></path><polygon points="10 15 15 12 10 9 10 15"></polygon></svg></span>
507 + <?php echo esc_html__('Watch MxChat Forms Tutorial', 'mxchat'); ?>
508 + </a>
501 509 </div>
510 + </div>
502 511
503 - <div class="faq-item">
504 - <h3><?php echo esc_html__('How does the X.AI API integration work?', 'mxchat'); ?></h3>
505 - <p>
506 - <?php echo esc_html__('The X.AI API, released on 10.21.24, is currently in beta. To use it, you will need both an OpenAI API key and an X.AI API key. This is because OpenAI handles vector embeddings in the Retrieval-Augmented Generation (RAG) process, as X.AI does not yet provide an embedding API.', 'mxchat'); ?>
507 - </p>
508 - <p>
509 - <?php echo esc_html__('Custom content is sent to the X.AI API for generating responses, while OpenAI processes the embeddings. This allows the chatbot to provide advanced responses while maintaining context from your website. You can get your X.AI API key from the', 'mxchat'); ?> <a href="https://docs.x.ai/docs" target="_blank" rel="noopener"><?php echo esc_html__('X.AI API documentation', 'mxchat'); ?></a>.
510 - </p>
512 + <div class="tutorial-item">
513 + <h3><?php echo esc_html__('Intent Tester Guide', 'mxchat'); ?></h3>
514 + <div class="video-description">
515 + <p><?php echo esc_html__('Discover how to use the Intent Tester to fine-tune your chatbot\'s responses and ensure it accurately understands user queries.', 'mxchat'); ?></p>
516 + <a href="https://www.youtube.com/watch?v=uTr14tn59Hc" target="_blank" rel="noopener" class="video-link">
517 + <span class="video-icon"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M12 19c-2.3 0-6.4-.2-8.1-.6-.7-.2-1.2-.7-1.4-1.4-.3-1.1-.5-3.4-.5-5s.2-3.9.5-5c.2-.7.7-1.2 1.4-1.4C5.6 5.2 9.7 5 12 5s6.4.2 8.1.6c.7.2 1.2.7 1.4 1.4.3 1.1.5 3.4.5 5s-.2 3.9-.5 5c-.2.7-.7 1.2-1.4 1.4-1.7.4-5.8.6-8.1.6z"></path><polygon points="10 15 15 12 10 9 10 15"></polygon></svg></span>
518 + <?php echo esc_html__('Watch Intent Tester Tutorial', 'mxchat'); ?>
519 + </a>
511 520 </div>
521 + </div>
512 522
513 - <div class="faq-item">
514 - <h3><?php echo esc_html__('Do I need an OpenAI API key to use the chatbot?', 'mxchat'); ?></h3>
515 - <p>
516 - <?php echo esc_html__('Yes, you will need an OpenAI API key to power the chatbot. You can obtain an API key by signing up on the', 'mxchat'); ?> <a href="https://platform.openai.com/signup" target="_blank" rel="noopener"><?php echo esc_html__('OpenAI platform', 'mxchat'); ?></a>. <?php echo esc_html__('After signing up, you must add credits to your account—typically, $5 in credits is sufficient to get started.', 'mxchat'); ?>
517 - </p>
518 - <p>
519 - <?php echo esc_html__('Once you have your API key, simply enter it in the chatbot\'s settings to enable functionality. The chatbot relies on OpenAI’s models for generating responses, so having sufficient credits in your OpenAI account is essential for smooth operation.', 'mxchat'); ?>
520 - </p>
523 + <div class="tutorial-item">
524 + <h3><?php echo esc_html__('WooCommerce Integration', 'mxchat'); ?></h3>
525 + <div class="video-description">
526 + <p><?php echo esc_html__('See how to integrate MxChat with your WooCommerce store to provide product recommendations and shopping assistance to your customers.', 'mxchat'); ?></p>
527 + <a href="https://www.youtube.com/watch?v=WsqAppHRGdA" target="_blank" rel="noopener" class="video-link">
528 + <span class="video-icon"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M12 19c-2.3 0-6.4-.2-8.1-.6-.7-.2-1.2-.7-1.4-1.4-.3-1.1-.5-3.4-.5-5s.2-3.9.5-5c.2-.7.7-1.2 1.4-1.4C5.6 5.2 9.7 5 12 5s6.4.2 8.1.6c.7.2 1.2.7 1.4 1.4.3 1.1.5 3.4.5 5s-.2 3.9-.5 5c-.2.7-.7 1.2-1.4 1.4-1.7.4-5.8.6-8.1.6z"></path><polygon points="10 15 15 12 10 9 10 15"></polygon></svg></span>
529 + <?php echo esc_html__('Watch WooCommerce Integration Tutorial', 'mxchat'); ?>
530 + </a>
521 531 </div>
532 + </div>
522 533
523 - <div class="faq-item">
524 - <h3><?php echo esc_html__('How do I add the chatbot to my site?', 'mxchat'); ?></h3>
525 - <p>
526 - <?php echo esc_html__('You can add the chatbot using the shortcode', 'mxchat'); ?> <code>[mxchat_chatbot floating="yes"]</code> <?php echo esc_html__('or', 'mxchat'); ?> <code>[mxchat_chatbot floating="no"]</code>. <?php echo esc_html__('For initial testing and styling, it\'s best to use the shortcode on a draft or non-public page. Once you’re ready to go live, enable the “Append Chat Widget to Body” option in the settings for site-wide integration (recommended) or add shortcode to the footer.', 'mxchat'); ?>
527 - </p>
534 + <div class="tutorial-item">
535 + <h3><?php echo esc_html__('Knowledge Base Setup', 'mxchat'); ?></h3>
536 + <div class="video-description">
537 + <p><?php echo esc_html__('Learn how to set up your knowledge base using PDFs, sitemaps, and manual entries to enhance your chatbot\'s responses with site-specific information.', 'mxchat'); ?></p>
538 + <p><small><?php echo esc_html__('Note: This tutorial uses an older UI, but the process remains the same.', 'mxchat'); ?></small></p>
539 + <a href="https://www.youtube.com/watch?v=8Ztjs66-VTo" target="_blank" rel="noopener" class="video-link">
540 + <span class="video-icon"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M12 19c-2.3 0-6.4-.2-8.1-.6-.7-.2-1.2-.7-1.4-1.4-.3-1.1-.5-3.4-.5-5s.2-3.9.5-5c.2-.7.7-1.2 1.4-1.4C5.6 5.2 9.7 5 12 5s6.4.2 8.1.6c.7.2 1.2.7 1.4 1.4.3 1.1.5 3.4.5 5s-.2 3.9-.5 5c-.2.7-.7 1.2-1.4 1.4-1.7.4-5.8.6-8.1.6z"></path><polygon points="10 15 15 12 10 9 10 15"></polygon></svg></span>
541 + <?php echo esc_html__('Watch Knowledge Base Setup Tutorial', 'mxchat'); ?>
542 + </a>
528 543 </div>
544 + </div>
529 545
530 - <div class="faq-item">
531 - <h3><?php echo esc_html__('How does the chatbot use my content to generate responses?', 'mxchat'); ?></h3>
532 - <p>
533 - <?php echo esc_html__('The chatbot uses AI and vector embeddings to connect users with relevant information. When you submit content, it converts it into a mathematical format. When a user asks a question, the bot matches it to your stored content and generates a response based on relevance. For example, submitting "Our phone number is 910-123-4567" allows the bot to retrieve this information when asked about contact details. To ensure related information is provided together, submit it in one entry.', 'mxchat'); ?>
534 - </p>
546 + <div class="tutorial-item">
547 + <h3><?php echo esc_html__('Toolbar Chat with Documents', 'mxchat'); ?></h3>
548 + <div class="video-description">
549 + <p><?php echo esc_html__('See how to use the MxChat toolbar to chat with PDF and Word documents for enhanced document analysis and information retrieval.', 'mxchat'); ?></p>
550 + <a href="https://www.youtube.com/watch?v=j_c45WWCTG0" target="_blank" rel="noopener" class="video-link">
551 + <span class="video-icon"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M12 19c-2.3 0-6.4-.2-8.1-.6-.7-.2-1.2-.7-1.4-1.4-.3-1.1-.5-3.4-.5-5s.2-3.9.5-5c.2-.7.7-1.2 1.4-1.4C5.6 5.2 9.7 5 12 5s6.4.2 8.1.6c.7.2 1.2.7 1.4 1.4.3 1.1.5 3.4.5 5s-.2 3.9-.5 5c-.2.7-.7 1.2-1.4 1.4-1.7.4-5.8.6-8.1.6z"></path><polygon points="10 15 15 12 10 9 10 15"></polygon></svg></span>
552 + <?php echo esc_html__('Watch Document Chat Tutorial', 'mxchat'); ?>
553 + </a>
535 554 </div>
536 -
537 - <div class="faq-item">
538 - <h3><?php echo esc_html__('Why does the chatbot sometimes make up links or information?', 'mxchat'); ?></h3>
539 - <p>
540 - <?php echo esc_html__('Occasionally, the chatbot may generate inaccurate links or information, known as "hallucinations." To minimize this, you can add system instructions to guide its behavior. For example, include an instruction like: "Only provide links you directly have access to or retrieve from the knowledge base. Do not make up links or information that you do not have direct access to." This helps the bot stay aligned with your content.', 'mxchat'); ?>
541 - </p>
555 + </div>
556 +
557 + <div class="tutorial-item">
558 + <h3><?php echo esc_html__('Perplexity Integration', 'mxchat'); ?></h3>
559 + <div class="video-description">
560 + <p><?php echo esc_html__('Learn how to integrate Perplexity with your chatbot for real-time web search capabilities. This tutorial covers intent recognition, the toolbar toggle button, and how to enable your chatbot to search the web and provide up-to-date information to your visitors.', 'mxchat'); ?></p>
561 + <a href="https://youtu.be/wpKkbt24-bo" target="_blank" rel="noopener" class="video-link">
562 + <span class="video-icon"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M12 19c-2.3 0-6.4-.2-8.1-.6-.7-.2-1.2-.7-1.4-1.4-.3-1.1-.5-3.4-.5-5s.2-3.9.5-5c.2-.7.7-1.2 1.4-1.4C5.6 5.2 9.7 5 12 5s6.4.2 8.1.6c.7.2 1.2.7 1.4 1.4.3 1.1.5 3.4.5 5s-.2 3.9-.5 5c-.2.7-.7 1.2-1.4 1.4-1.7.4-5.8.6-8.1.6z"></path><polygon points="10 15 15 12 10 9 10 15"></polygon></svg></span>
563 + <?php echo esc_html__('Watch Perplexity Integration Tutorial', 'mxchat'); ?>
564 + </a>
542 565 </div>
566 + </div>
543 567
544 - <div class="faq-item">
545 - <h3><?php echo esc_html__('How do intents work in MxChat?', 'mxchat'); ?></h3>
546 - <p>
547 - <?php echo esc_html__('Intents allow MxChat to recognize user requests and trigger specific actions, such as capturing emails or displaying product information. This helps provide a more interactive and responsive experience. For a detailed explanation of each intent, please refer to our', 'mxchat'); ?> <a href="https://mxchat.ai/documentation/#intents" target="_blank" rel="noopener noreferrer"><?php echo esc_html__('Intents Documentation', 'mxchat'); ?></a>.
548 - </p>
568 + <div class="tutorial-item">
569 + <h3><?php echo esc_html__('Brave Search Intent', 'mxchat'); ?></h3>
570 + <div class="video-description">
571 + <p><?php echo esc_html__('Learn how to leverage Brave Search intent capabilities to improve your chatbot\'s understanding of user queries and provide more accurate responses.', 'mxchat'); ?></p>
572 + <a href="https://www.youtube.com/watch?v=7vDL5H7vToc" target="_blank" rel="noopener" class="video-link">
573 + <span class="video-icon"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M12 19c-2.3 0-6.4-.2-8.1-.6-.7-.2-1.2-.7-1.4-1.4-.3-1.1-.5-3.4-.5-5s.2-3.9.5-5c.2-.7.7-1.2 1.4-1.4C5.6 5.2 9.7 5 12 5s6.4.2 8.1.6c.7.2 1.2.7 1.4 1.4.3 1.1.5 3.4.5 5s-.2 3.9-.5 5c-.2.7-.7 1.2-1.4 1.4-1.7.4-5.8.6-8.1.6z"></path><polygon points="10 15 15 12 10 9 10 15"></polygon></svg></span>
574 + <?php echo esc_html__('Watch Brave Search Intent Tutorial', 'mxchat'); ?>
575 + </a>
549 576 </div>
577 + </div>
550 578
551 - <div class="faq-item">
552 - <h3><?php echo esc_html__('How does the Complianz integration work?', 'mxchat'); ?></h3>
553 - <p>
554 - <?php echo esc_html__('The Pro version offers direct integration with the Complianz GDPR plugin, making it easy to stay compliant with GDPR. If Complianz is enabled on your website, users must accept consent before the chatbot widget appears. The chatbot will only display once the user has accepted, ensuring compliance with data privacy regulations.', 'mxchat'); ?>
555 - </p>
579 + <div class="tutorial-item">
580 + <h3><?php echo esc_html__('Loops Email Capture', 'mxchat'); ?></h3>
581 + <div class="video-description">
582 + <p><?php echo esc_html__('Discover how to set up email capture with MxChat using Loops to grow your mailing list while providing value through your chatbot.', 'mxchat'); ?></p>
583 + <p><small><?php echo esc_html__('Note: This tutorial uses an older UI, but the process remains the same.', 'mxchat'); ?></small></p>
584 + <a href="https://www.youtube.com/watch?v=CNgm5TYDyTc" target="_blank" rel="noopener" class="video-link">
585 + <span class="video-icon"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M12 19c-2.3 0-6.4-.2-8.1-.6-.7-.2-1.2-.7-1.4-1.4-.3-1.1-.5-3.4-.5-5s.2-3.9.5-5c.2-.7.7-1.2 1.4-1.4C5.6 5.2 9.7 5 12 5s6.4.2 8.1.6c.7.2 1.2.7 1.4 1.4.3 1.1.5 3.4.5 5s-.2 3.9-.5 5c-.2.7-.7 1.2-1.4 1.4-1.7.4-5.8.6-8.1.6z"></path><polygon points="10 15 15 12 10 9 10 15"></polygon></svg></span>
586 + <?php echo esc_html__('Watch Loops Email Capture Tutorial', 'mxchat'); ?>
587 + </a>
556 588 </div>
589 + </div>
557 590
558 - <div class="faq-item">
559 - <h3><?php echo esc_html__('How does the WooCommerce integration work?', 'mxchat'); ?></h3>
560 - <p>
561 - <?php echo esc_html__('With WooCommerce integration, the chatbot automatically embeds new products and updates existing ones. For already-published products, you can click update or submit the product sitemap. The “Order History Access” setting allows the bot to access users\' order history (requires login) and assist with order inquiries. To enable the “Add to Cart” feature, add this system instruction: “After discussing a product, ask if the user wants to add it to their cart. The user must say \'Add to cart\' exactly.” Currently, this feature supports English only, with more languages coming soon.', 'mxchat'); ?>
562 - </p>
591 + <div class="tutorial-item">
592 + <h3><?php echo esc_html__('MxChat AI Agent Testing Service', 'mxchat'); ?></h3>
593 + <div class="video-description">
594 + <p><?php echo esc_html__('Learn how to use the MxChat AI Agent Testing Service to evaluate and improve your chatbot\'s performance and accuracy.', 'mxchat'); ?></p>
595 + <p><small><?php echo esc_html__('Note: This tutorial uses an older UI, but the process remains the same.', 'mxchat'); ?></small></p>
596 + <a href="https://www.youtube.com/watch?v=A0jowbpyX54" target="_blank" rel="noopener" class="video-link">
597 + <span class="video-icon"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M12 19c-2.3 0-6.4-.2-8.1-.6-.7-.2-1.2-.7-1.4-1.4-.3-1.1-.5-3.4-.5-5s.2-3.9.5-5c.2-.7.7-1.2 1.4-1.4C5.6 5.2 9.7 5 12 5s6.4.2 8.1.6c.7.2 1.2.7 1.4 1.4.3 1.1.5 3.4.5 5s-.2 3.9-.5 5c-.2.7-.7 1.2-1.4 1.4-1.7.4-5.8.6-8.1.6z"></path><polygon points="10 15 15 12 10 9 10 15"></polygon></svg></span>
598 + <?php echo esc_html__('Watch AI Agent Testing Tutorial', 'mxchat'); ?>
599 + </a>
563 600 </div>
601 + </div>
602 + </div>
564 603
565 - <div class="faq-item">
566 - <h3><?php echo esc_html__('Why isn\'t my chatbot responding as expected?', 'mxchat'); ?></h3>
567 - <p>
568 - <?php echo esc_html__('AI chatbots can sometimes behave in unexpected ways, especially if you\'re new to configuring AI for specific tasks. We\'re committed to helping you get the most out of your chatbot experience. While we’re working on comprehensive guides and video tutorials, our team is here to assist you directly. If your chatbot isn\'t delivering the responses you need, please don’t hesitate to', 'mxchat'); ?> <a href="https://mxchat.ai/contact/" target="_blank" rel="noopener noreferrer"><?php echo esc_html__('contact us', 'mxchat'); ?></a> <?php echo esc_html__('for personalized support.', 'mxchat'); ?>
569 - </p>
570 - <p>
571 - <?php echo esc_html__('We’re dedicated to your success and ready to guide you in aligning the AI\'s behavior to meet your goals.', 'mxchat'); ?>
572 - </p>
604 + <div class="support-section">
605 + <h3><?php echo esc_html__('Need Help?', 'mxchat'); ?></h3>
606 + <div class="support-content">
607 + <p>
608 + <?php echo esc_html__('If you\'re having trouble with setup or getting the responses you need, we encourage you to review our', 'mxchat'); ?>
609 + <a href="https://mxchat.ai/documentation/" target="_blank" rel="noopener noreferrer"><?php echo esc_html__('documentation', 'mxchat'); ?></a> <?php echo esc_html__('or', 'mxchat'); ?>
610 + <a href="https://wordpress.org/support/plugin/mxchat-basic/" target="_blank" rel="noopener noreferrer"><?php echo esc_html__('create a support ticket', 'mxchat'); ?></a>.
611 + </p>
612 + <p>
613 + <?php echo esc_html__('If you like our plugin, please consider', 'mxchat'); ?> <a href="https://wordpress.org/plugins/mxchat-basic/#reviews" target="_blank" rel="noopener noreferrer"><?php echo esc_html__('leaving us a review', 'mxchat'); ?></a>.
614 + </p>
615 + </div>
616 + </div>
617 + </div>
618 + </div>
573 619 </div>
574 -
575 - <div class="faq-item">
576 - <h3><?php echo esc_html__('What is Loops, and how do I get an API key?', 'mxchat'); ?></h3>
577 - <p>
578 - <?php echo esc_html__('Loops is a powerful SaaS email service that helps you automate and enhance your email marketing campaigns, making it easy to reach and engage with your audience. To integrate Loops with MxChat, you’ll need an API key from Loops. You can obtain this key by logging into your Loops account and navigating to the API settings. Visit the', 'mxchat'); ?> <a href="https://loops.so" target="_blank" rel="noopener noreferrer"><?php echo esc_html__('Loops website', 'mxchat'); ?></a> <?php echo esc_html__('to get started or to sign up for an account.', 'mxchat'); ?>
579 - </p>
580 - </div>
581 -
582 620 </div>
583 621 </div>
584 622 <?php
585 623 }
@@ -584,73 +622,348 @@
584 622 <?php
585 623 }
586 624
587 625
588 -
589 626 public function mxchat_create_transcripts_page() {
590 627 global $wpdb;
591 628 $table_name = $wpdb->prefix . 'mxchat_chat_transcripts';
592 -
629 +
593 630 // Get basic stats
594 631 $total_chats = $wpdb->get_var("SELECT COUNT(DISTINCT session_id) FROM $table_name");
595 632 $total_messages = $wpdb->get_var("SELECT COUNT(*) FROM $table_name");
596 - $total_users = $wpdb->get_var("SELECT COUNT(DISTINCT user_email) FROM $table_name WHERE user_email != ''");
633 +
634 + // Count unique users with detailed breakdown
635 + $total_users = $wpdb->get_var("
636 + SELECT COUNT(DISTINCT
637 + CASE
638 + WHEN user_email != '' AND user_email IS NOT NULL THEN user_email
639 + WHEN user_id != 0 THEN CONCAT('user_', user_id)
640 + WHEN user_identifier NOT LIKE 'Tech-Savvy User'
641 + AND user_identifier NOT LIKE 'Detail-Oriented User'
642 + AND user_identifier NOT LIKE 'Language Learner'
643 + AND user_identifier NOT LIKE 'Casual Browser'
644 + AND user_identifier NOT LIKE 'Policy Enforcer'
645 + AND user_identifier NOT LIKE 'Researcher'
646 + AND user_identifier NOT LIKE 'Loyalty Member'
647 + AND user_identifier NOT LIKE 'Gift Buyer'
648 + AND user_identifier NOT LIKE 'Parent or Caregiver'
649 + THEN user_identifier
650 + ELSE session_id
651 + END
652 + )
653 + FROM $table_name
654 + WHERE role != 'assistant'
655 + ");
656 +
657 + // Get user type breakdown
658 + $registered_users = $wpdb->get_var("
659 + SELECT COUNT(DISTINCT user_email)
660 + FROM $table_name
661 + WHERE user_email != '' AND user_email IS NOT NULL
662 + ");
663 +
664 + $guest_users = $wpdb->get_var("
665 + SELECT COUNT(DISTINCT user_identifier)
666 + FROM $table_name
667 + WHERE (user_email = '' OR user_email IS NULL)
668 + AND role != 'assistant'
669 + AND user_identifier NOT LIKE 'Tech-Savvy User'
670 + AND user_identifier NOT LIKE 'Detail-Oriented User'
671 + AND user_identifier NOT LIKE 'Language Learner'
672 + AND user_identifier NOT LIKE 'Casual Browser'
673 + AND user_identifier NOT LIKE 'Policy Enforcer'
674 + AND user_identifier NOT LIKE 'Researcher'
675 + AND user_identifier NOT LIKE 'Loyalty Member'
676 + AND user_identifier NOT LIKE 'Gift Buyer'
677 + AND user_identifier NOT LIKE 'Parent or Caregiver'
678 + ");
679 +
680 + // Get agent test messages count
681 + $agent_tests = $wpdb->get_var("
682 + SELECT COUNT(DISTINCT session_id)
683 + FROM $table_name
684 + WHERE user_identifier IN (
685 + 'Tech-Savvy User',
686 + 'Detail-Oriented User',
687 + 'Language Learner',
688 + 'Casual Browser',
689 + 'Policy Enforcer',
690 + 'Researcher',
691 + 'Loyalty Member',
692 + 'Gift Buyer',
693 + 'Parent or Caregiver'
694 + )
695 + ");
597 696 ?>
598 - <div class="wrap mxchat-admin">
599 - <!-- Stats Cards -->
600 - <div class="mxchat-stats-grid">
601 - <div class="mxchat-stat-card">
602 - <div class="stat-icon">💬</div>
603 - <div class="stat-content">
604 - <span class="stat-value"><?php echo esc_html($total_chats); ?></span>
605 - <span class="stat-label"><?php esc_html_e('Total Chats', 'mxchat'); ?></span>
697 + <div class="wrap mxchat-transcripts-wrapper">
698 + <!-- Hero Section -->
699 + <div class="mxchat-transcripts-hero">
700 + <h1 class="mxchat-main-title">
701 + Chat <span class="mxchat-gradient-text">Transcripts</span>
702 + </h1>
703 + <p class="mxchat-hero-subtitle">
704 + <?php esc_html_e('Review and manage your chatbot conversations with detailed message history.', 'mxchat'); ?>
705 + </p>
706 + </div>
707 + <div class="mxchat-content">
708 + <!-- Stats Cards -->
709 + <div class="mxchat-stats-grid">
710 + <div class="mxchat-stat-card">
711 + <div class="stat-icon">💬</div>
712 + <div class="stat-content">
713 + <span class="stat-value"><?php echo esc_html($total_chats); ?></span>
714 + <span class="stat-label"><?php esc_html_e('Total Chats', 'mxchat'); ?></span>
715 + </div>
606 716 </div>
607 - </div>
608 - <div class="mxchat-stat-card">
609 - <div class="stat-icon">📝</div>
610 - <div class="stat-content">
611 - <span class="stat-value"><?php echo esc_html($total_messages); ?></span>
612 - <span class="stat-label"><?php esc_html_e('Total Messages', 'mxchat'); ?></span>
717 + <div class="mxchat-stat-card">
718 + <div class="stat-icon">📝</div>
719 + <div class="stat-content">
720 + <span class="stat-value"><?php echo esc_html($total_messages); ?></span>
721 + <span class="stat-label"><?php esc_html_e('Total Messages', 'mxchat'); ?></span>
722 + </div>
613 723 </div>
724 + <div class="mxchat-stat-card">
725 + <div class="stat-icon">👥</div>
726 + <div class="stat-content">
727 + <span class="stat-value"><?php echo esc_html($total_users); ?></span>
728 + <span class="stat-label"><?php esc_html_e('Unique Users', 'mxchat'); ?></span>
729 + <span class="stat-sublabel">
730 + <?php
731 + echo sprintf(
732 + esc_html__('%d registered, %d guests, %d agent tests', 'mxchat'),
733 + $registered_users,
734 + $guest_users,
735 + $agent_tests
736 + );
737 + ?>
738 + </span>
739 + </div>
740 + </div>
614 741 </div>
615 - <div class="mxchat-stat-card">
616 - <div class="stat-icon">👥</div>
617 - <div class="stat-content">
618 - <span class="stat-value"><?php echo esc_html($total_users); ?></span>
619 - <span class="stat-label"><?php esc_html_e('Unique Users', 'mxchat'); ?></span>
742 + <!-- Search and Filter Controls -->
743 + <div class="mxchat-controls-wrapper">
744 + <div class="mxchat-search-box">
745 + <input type="text" id="mxchat-search-transcripts"
746 + placeholder="<?php esc_attr_e('Search transcripts...', 'mxchat'); ?>"
747 + class="regular-text">
620 748 </div>
749 + <form id="mxchat-delete-form" method="post">
750 + <?php wp_nonce_field('mxchat_delete_chat_history', 'mxchat_delete_chat_nonce'); ?>
751 + <div class="mxchat-controls">
752 + <button type="button" id="mxchat-export-transcripts" class="mxchat-action-button">
753 + <span class="dashicons dashicons-download"></span>
754 + <?php esc_html_e('Export All Chats', 'mxchat'); ?>
755 + </button>
756 + <button type="button" id="mxchat-select-all-transcripts" class="mxchat-select-button">
757 + <span class="dashicons dashicons-yes-alt"></span>
758 + <span class="button-text"><?php esc_html_e('Select All', 'mxchat'); ?></span>
759 + </button>
760 + <button type="submit" class="button delete-chats-button">
761 + <span class="dashicons dashicons-trash"></span>
762 + <?php esc_html_e('Delete Selected', 'mxchat'); ?>
763 + </button>
764 + </div>
765 + </form>
621 766 </div>
767 + <!-- Transcripts Container -->
768 + <div id="mxchat-transcripts"></div>
622 769 </div>
770 + </div>
771 + <?php
772 +}
623 773
624 - <!-- Search and Filter Controls -->
625 - <div class="mxchat-controls-wrapper">
626 - <div class="mxchat-search-box">
627 - <input type="text" id="mxchat-search-transcripts"
628 - placeholder="<?php esc_attr_e('Search transcripts...', 'mxchat'); ?>"
629 - class="regular-text">
630 - </div>
774 +public function export_chat_transcripts() {
775 + if (!current_user_can('manage_options')) {
776 + wp_die(esc_html__('You do not have sufficient permissions to access this page.', 'mxchat'));
777 + }
631 778
632 - <form id="mxchat-delete-form" method="post">
633 - <?php wp_nonce_field('mxchat_delete_chat_history', 'mxchat_delete_chat_nonce'); ?>
634 - <div class="mxchat-controls">
635 - <button type="button" id="mxchat-select-all-transcripts" class="mxchat-select-button">
636 - <span class="dashicons dashicons-yes-alt"></span>
637 - <span class="button-text"><?php esc_html_e('Select All', 'mxchat'); ?></span>
638 - </button>
639 - <button type="submit" class="button delete-chats-button">
640 - <span class="dashicons dashicons-trash"></span>
641 - <?php esc_html_e('Delete Selected', 'mxchat'); ?>
642 - </button>
643 - </div>
644 - </form>
645 - </div>
779 + check_ajax_referer('mxchat_export_transcripts', 'security');
646 780
647 - <!-- Transcripts Container -->
648 - <div id="mxchat-transcripts"></div>
649 - </div>
650 - <?php
781 + global $wpdb;
782 + $table_name = $wpdb->prefix . 'mxchat_chat_transcripts';
783 +
784 + // Get all transcripts ordered by session and timestamp
785 + $results = $wpdb->get_results(
786 + "SELECT session_id, user_email, user_identifier, role, message, timestamp
787 + FROM {$table_name}
788 + ORDER BY session_id, timestamp ASC"
789 + );
790 +
791 + if (empty($results)) {
792 + wp_send_json_error(array('message' => 'No transcripts found.'));
793 + wp_die();
794 + }
795 +
796 + // Set headers for CSV download
797 + header('Content-Type: text/csv');
798 + header('Content-Disposition: attachment; filename="chat-transcripts-' . date('Y-m-d') . '.csv"');
799 + header('Pragma: no-cache');
800 + header('Expires: 0');
801 +
802 + // Create output stream
803 + $output = fopen('php://output', 'w');
804 +
805 + // Add UTF-8 BOM for proper Excel encoding
806 + fputs($output, "\xEF\xBB\xBF");
807 +
808 + // Add CSV headers
809 + fputcsv($output, array(
810 + 'Session ID',
811 + 'Email',
812 + 'User Identifier',
813 + 'Role',
814 + 'Message',
815 + 'Timestamp'
816 + ));
817 +
818 + // Add data rows
819 + foreach ($results as $row) {
820 + fputcsv($output, array(
821 + $row->session_id,
822 + $row->user_email,
823 + $row->user_identifier,
824 + $row->role,
825 + $row->message,
826 + $row->timestamp
827 + ));
828 + }
829 +
830 + fclose($output);
831 + wp_die();
651 832 }
652 833
834 +public function mxchat_fetch_chat_history() {
835 + global $wpdb;
836 + $table_name = $wpdb->prefix . 'mxchat_chat_transcripts';
837 +
838 + if (!current_user_can('manage_options')) {
839 + wp_die(esc_html__('You do not have sufficient permissions to view this page.', 'mxchat'));
840 + }
841 +
842 + // First get unique session IDs ordered by most recent message in each session
843 + $session_ids = $wpdb->get_col(
844 + $wpdb->prepare(
845 + "SELECT DISTINCT session_id
846 + FROM {$table_name}
847 + GROUP BY session_id
848 + ORDER BY MAX(timestamp) DESC"
849 + )
850 + );
851 +
852 + if (empty($session_ids)) {
853 + wp_die(esc_html__('No chat history available.', 'mxchat'));
854 + }
855 +
856 + ob_start();
857 + echo '<div class="mxchat-transcript">';
858 +
859 + // Iterate through sessions from newest to oldest
860 + foreach ($session_ids as $session_id) {
861 + // Get the email associated with this session (if available)
862 + $email = $wpdb->get_var(
863 + $wpdb->prepare(
864 + "SELECT user_email
865 + FROM {$table_name}
866 + WHERE session_id = %s AND user_email != ''
867 + ORDER BY timestamp ASC
868 + LIMIT 1",
869 + $session_id
870 + )
871 + );
872 +
873 + // Debug: Check email retrieval
874 + if (empty($email)) {
875 + //error_log("No email found for session {$session_id}");
876 + } else {
877 + //error_log("Email for session {$session_id}: " . $email);
878 + }
879 +
880 + // Get messages for this session ordered by timestamp
881 + $messages = $wpdb->get_results(
882 + $wpdb->prepare(
883 + "SELECT * FROM {$table_name}
884 + WHERE session_id = %s
885 + ORDER BY timestamp ASC",
886 + $session_id
887 + )
888 + );
889 +
890 + // Start session block
891 + echo '<div class="mxchat-session">';
892 + echo '<div class="mxchat-session-header">';
893 + // Wrap checkbox and session ID in one block
894 + echo '<div class="mxchat-session-id">';
895 + echo '<input type="checkbox" name="delete_session_ids[]" value="' . esc_attr($session_id) . '"> ';
896 + echo '<strong>' . esc_html__('Session ID:', 'mxchat') . '</strong> ' . esc_html($session_id);
897 + echo '</div>';
898 +
899 + // Place email directly below the session ID block
900 + if (!empty($email)) {
901 + echo '<div class="mxchat-session-email">';
902 + echo '<strong>' . esc_html__('Email:', 'mxchat') . '</strong> ' . esc_html($email);
903 + echo '</div>';
904 + }
905 + echo '</div>';
906 +
907 + echo '<div class="mxchat-messages">';
908 +
909 + // Display messages for this session
910 + foreach ($messages as $transcript) {
911 + $formatted_timestamp = date_i18n('F j, Y g:i a', strtotime($transcript->timestamp));
912 +
913 + // Determine message styling
914 + switch ($transcript->role) {
915 + case 'assistant':
916 + case 'bot':
917 + $message_class = 'bot-message';
918 + $display_role = esc_html__('Chatbot', 'mxchat');
919 + break;
920 + case 'user':
921 + $message_class = 'user-message';
922 + $display_role = !empty($transcript->user_identifier)
923 + ? sanitize_text_field($transcript->user_identifier)
924 + : esc_html__('User', 'mxchat');
925 + break;
926 + case 'agent':
927 + $message_class = 'agent-message';
928 + $display_role = esc_html__('Agent', 'mxchat');
929 + break;
930 + default:
931 + $message_class = 'unknown-message';
932 + $display_role = esc_html__('Unknown', 'mxchat');
933 + }
934 +
935 + // Process message content
936 + $message_content = wp_kses(
937 + stripslashes($transcript->message),
938 + [
939 + 'b' => [], 'strong' => [], 'i' => [], 'em' => [], 'u' => [],
940 + 'br' => [], 'p' => [], 'ul' => [], 'ol' => [], 'li' => [],
941 + 'a' => ['href' => [], 'title' => []]
942 + ]
943 + );
944 + $message_content = nl2br($message_content);
945 +
946 + // Render message
947 + echo '<div class="mxchat-message ' . esc_attr($message_class) . '">';
948 + echo '<div class="mxchat-message-header">' . esc_html($display_role) . '</div>';
949 + echo '<div class="mxchat-message-content">' . $message_content . '</div>';
950 + echo '<div class="mxchat-timestamp">' . esc_html($formatted_timestamp) . '</div>';
951 + echo '</div>';
952 + }
953 +
954 + // Close session block
955 + echo '</div></div>';
956 + }
957 +
958 + echo '</div>';
959 + $output = ob_get_clean();
960 + echo $output;
961 + wp_die();
962 +}
963 +
964 +
965 +
653 966 public function mxchat_create_prompts_page() {
654 967 global $wpdb;
655 968 $table_name = $wpdb->prefix . 'mxchat_system_prompt_content';
656 969
@@ -731,10 +1044,39 @@
731 1044 <div class="mxchat-content">
732 1045 <!-- Import Settings Card -->
733 1046 <div class="mxchat-card">
734 1047 <h2><?php esc_html_e('Knowledge Import Settings', 'mxchat'); ?></h2>
735 - <p><?php esc_html_e('Using the free Pinecone DB Manager add-on is recommended for high performance and a knowledge database of more than 500.', 'mxchat'); ?></p>
1048 +<?php
1049 +// Check if the appropriate embedding API key exists
1050 +$embedding_model = isset($this->options['embedding_model']) ? esc_attr($this->options['embedding_model']) : 'text-embedding-ada-002';
1051 +$has_openai_key = !empty($this->options['api_key']);
1052 +$has_voyage_key = !empty($this->options['voyage_api_key']);
736 1053
1054 +// Determine if they have the needed API key for their selected embedding model
1055 +$has_required_key = false;
1056 +$required_key_type = '';
1057 +
1058 +if (strpos($embedding_model, 'text-embedding-') !== false && $has_openai_key) {
1059 + $has_required_key = true;
1060 + $required_key_type = 'OpenAI';
1061 +} elseif (strpos($embedding_model, 'voyage-') !== false && $has_voyage_key) {
1062 + $has_required_key = true;
1063 + $required_key_type = 'Voyage AI';
1064 +} elseif (strpos($embedding_model, 'text-embedding-') !== false) {
1065 + $required_key_type = 'OpenAI';
1066 +} elseif (strpos($embedding_model, 'voyage-') !== false) {
1067 + $required_key_type = 'Voyage AI';
1068 +}
1069 +?>
1070 +
1071 +<div class="mxchat-knowledge-warning <?php echo $has_required_key ? 'success' : 'warning'; ?>">
1072 + <?php if ($has_required_key): ?>
1073 + <p><span class="dashicons dashicons-yes-alt"></span> <?php echo wp_kses_post(sprintf(__('We detected your %s API key. <strong>You must have added credits to your %s account</strong> before using the knowledgebase.', 'mxchat'), $required_key_type, $required_key_type)); ?></p>
1074 + <?php else: ?>
1075 + <p><span class="dashicons dashicons-warning"></span> <strong><?php esc_html_e('Important:', 'mxchat'); ?></strong> <?php echo sprintf(esc_html__('Before importing knowledge, you must add a %s API key with sufficient credits in the Chatbot settings.', 'mxchat'), $required_key_type); ?> <a href="<?php echo admin_url('admin.php?page=mxchat-max'); ?>"><?php esc_html_e('Go to API Key Settings', 'mxchat'); ?></a></p>
1076 + <?php endif; ?>
1077 +</div>
1078 +
737 1079 <!-- Tab Contents -->
738 1080 <div class="mxchat-tab-contents">
739 1081 <!-- Default Database Tab -->
740 1082 <div id="default-db" class="mxchat-tab-content active">
@@ -781,10 +1123,9 @@
781 1123 <!-- Import Methods -->
782 1124 <div class="mxchat-import-methods">
783 1125 <div class="mxchat-method-card">
784 1126 <h4><?php esc_html_e('Sitemap Import', 'mxchat'); ?></h4>
785 - <p><?php esc_html_e('Import all content from your sitemap automatically.', 'mxchat'); ?></p>
786 - </div>
1127 + <p><span class="red-warning">IMPORTANT:</span> <?php esc_html_e('Use a content-specific sub-sitemap, not the sitemap index.', 'mxchat'); ?></p> </div>
787 1128 <div class="mxchat-method-card">
788 1129 <h4><?php esc_html_e('PDF Import', 'mxchat'); ?></h4>
789 1130 <p><?php esc_html_e('Import knowledge directly from PDF documents.', 'mxchat'); ?></p>
790 1131 </div>
@@ -893,8 +1234,10 @@
893 1234 <?php endif; ?>
894 1235 </div>
895 1236 </div>
896 1237 <?php endif; ?>
1238 +
1239 +
897 1240 </div>
898 1241
899 1242
900 1243 </div>
@@ -1091,30 +1434,134 @@
1091 1434
1092 1435 wp_safe_redirect(add_query_arg(array('page' => 'mxchat-prompts', 'deleted' => 'true'), admin_url('admin.php')));
1093 1436 exit;
1094 1437 }
1095 -public function mxchat_generate_embedding($text) {
1096 - $options = get_option('mxchat_options');
1097 - $api_key = $options['api_key'] ?? esc_html__('default_api_key', 'mxchat');
1098 1438
1099 - $response = wp_remote_post('https://api.openai.com/v1/embeddings', array(
1100 - 'body' => wp_json_encode(array(
1101 - 'model' => esc_html__('text-embedding-ada-002', 'mxchat'),
1102 - 'input' => $text
1103 - )),
1104 - 'headers' => array(
1105 - 'Authorization' => 'Bearer ' . $api_key,
1106 - 'Content-Type' => esc_html__('application/json', 'mxchat')
1107 - ),
1108 - ));
1109 1439
1110 - if (is_wp_error($response)) {
1111 - return null;
1440 +public function mxchat_generate_embedding($text) {
1441 + //error_log('[MXCHAT-EMBED] Starting embedding generation. Text length: ' . strlen($text) . ' bytes');
1442 + //error_log('[MXCHAT-EMBED] Text preview: ' . substr($text, 0, 100) . '...');
1443 +
1444 + $options = get_option('mxchat_options');
1445 + $selected_model = $options['embedding_model'] ?? 'text-embedding-ada-002';
1446 + //error_log('[MXCHAT-EMBED] Selected embedding model: ' . $selected_model);
1447 +
1448 + // Determine provider and endpoint
1449 + if (strpos($selected_model, 'voyage') === 0) {
1450 + $api_key = $options['voyage_api_key'] ?? '';
1451 + $endpoint = 'https://api.voyageai.com/v1/embeddings';
1452 + //error_log('[MXCHAT-EMBED] Using Voyage AI API');
1453 + } else {
1454 + $api_key = $options['api_key'] ?? '';
1455 + $endpoint = 'https://api.openai.com/v1/embeddings';
1456 + //error_log('[MXCHAT-EMBED] Using OpenAI API');
1457 + }
1458 +
1459 + //error_log('[MXCHAT-EMBED] Using endpoint: ' . $endpoint);
1460 +
1461 + if (empty($api_key)) {
1462 + //error_log('[MXCHAT-EMBED] Error: API key not configured');
1463 + return 'Missing API key. Please configure your API key in the settings.';
1464 + }
1465 +
1466 + // Check if text is too long (for OpenAI, roughly estimate tokens as words/0.75)
1467 + $estimated_tokens = ceil(str_word_count($text) / 0.75);
1468 + //error_log('[MXCHAT-EMBED] Estimated token count: ~' . $estimated_tokens);
1469 +
1470 + if ($estimated_tokens > 8000 && strpos($selected_model, 'voyage') === false) {
1471 + //error_log('[MXCHAT-EMBED] Warning: Text may exceed OpenAI token limits (8K for most models)');
1472 + // Consider truncating text here
1473 + }
1474 +
1475 + // Prepare request body
1476 + $request_body = array(
1477 + 'model' => $selected_model,
1478 + 'input' => $text
1479 + );
1480 +
1481 + // Add output_dimension for voyage-3-large model
1482 + if ($selected_model === 'voyage-3-large') {
1483 + $request_body['output_dimension'] = 2048;
1484 + }
1485 +
1486 + //error_log('[MXCHAT-EMBED] Request prepared with model: ' . $selected_model);
1487 +
1488 + // Make API request
1489 + //error_log('[MXCHAT-EMBED] Sending API request to: ' . $endpoint);
1490 + $response = wp_remote_post($endpoint, array(
1491 + 'body' => wp_json_encode($request_body),
1492 + 'headers' => array(
1493 + 'Authorization' => 'Bearer ' . $api_key,
1494 + 'Content-Type' => 'application/json'
1495 + ),
1496 + 'timeout' => 60 // Increased timeout for large inputs
1497 + ));
1498 +
1499 + // Handle wp_remote_post errors
1500 + if (is_wp_error($response)) {
1501 + $error_message = $response->get_error_message();
1502 + //error_log('[MXCHAT-EMBED] WP Remote Post Error: ' . $error_message);
1503 + return 'Connection error: ' . $error_message;
1504 + }
1505 +
1506 + // Get and check HTTP response code
1507 + $http_code = wp_remote_retrieve_response_code($response);
1508 + //error_log('[MXCHAT-EMBED] API Response Code: ' . $http_code);
1509 +
1510 + if ($http_code !== 200) {
1511 + $error_body = wp_remote_retrieve_body($response);
1512 + //error_log('[MXCHAT-EMBED] API Error Response Body: ' . $error_body);
1513 +
1514 + // Try to parse error for more details
1515 + $error_json = json_decode($error_body, true);
1516 + if (json_last_error() === JSON_ERROR_NONE && isset($error_json['error'])) {
1517 + $error_type = $error_json['error']['type'] ?? 'unknown';
1518 + $error_message = $error_json['error']['message'] ?? 'No message';
1519 + //error_log('[MXCHAT-EMBED] API Error Type: ' . $error_type);
1520 + //error_log('[MXCHAT-EMBED] API Error Message: ' . $error_message);
1521 + return "API Error ($error_type): $error_message";
1112 1522 }
1523 +
1524 + return "API Error (HTTP $http_code): Unable to generate embedding";
1525 + }
1526 +
1527 + // Parse response body
1528 + $response_body = wp_remote_retrieve_body($response);
1529 + //error_log('[MXCHAT-EMBED] Received response length: ' . strlen($response_body) . ' bytes');
1530 +
1531 + $response_data = json_decode($response_body, true);
1532 +
1533 + if (json_last_error() !== JSON_ERROR_NONE) {
1534 + $error = json_last_error_msg();
1535 + //error_log('[MXCHAT-EMBED] JSON Parse Error: ' . $error);
1536 + //error_log('[MXCHAT-EMBED] Response preview: ' . substr($response_body, 0, 200));
1537 + return "Failed to parse API response: $error";
1538 + }
1539 +
1540 + // Both APIs use the same structure, so we can extract the embedding the same way
1541 + if (isset($response_data['data'][0]['embedding'])) {
1542 + $embedding_dimensions = count($response_data['data'][0]['embedding']);
1543 + //error_log('[MXCHAT-EMBED] Successfully extracted embedding with ' . $embedding_dimensions . ' dimensions');
1544 +
1545 + // Check if embedding dimensions are as expected
1546 + if (($selected_model === 'text-embedding-ada-002' && $embedding_dimensions !== 1536) ||
1547 + ($selected_model === 'voyage-3-large' && $embedding_dimensions !== 2048)) {
1548 + }
1549 +
1550 + return $response_data['data'][0]['embedding'];
1551 + } else {
1552 + //error_log('[MXCHAT-EMBED] Error: No embedding found in response');
1553 + //error_log('[MXCHAT-EMBED] Response structure: ' . wp_json_encode(array_keys($response_data)));
1554 +
1555 + if (isset($response_data['error'])) {
1556 + //error_log('[MXCHAT-EMBED] API Error in response: ' . wp_json_encode($response_data['error']));
1557 + return "API Error in response: " . wp_json_encode($response_data['error']);
1558 + }
1559 +
1560 + return "Invalid API response format: No embedding found";
1561 + }
1562 +}
1113 1563
1114 - $response_data = json_decode(wp_remote_retrieve_body($response), true);
1115 - return $response_data['data'][0]['embedding'] ?? null;
1116 - }
1117 1564 public function mxchat_delete_chat_history() {
1118 1565 if (!current_user_can('manage_options')) {
1119 1566 echo wp_json_encode(['error' => esc_html__('You do not have sufficient permissions.', 'mxchat')]);
1120 1567 wp_die();
@@ -1339,8 +1786,10 @@
1339 1786 'success' => true,
1340 1787 'message' => 'Successfully stored in Pinecone'
1341 1788 );
1342 1789 }
1790 +
1791 +
1343 1792 // Helper method for WordPress DB storage
1344 1793 private function store_in_wordpress_db($content, $url, $embedding_vector) {
1345 1794 global $wpdb;
1346 1795 $table_name = $wpdb->prefix . 'mxchat_system_prompt_content';
@@ -1716,19 +2165,26 @@
1716 2165 'status' => sanitize_text_field($status['status']),
1717 2166 'last_update' => human_time_diff(absint($status['last_update']), time()) . ' ' . esc_html__('ago', 'mxchat')
1718 2167 );
1719 2168 }
2169 +
1720 2170 public function mxchat_handle_sitemap_submission() {
2171 + // Start logging the submission process
2172 + //error_log('[MXCHAT-URL] ===== Starting URL submission process =====');
2173 +
1721 2174 // Check if the form was submitted and verify permissions
1722 2175 if (!isset($_POST['submit_sitemap']) || !current_user_can('manage_options')) {
2176 + //error_log('[MXCHAT-URL] Error: Unauthorized access or form not submitted properly');
1723 2177 wp_die(esc_html__('Unauthorized access', 'mxchat'));
1724 2178 }
1725 2179
1726 2180 // Verify nonce
2181 + //error_log('[MXCHAT-URL] Verifying nonce');
1727 2182 check_admin_referer('mxchat_submit_sitemap_action', 'mxchat_submit_sitemap_nonce');
1728 2183
1729 2184 // Validate URL
1730 2185 if (!isset($_POST['sitemap_url']) || empty($_POST['sitemap_url'])) {
2186 + //error_log('[MXCHAT-URL] Error: Empty or missing URL');
1731 2187 set_transient('mxchat_admin_notice_error',
1732 2188 esc_html__('Please provide a valid URL.', 'mxchat'),
1733 2189 30
1734 2190 );
@@ -1736,12 +2192,16 @@
1736 2192 exit;
1737 2193 }
1738 2194
1739 2195 $submitted_url = esc_url_raw($_POST['sitemap_url']);
2196 + //error_log('[MXCHAT-URL] Processing URL: ' . $submitted_url);
2197 +
2198 + //error_log('[MXCHAT-URL] Fetching URL content');
1740 2199 $response = wp_remote_get($submitted_url, array('timeout' => 30));
1741 2200
1742 2201 if (is_wp_error($response) || wp_remote_retrieve_response_code($response) !== 200) {
1743 - $error_message = is_wp_error($response) ? $response->get_error_message() : __('Failed to fetch URL', 'mxchat');
2202 + $error_message = is_wp_error($response) ? $response->get_error_message() : 'HTTP Status: ' . wp_remote_retrieve_response_code($response);
2203 + //error_log('[MXCHAT-URL] Error fetching URL: ' . $error_message);
1744 2204 set_transient('mxchat_admin_notice_error',
1745 2205 sprintf(
1746 2206 esc_html__('Failed to fetch the URL: %s', 'mxchat'),
1747 2207 esc_html($error_message)
@@ -1752,11 +2212,13 @@
1752 2212 exit;
1753 2213 }
1754 2214
1755 2215 $content_type = wp_remote_retrieve_header($response, 'content-type');
2216 + //error_log('[MXCHAT-URL] Content type: ' . $content_type);
1756 2217 $body_content = wp_remote_retrieve_body($response);
1757 2218
1758 2219 if (empty($body_content)) {
2220 + //error_log('[MXCHAT-URL] Error: Empty response body');
1759 2221 set_transient('mxchat_admin_notice_error',
1760 2222 esc_html__('Empty response received from URL.', 'mxchat'),
1761 2223 30
1762 2224 );
@@ -1762,12 +2224,15 @@
1762 2224 );
1763 2225 wp_safe_redirect(esc_url(admin_url('admin.php?page=mxchat-prompts')));
1764 2226 exit;
1765 2227 }
2228 + //error_log('[MXCHAT-URL] Retrieved body content length: ' . strlen($body_content) . ' bytes');
1766 2229
1767 2230 // Handle PDF URL
1768 2231 if ($this->is_pdf_url($submitted_url, $response)) {
2232 + //error_log('[MXCHAT-URL] Detected PDF URL, handling PDF for knowledge base');
1769 2233 $result = $this->handle_pdf_for_knowledge_base($submitted_url, $response);
2234 + //error_log('[MXCHAT-URL] PDF handling result: ' . $result);
1770 2235
1771 2236 if ($result === 'scheduled') {
1772 2237 set_transient(
1773 2238 'mxchat_last_pdf_url',
@@ -1779,9 +2244,9 @@
1779 2244 30
1780 2245 );
1781 2246 } else {
1782 2247 set_transient('mxchat_admin_notice_error',
1783 - esc_html__('Failed to start PDF processing. Please try again.', 'mxchat'),
2248 + esc_html__('Failed to start PDF processing: ', 'mxchat') . esc_html($result),
1784 2249 30
1785 2250 );
1786 2251 }
1787 2252
@@ -1790,8 +2255,9 @@
1790 2255 }
1791 2256
1792 2257 // Handle Sitemap XML
1793 2258 if (strpos($content_type, 'xml') !== false || strpos($body_content, '<urlset') !== false) {
2259 + //error_log('[MXCHAT-URL] Detected XML content, processing as sitemap');
1794 2260 libxml_use_internal_errors(true);
1795 2261 $xml = simplexml_load_string($body_content);
1796 2262 $xml_errors = libxml_get_errors();
1797 2263 libxml_clear_errors();
@@ -1796,8 +2262,15 @@
1796 2262 $xml_errors = libxml_get_errors();
1797 2263 libxml_clear_errors();
1798 2264
1799 2265 if ($xml === false || !empty($xml_errors)) {
2266 + //error_log('[MXCHAT-URL] Error: Invalid XML format');
2267 + if (!empty($xml_errors)) {
2268 + foreach ($xml_errors as $error) {
2269 + //error_log('[MXCHAT-URL] XML Error: ' . $error->message);
2270 + }
2271 + }
2272 +
1800 2273 set_transient('mxchat_admin_notice_error',
1801 2274 esc_html__('Invalid sitemap XML. Please provide a valid sitemap.', 'mxchat'),
1802 2275 30
1803 2276 );
@@ -1804,9 +2277,11 @@
1804 2277 wp_safe_redirect(esc_url(admin_url('admin.php?page=mxchat-prompts')));
1805 2278 exit;
1806 2279 }
1807 2280
2281 + //error_log('[MXCHAT-URL] Valid XML found, handling sitemap for knowledge base');
1808 2282 $result = $this->handle_sitemap_for_knowledge_base($xml, $submitted_url);
2283 + //error_log('[MXCHAT-URL] Sitemap handling result: ' . $result);
1809 2284
1810 2285 if ($result === 'scheduled') {
1811 2286 set_transient(
1812 2287 'mxchat_last_sitemap_url',
@@ -1817,10 +2292,12 @@
1817 2292 esc_html__('Sitemap processing has started in the background. You can check the progress in the Knowledge Base section.', 'mxchat'),
1818 2293 30
1819 2294 );
1820 2295 } else {
2296 + // Return to the admin page without a redirect for better error display
2297 + // The error is already stored in the sitemap status transient
1821 2298 set_transient('mxchat_admin_notice_error',
1822 - esc_html__('Failed to start sitemap processing. Please try again.', 'mxchat'),
2299 + esc_html__('Failed to start sitemap processing. Please check the status below for details.', 'mxchat'),
1823 2300 30
1824 2301 );
1825 2302 }
1826 2303
@@ -1828,12 +2305,17 @@
1828 2305 exit;
1829 2306 }
1830 2307
1831 2308 // Handle Regular URL
2309 + //error_log('[MXCHAT-URL] Processing as regular webpage');
1832 2310 $page_content = $this->mxchat_extract_main_content($body_content);
2311 + //error_log('[MXCHAT-URL] Extracted content length: ' . strlen($page_content) . ' bytes');
2312 +
1833 2313 $sanitized_content = $this->mxchat_sanitize_content_for_api($page_content);
2314 + //error_log('[MXCHAT-URL] Sanitized content length: ' . strlen($sanitized_content) . ' bytes');
1834 2315
1835 2316 if (empty($sanitized_content)) {
2317 + //error_log('[MXCHAT-URL] Error: No valid content after sanitization');
1836 2318 set_transient('mxchat_admin_notice_error',
1837 2319 esc_html__('No valid content found on the provided URL.', 'mxchat'),
1838 2320 30
1839 2321 );
@@ -1840,29 +2322,59 @@
1840 2322 wp_safe_redirect(esc_url(admin_url('admin.php?page=mxchat-prompts')));
1841 2323 exit;
1842 2324 }
1843 2325
2326 + //error_log('[MXCHAT-URL] Generating embedding for content');
1844 2327 $embedding_vector = $this->mxchat_generate_embedding($sanitized_content);
2328 +
2329 + // Check if embedding_vector is a string (error message)
2330 + if (is_string($embedding_vector)) {
2331 + //error_log('[MXCHAT-URL] Error generating embedding: ' . $embedding_vector);
2332 + set_transient('mxchat_admin_notice_error',
2333 + esc_html__('Failed to generate embedding: ', 'mxchat') . esc_html($embedding_vector),
2334 + 30
2335 + );
2336 + wp_safe_redirect(esc_url(admin_url('admin.php?page=mxchat-prompts')));
2337 + exit;
2338 + }
2339 +
1845 2340 if (is_array($embedding_vector)) {
1846 - MxChat_Utils::submit_content_to_db(
2341 + //error_log('[MXCHAT-URL] Successfully generated embedding with ' . count($embedding_vector) . ' dimensions');
2342 +
2343 + $db_result = MxChat_Utils::submit_content_to_db(
1847 2344 $sanitized_content,
1848 2345 $submitted_url,
1849 2346 $this->options['api_key']
1850 2347 );
2348 +
2349 + if (is_wp_error($db_result)) {
2350 + //error_log('[MXCHAT-URL] Error: Failed to store content in database: ' . $db_result->get_error_message());
2351 + set_transient('mxchat_admin_notice_error',
2352 + esc_html__('Failed to store content in database: ', 'mxchat') . esc_html($db_result->get_error_message()),
2353 + 30
2354 + );
2355 + wp_safe_redirect(esc_url(admin_url('admin.php?page=mxchat-prompts')));
2356 + exit;
2357 + }
2358 +
2359 + //error_log('[MXCHAT-URL] Successfully stored content in database');
1851 2360 set_transient('mxchat_admin_notice_success',
1852 2361 esc_html__('URL content successfully submitted!', 'mxchat'),
1853 2362 30
1854 2363 );
1855 2364 } else {
2365 + //error_log('[MXCHAT-URL] Error: Failed to generate embedding. Unexpected result type: ' . gettype($embedding_vector));
1856 2366 set_transient('mxchat_admin_notice_error',
1857 - esc_html__('Failed to generate embedding for the URL content. Please check your API key and try again.', 'mxchat'),
2367 + esc_html__('Failed to generate embedding: Unexpected result type. Please check your API key and try again.', 'mxchat'),
1858 2368 30
1859 2369 );
1860 2370 }
1861 2371
2372 + //error_log('[MXCHAT-URL] ===== Completed URL submission process =====');
1862 2373 wp_safe_redirect(esc_url(admin_url('admin.php?page=mxchat-prompts')));
1863 2374 exit;
1864 2375 }
2376 +
1865 2377 private function handle_sitemap_for_knowledge_base($xml, $sitemap_url) {
1866 2378 if (!current_user_can('manage_options')) {
1867 2379 //error_log(esc_html__('Unauthorized sitemap processing attempt', 'mxchat'));
1868 2380 return false;
@@ -1874,8 +2386,40 @@
1874 2386 if (!$xml || !is_object($xml)) {
1875 2387 throw new Exception(__('Invalid XML object provided', 'mxchat'));
1876 2388 }
1877 2389
2390 + // Add embedding validation before processing
2391 + // Test embedding with a small sample text to verify API key is working
2392 + $test_result = $this->mxchat_generate_embedding("This is a test to verify the embedding API key is working.");
2393 +
2394 + // Check if test_result is a string (error message) rather than an array (valid embedding)
2395 + if (is_string($test_result)) {
2396 + //error_log('[MXCHAT-URL] Embedding API validation failed: ' . $test_result);
2397 +
2398 + // Store the error in the status transient so it can be displayed later
2399 + $status_data = array(
2400 + 'total_urls' => 0,
2401 + 'processed_urls' => 0,
2402 + 'status' => 'error',
2403 + 'error' => __('Embedding API validation failed: ', 'mxchat') . $test_result,
2404 + 'last_update' => time()
2405 + );
2406 +
2407 + set_transient(
2408 + sanitize_key('mxchat_sitemap_status_' . md5($sitemap_url)),
2409 + array_map('sanitize_text_field', $status_data),
2410 + DAY_IN_SECONDS
2411 + );
2412 +
2413 + throw new Exception(__('Embedding API validation failed: ', 'mxchat') . $test_result);
2414 + }
2415 +
2416 + // Make sure it's an array (valid embedding)
2417 + if (!is_array($test_result)) {
2418 + //error_log('[MXCHAT-URL] Embedding API returned unexpected result type: ' . gettype($test_result));
2419 + throw new Exception(__('Embedding API returned unexpected result type. Please check your configuration.', 'mxchat'));
2420 + }
2421 +
1878 2422 $urls = [];
1879 2423 foreach ($xml->url as $url_element) {
1880 2424 $url = esc_url_raw((string)$url_element->loc);
1881 2425 if ($url) {
@@ -1912,12 +2456,36 @@
1912 2456
1913 2457 return __('scheduled', 'mxchat');
1914 2458
1915 2459 } catch (\Exception $e) {
1916 - //error_log(sprintf(esc_html__('Error preparing sitemap for processing: %s', 'mxchat'), esc_html($e->getMessage())));
1917 - return false;
2460 + $error_message = $e->getMessage();
2461 + //error_log(sprintf(esc_html__('Error preparing sitemap for processing: %s', 'mxchat'), esc_html($error_message)));
2462 +
2463 + // Store the sitemap URL and error in transients so they can be displayed
2464 + set_transient(
2465 + 'mxchat_last_sitemap_url',
2466 + sanitize_text_field($sitemap_url),
2467 + DAY_IN_SECONDS
2468 + );
2469 +
2470 + $status_data = array(
2471 + 'total_urls' => 0,
2472 + 'processed_urls' => 0,
2473 + 'status' => 'error',
2474 + 'error' => $error_message,
2475 + 'last_update' => time()
2476 + );
2477 +
2478 + set_transient(
2479 + sanitize_key('mxchat_sitemap_status_' . md5($sitemap_url)),
2480 + array_map('sanitize_text_field', $status_data),
2481 + DAY_IN_SECONDS
2482 + );
2483 +
2484 + return $error_message;
1918 2485 }
1919 2486 }
2487 +
1920 2488 public static function process_sitemap_urls_cron($urls, $sitemap_url, $total_urls, $batch_size, $batch_pause) {
1921 2489 // Validate inputs
1922 2490 $sitemap_url = esc_url_raw($sitemap_url);
1923 2491 $total_urls = absint($total_urls);
@@ -1943,11 +2511,38 @@
1943 2511 // Track failures in batch
1944 2512 $batch_stats = [
1945 2513 'processed' => 0,
1946 2514 'failed' => 0,
1947 - 'last_error' => ''
2515 + 'last_error' => '',
2516 + 'embedding_errors' => 0 // Track specifically embedding errors
1948 2517 ];
1949 2518
2519 + // Check embedding configuration with first URL
2520 + if ($start_url === 0) {
2521 + $page_url = esc_url_raw($urls[0]);
2522 + $page_response = wp_remote_get($page_url);
2523 +
2524 + if (!is_wp_error($page_response) && wp_remote_retrieve_response_code($page_response) === 200) {
2525 + $page_html = wp_remote_retrieve_body($page_response);
2526 + $page_content = $instance->mxchat_extract_main_content($page_html);
2527 + $sanitized_content = $instance->mxchat_sanitize_content_for_api($page_content);
2528 +
2529 + if (!empty($sanitized_content)) {
2530 + $embedding_vector = $instance->mxchat_generate_embedding($sanitized_content);
2531 +
2532 + // Check if embedding_vector is a string (error message)
2533 + if (is_string($embedding_vector)) {
2534 + throw new Exception('Embedding generation failed: ' . $embedding_vector);
2535 + }
2536 +
2537 + // Make sure it's an array (valid embedding)
2538 + if (!is_array($embedding_vector)) {
2539 + throw new Exception('Embedding generation returned unexpected result type: ' . gettype($embedding_vector));
2540 + }
2541 + }
2542 + }
2543 + }
2544 +
1950 2545 for ($i = $start_url; $i < $end_url; $i++) {
1951 2546 $page_url = esc_url_raw($urls[$i]);
1952 2547 $page_response = wp_remote_get($page_url);
1953 2548
@@ -1952,8 +2547,10 @@
1952 2547 $page_response = wp_remote_get($page_url);
1953 2548
1954 2549 if (is_wp_error($page_response) || wp_remote_retrieve_response_code($page_response) !== 200) {
1955 2550 $batch_stats['failed']++;
2551 + $error_message = is_wp_error($page_response) ? $page_response->get_error_message() : 'HTTP Status: ' . wp_remote_retrieve_response_code($page_response);
2552 + $batch_stats['last_error'] = 'Failed to fetch URL: ' . $error_message;
1956 2553 continue;
1957 2554 }
1958 2555
1959 2556 $page_html = wp_remote_retrieve_body($page_response);
@@ -1962,8 +2559,22 @@
1962 2559
1963 2560 if (!empty($sanitized_content)) {
1964 2561 $embedding_vector = $instance->mxchat_generate_embedding($sanitized_content);
1965 2562
2563 + // Check if embedding_vector is a string (error message)
2564 + if (is_string($embedding_vector)) {
2565 + $batch_stats['failed']++;
2566 + $batch_stats['embedding_errors']++;
2567 + $batch_stats['last_error'] = 'Failed to generate embedding: ' . $embedding_vector;
2568 +
2569 + // If we have multiple embedding errors, stop processing
2570 + if ($batch_stats['embedding_errors'] >= 3) {
2571 + throw new Exception('Multiple embedding failures detected: ' . $embedding_vector);
2572 + }
2573 + continue;
2574 + }
2575 +
2576 + // Check if it's an array (valid embedding)
1966 2577 if (is_array($embedding_vector)) {
1967 2578 $options = get_option('mxchat_options');
1968 2579 $submission_result = MxChat_Utils::submit_content_to_db($sanitized_content, $page_url, $options['api_key']);
1969 2580
@@ -1975,9 +2586,15 @@
1975 2586
1976 2587 $batch_stats['processed']++;
1977 2588 } else {
1978 2589 $batch_stats['failed']++;
1979 - $batch_stats['last_error'] = 'Failed to generate embedding. Please check OpenAI API key.';
2590 + $batch_stats['embedding_errors']++;
2591 + $batch_stats['last_error'] = 'Failed to generate embedding: Unexpected result type: ' . gettype($embedding_vector);
2592 +
2593 + // If we have multiple embedding errors, stop processing
2594 + if ($batch_stats['embedding_errors'] >= 3) {
2595 + throw new Exception('Multiple embedding failures detected. Please check your embedding API configuration.');
2596 + }
1980 2597 }
1981 2598 }
1982 2599
1983 2600 $status['processed_urls'] = absint($i + 1);
@@ -2018,8 +2635,9 @@
2018 2635 set_transient($status_key, array_map('sanitize_text_field', $status), DAY_IN_SECONDS);
2019 2636 }
2020 2637 }
2021 2638
2639 +
2022 2640 public function get_sitemap_processing_status($sitemap_url) {
2023 2641 $sitemap_url = esc_url_raw($sitemap_url);
2024 2642 $status = get_transient(sanitize_key('mxchat_sitemap_status_' . md5($sitemap_url)));
2025 2643
@@ -2040,8 +2658,42 @@
2040 2658 'last_error' => isset($status['last_error']) ? sanitize_text_field($status['last_error']) : ''
2041 2659 );
2042 2660 }
2043 2661
2662 +
2663 +
2664 +/**
2665 + * AJAX handler to return the current processing status
2666 + */
2667 +public function ajax_get_status_updates() {
2668 + // Verify the request
2669 + check_ajax_referer('mxchat_status_nonce', 'nonce');
2670 +
2671 + // Get the status just like in your admin page
2672 + $pdf_url = get_transient('mxchat_last_pdf_url');
2673 + $sitemap_url = get_transient('mxchat_last_sitemap_url');
2674 + $pdf_status = $pdf_url ? $this->get_pdf_processing_status($pdf_url) : false;
2675 + $sitemap_status = $sitemap_url ? $this->get_sitemap_processing_status($sitemap_url) : false;
2676 +
2677 + if ($pdf_status && $pdf_status['status'] === 'complete') {
2678 + delete_transient('mxchat_last_pdf_url');
2679 + $pdf_status = false;
2680 + }
2681 + if ($sitemap_status && $sitemap_status['status'] === 'complete') {
2682 + delete_transient('mxchat_last_sitemap_url');
2683 + $sitemap_status = false;
2684 + }
2685 +
2686 + // Return JSON response with the status data
2687 + wp_send_json(array(
2688 + 'pdf_status' => $pdf_status,
2689 + 'sitemap_status' => $sitemap_status,
2690 + 'is_processing' => ($pdf_status && ($pdf_status['status'] === 'processing' || $pdf_status['status'] === 'error'))
2691 + || ($sitemap_status && ($sitemap_status['status'] === 'processing' || $sitemap_status['status'] === 'error'))
2692 + ));
2693 +}
2694 +
2695 +
2044 2696 public function mxchat_stop_processing() {
2045 2697 // Verify permissions
2046 2698 if (!current_user_can('manage_options')) {
2047 2699 wp_die(esc_html__('Unauthorized access', 'mxchat'));
@@ -2077,27 +2729,53 @@
2077 2729 );
2078 2730 wp_safe_redirect(admin_url('admin.php?page=mxchat-prompts'));
2079 2731 exit;
2080 2732 }
2733 +
2734 +
2081 2735 private function mxchat_sanitize_content_for_api($content) {
2736 + //error_log('[MXCHAT-SANITIZE] Original content preview: ' . substr($content, 0, 500) . '...');
2737 +
2082 2738 // Remove script, style tags, and HTML comments
2083 2739 $content = preg_replace('/<script\b[^>]*>(.*?)<\/script>/is', '', $content);
2084 2740 $content = preg_replace('/<style\b[^>]*>(.*?)<\/style>/is', '', $content);
2085 2741 $content = preg_replace('/<!--(.|\s)*?-->/', '', $content);
2086 -
2742 +
2087 2743 // Remove all HTML tags and decode HTML entities
2088 2744 $content = wp_strip_all_tags($content);
2089 2745 $content = html_entity_decode($content, ENT_QUOTES | ENT_HTML5);
2090 -
2746 +
2091 2747 // Trim and normalize whitespace
2092 2748 $content = trim(preg_replace('/\s+/', ' ', $content));
2093 -
2749 +
2750 + // Remove control characters (which can cause database issues)
2751 + $content = preg_replace('/[\x00-\x08\x0B\x0C\x0E-\x1F\x7F]/u', '', $content);
2752 +
2753 + // Remove NULL bytes which can cause database errors
2754 + $content = str_replace("\0", "", $content);
2755 +
2756 + // Ensure valid UTF-8 encoding
2757 + $content = wp_check_invalid_utf8($content);
2758 +
2759 + // Remove any extremely long strings without spaces (often garbage)
2760 + $content = preg_replace('/\S{300,}/', ' ', $content);
2761 +
2762 + // Replace problematic characters that often cause database issues
2763 + $content = preg_replace('/[\x{10000}-\x{10FFFF}]/u', '', $content); // Remove emoji and other high Unicode characters
2764 +
2765 + // Replace any remaining potentially problematic characters with spaces
2766 + $content = preg_replace('/[^\p{L}\p{N}\p{P}\p{Z}\p{Sm}]/u', ' ', $content);
2767 +
2768 + // Limit to reasonable length if needed
2769 + $max_length = 65000; // Just under MySQL TEXT field limit
2770 + if (strlen($content) > $max_length) {
2771 + $content = substr($content, 0, $max_length);
2772 + }
2773 +
2774 + //error_log('[MXCHAT-SANITIZE] Sanitized content preview: ' . substr($content, 0, 500) . '...');
2094 2775 return $content;
2095 2776 }
2096 2777
2097 -
2098 -
2099 -
2100 2778 public function mxchat_handle_product_change($post_id, $post, $update) {
2101 2779 if ($post->post_type !== 'product') {
2102 2780 return;
2103 2781 }
@@ -2206,8 +2884,9 @@
2206 2884 $wpdb->delete($table_name, array('source_url' => $source_url), array('%s'));
2207 2885 }
2208 2886 }
2209 2887
2888 +
2210 2889 /**
2211 2890 * Delete vectors from Pinecone by source URL
2212 2891 *
2213 2892 * @param array $urls Array of source URLs to delete
@@ -2296,139 +2975,11 @@
2296 2975 );
2297 2976 }
2298 2977
2299 2978
2300 -public function mxchat_fetch_chat_history() {
2301 - global $wpdb;
2302 - $table_name = $wpdb->prefix . 'mxchat_chat_transcripts';
2303 2979
2304 - if (!current_user_can('manage_options')) {
2305 - wp_die(esc_html__('You do not have sufficient permissions to view this page.', 'mxchat'));
2306 - }
2307 2980
2308 - // First get unique session IDs ordered by most recent message in each session
2309 - $session_ids = $wpdb->get_col(
2310 - $wpdb->prepare(
2311 - "SELECT DISTINCT session_id
2312 - FROM {$table_name}
2313 - GROUP BY session_id
2314 - ORDER BY MAX(timestamp) DESC"
2315 - )
2316 - );
2317 2981
2318 - if (empty($session_ids)) {
2319 - wp_die(esc_html__('No chat history available.', 'mxchat'));
2320 - }
2321 -
2322 - ob_start();
2323 - echo '<div class="mxchat-transcript">';
2324 -
2325 - // Iterate through sessions from newest to oldest
2326 - foreach ($session_ids as $session_id) {
2327 - // Get the email associated with this session (if available)
2328 - $email = $wpdb->get_var(
2329 - $wpdb->prepare(
2330 - "SELECT user_email
2331 - FROM {$table_name}
2332 - WHERE session_id = %s AND user_email != ''
2333 - ORDER BY timestamp ASC
2334 - LIMIT 1",
2335 - $session_id
2336 - )
2337 - );
2338 -
2339 - // Debug: Check email retrieval
2340 - if (empty($email)) {
2341 - //error_log("No email found for session {$session_id}");
2342 - } else {
2343 - //error_log("Email for session {$session_id}: " . $email);
2344 - }
2345 -
2346 - // Get messages for this session ordered by timestamp
2347 - $messages = $wpdb->get_results(
2348 - $wpdb->prepare(
2349 - "SELECT * FROM {$table_name}
2350 - WHERE session_id = %s
2351 - ORDER BY timestamp ASC",
2352 - $session_id
2353 - )
2354 - );
2355 -
2356 - // Start session block
2357 - echo '<div class="mxchat-session">';
2358 - echo '<div class="mxchat-session-header">';
2359 - // Wrap checkbox and session ID in one block
2360 - echo '<div class="mxchat-session-id">';
2361 - echo '<input type="checkbox" name="delete_session_ids[]" value="' . esc_attr($session_id) . '"> ';
2362 - echo '<strong>' . esc_html__('Session ID:', 'mxchat') . '</strong> ' . esc_html($session_id);
2363 - echo '</div>';
2364 -
2365 - // Place email directly below the session ID block
2366 - if (!empty($email)) {
2367 - echo '<div class="mxchat-session-email">';
2368 - echo '<strong>' . esc_html__('Email:', 'mxchat') . '</strong> ' . esc_html($email);
2369 - echo '</div>';
2370 - }
2371 - echo '</div>';
2372 -
2373 - echo '<div class="mxchat-messages">';
2374 -
2375 - // Display messages for this session
2376 - foreach ($messages as $transcript) {
2377 - $formatted_timestamp = date_i18n('F j, Y g:i a', strtotime($transcript->timestamp));
2378 -
2379 - // Determine message styling
2380 - switch ($transcript->role) {
2381 - case 'assistant':
2382 - case 'bot':
2383 - $message_class = 'bot-message';
2384 - $display_role = esc_html__('Chatbot', 'mxchat');
2385 - break;
2386 - case 'user':
2387 - $message_class = 'user-message';
2388 - $display_role = !empty($transcript->user_identifier)
2389 - ? sanitize_text_field($transcript->user_identifier)
2390 - : esc_html__('User', 'mxchat');
2391 - break;
2392 - case 'agent':
2393 - $message_class = 'agent-message';
2394 - $display_role = esc_html__('Agent', 'mxchat');
2395 - break;
2396 - default:
2397 - $message_class = 'unknown-message';
2398 - $display_role = esc_html__('Unknown', 'mxchat');
2399 - }
2400 -
2401 - // Process message content
2402 - $message_content = wp_kses(
2403 - stripslashes($transcript->message),
2404 - [
2405 - 'b' => [], 'strong' => [], 'i' => [], 'em' => [], 'u' => [],
2406 - 'br' => [], 'p' => [], 'ul' => [], 'ol' => [], 'li' => [],
2407 - 'a' => ['href' => [], 'title' => []]
2408 - ]
2409 - );
2410 - $message_content = nl2br($message_content);
2411 -
2412 - // Render message
2413 - echo '<div class="mxchat-message ' . esc_attr($message_class) . '">';
2414 - echo '<div class="mxchat-message-header">' . esc_html($display_role) . '</div>';
2415 - echo '<div class="mxchat-message-content">' . $message_content . '</div>';
2416 - echo '<div class="mxchat-timestamp">' . esc_html($formatted_timestamp) . '</div>';
2417 - echo '</div>';
2418 - }
2419 -
2420 - // Close session block
2421 - echo '</div></div>';
2422 - }
2423 -
2424 - echo '</div>';
2425 - $output = ob_get_clean();
2426 - echo $output;
2427 - wp_die();
2428 -}
2429 -
2430 -
2431 2982 public function mxchat_create_activation_page() {
2432 2983 $license_status = get_option('mxchat_license_status', 'inactive');
2433 2984 $license_error = get_option('mxchat_license_error', '');
2434 2985 ?>
@@ -3037,22 +3588,12 @@
3037 3588
3038 3589 private function mxchat_get_available_callbacks($grouped = false) {
3039 3590 $callbacks = [
3040 3591 'mxchat_handle_email_capture' => [
3041 - 'label' => __('Email Capture', 'mxchat'),
3592 + 'label' => __('Loops Email Capture', 'mxchat'),
3042 3593 'pro_only' => false,
3043 3594 'group' => __('Customer Engagement', 'mxchat'),
3044 3595 ],
3045 - 'mxchat_handle_product_inquiry' => [
3046 - 'label' => __('Show Product Card', 'mxchat'),
3047 - 'pro_only' => true,
3048 - 'group' => __('WooCommerce Features', 'mxchat'),
3049 - ],
3050 - 'mxchat_handle_order_history' => [
3051 - 'label' => __('Order History', 'mxchat'),
3052 - 'pro_only' => true,
3053 - 'group' => __('WooCommerce Features', 'mxchat'),
3054 - ],
3055 3596 'mxchat_generate_image' => [
3056 3597 'label' => __('Generate Image', 'mxchat'),
3057 3598 'pro_only' => true,
3058 3599 'group' => __('Other Features', 'mxchat'),
@@ -3066,28 +3607,13 @@
3066 3607 'label' => __('Brave Image Search', 'mxchat'),
3067 3608 'pro_only' => false,
3068 3609 'group' => __('Search Features', 'mxchat'),
3069 3610 ],
3070 - 'mxchat_handle_add_to_cart_intent' => [
3071 - 'label' => __('Add to Cart', 'mxchat'),
3072 - 'pro_only' => true,
3073 - 'group' => __('WooCommerce Features', 'mxchat'),
3074 - ],
3075 - 'mxchat_handle_checkout_intent' => [
3076 - 'label' => __('Proceed to Checkout', 'mxchat'),
3077 - 'pro_only' => true,
3078 - 'group' => __('WooCommerce Features', 'mxchat'),
3079 - ],
3080 3611 'mxchat_handle_pdf_discussion' => [
3081 3612 'label' => __('Chat with PDF', 'mxchat'),
3082 3613 'pro_only' => true,
3083 3614 'group' => __('Other Features', 'mxchat'),
3084 3615 ],
3085 - 'mxchat_handle_product_recommendations' => [
3086 - 'label' => __('Product Recommendations', 'mxchat'),
3087 - 'pro_only' => true,
3088 - 'group' => __('WooCommerce Features', 'mxchat'),
3089 - ],
3090 3616 'mxchat_live_agent_handover' => [
3091 3617 'label' => __('Live Agent', 'mxchat'),
3092 3618 'pro_only' => true,
3093 3619 'group' => __('Customer Engagement', 'mxchat'),
@@ -3098,8 +3624,11 @@
3098 3624 'group' => __('Customer Engagement', 'mxchat'),
3099 3625 ],
3100 3626 ];
3101 3627
3628 + // Allow other plugins to add their callbacks
3629 + $callbacks = apply_filters('mxchat_available_callbacks', $callbacks);
3630 +
3102 3631 // Return grouped structure if requested
3103 3632 if ($grouped) {
3104 3633 $grouped_callbacks = [];
3105 3634 foreach ($callbacks as $key => $data) {
@@ -3110,14 +3639,12 @@
3110 3639 ];
3111 3640 }
3112 3641 return $grouped_callbacks;
3113 3642 }
3114 -
3115 3643 return $callbacks;
3116 3644 }
3117 3645
3118 3646
3119 -
3120 3647 private function mxchat_average_vectors($vectors) {
3121 3648 $vector_length = count($vectors[0]);
3122 3649 $sum_vector = array_fill(0, $vector_length, 0);
3123 3650
@@ -3203,41 +3730,86 @@
3203 3730 );
3204 3731
3205 3732
3206 3733 // Existing fields...
3207 - add_settings_field(
3208 - 'api_key',
3209 - esc_html__('OpenAI API Key', 'mxchat'),
3210 - array($this, 'api_key_callback'),
3211 - 'mxchat-chatbot',
3212 - 'mxchat_chatbot_section'
3213 - );
3734 + add_settings_field(
3735 + 'api_key',
3736 + esc_html__('OpenAI API Key', 'mxchat'),
3737 + array($this, 'api_key_callback'),
3738 + 'mxchat-chatbot',
3739 + 'mxchat_chatbot_section',
3740 + array(
3741 + 'class' => 'mxchat-setting-row',
3742 + 'data-provider' => 'openai'
3743 + )
3744 + );
3745 +
3746 + add_settings_field(
3747 + 'xai_api_key',
3748 + esc_html__('X.AI API Key', 'mxchat'),
3749 + array($this, 'xai_api_key_callback'),
3750 + 'mxchat-chatbot',
3751 + 'mxchat_chatbot_section',
3752 + array(
3753 + 'class' => 'mxchat-setting-row',
3754 + 'data-provider' => 'xai'
3755 + )
3756 + );
3757 +
3758 + add_settings_field(
3759 + 'claude_api_key',
3760 + esc_html__('Claude API Key', 'mxchat'),
3761 + array($this, 'claude_api_key_callback'),
3762 + 'mxchat-chatbot',
3763 + 'mxchat_chatbot_section',
3764 + array(
3765 + 'class' => 'mxchat-setting-row',
3766 + 'data-provider' => 'claude'
3767 + )
3768 + );
3769 +
3770 + add_settings_field(
3771 + 'deepseek_api_key',
3772 + esc_html__('DeepSeek API Key', 'mxchat'),
3773 + array($this, 'deepseek_api_key_callback'),
3774 + 'mxchat-chatbot',
3775 + 'mxchat_chatbot_section',
3776 + array(
3777 + 'class' => 'mxchat-setting-row',
3778 + 'data-provider' => 'deepseek'
3779 + )
3780 + );
3781 +
3782 + add_settings_field(
3783 + 'voyage_api_key',
3784 + esc_html__('Voyage AI API Key', 'mxchat'),
3785 + array($this, 'voyage_api_key_callback'),
3786 + 'mxchat-chatbot',
3787 + 'mxchat_chatbot_section',
3788 + array(
3789 + 'class' => 'mxchat-setting-row',
3790 + 'data-provider' => 'voyage'
3791 + )
3792 + );
3214 3793
3215 3794 add_settings_field(
3216 - 'xai_api_key',
3217 - esc_html__('X.AI API Key', 'mxchat'),
3218 - array($this, 'xai_api_key_callback'),
3795 + 'model',
3796 + esc_html__('Chat Model', 'mxchat'),
3797 + array($this, 'mxchat_model_callback'),
3219 3798 'mxchat-chatbot',
3220 3799 'mxchat_chatbot_section'
3221 3800 );
3222 -
3801 +
3802 + // Add the settings field
3223 3803 add_settings_field(
3224 - 'claude_api_key',
3225 - esc_html__('Claude API Key', 'mxchat'),
3226 - array($this, 'claude_api_key_callback'),
3804 + 'embedding_model',
3805 + esc_html__('Embedding Model', 'mxchat'),
3806 + array($this, 'embedding_model_callback'),
3227 3807 'mxchat-chatbot',
3228 3808 'mxchat_chatbot_section'
3229 3809 );
3230 -
3810 +
3231 3811 add_settings_field(
3232 - 'deepseek_api_key',
3233 - esc_html__('DeepSeek API Key', 'mxchat'),
3234 - array($this, 'deepseek_api_key_callback'),
3235 - 'mxchat-chatbot',
3236 - 'mxchat_chatbot_section'
3237 - );
3238 -
3239 - add_settings_field(
3240 3812 'system_prompt_instructions',
3241 3813 esc_html__('AI Instructions (Behavior)', 'mxchat'),
3242 3814 array($this, 'system_prompt_instructions_callback'),
3243 3815 'mxchat-chatbot',
@@ -3243,15 +3815,8 @@
3243 3815 'mxchat-chatbot',
3244 3816 'mxchat_chatbot_section'
3245 3817 );
3246 3818
3247 - add_settings_field(
3248 - 'model',
3249 - esc_html__('Model', 'mxchat'),
3250 - array($this, 'mxchat_model_callback'),
3251 - 'mxchat-chatbot',
3252 - 'mxchat_chatbot_section'
3253 - );
3254 3819
3255 3820 add_settings_field(
3256 3821 'top_bar_title',
3257 3822 esc_html__('Top Bar Title', 'mxchat'),
@@ -3365,9 +3930,9 @@
3365 3930 );
3366 3931
3367 3932 add_settings_field(
3368 3933 'popular_question_1',
3369 - esc_html__('Popular Question 1', 'mxchat'),
3934 + esc_html__('Quick Question 1', 'mxchat'),
3370 3935 array($this, 'mxchat_popular_question_1_callback'),
3371 3936 'mxchat-chatbot',
3372 3937 'mxchat_chatbot_section'
3373 3938 );
@@ -3373,9 +3938,9 @@
3373 3938 );
3374 3939
3375 3940 add_settings_field(
3376 3941 'popular_question_2',
3377 - esc_html__('Popular Question 2', 'mxchat'),
3942 + esc_html__('Quick Question 2', 'mxchat'),
3378 3943 array($this, 'mxchat_popular_question_2_callback'),
3379 3944 'mxchat-chatbot',
3380 3945 'mxchat_chatbot_section'
3381 3946 );
@@ -3381,9 +3946,9 @@
3381 3946 );
3382 3947
3383 3948 add_settings_field(
3384 3949 'popular_question_3',
3385 - esc_html__('Popular Question 3', 'mxchat'),
3950 + esc_html__('Quick Question 3', 'mxchat'),
3386 3951 array($this, 'mxchat_popular_question_3_callback'),
3387 3952 'mxchat-chatbot',
3388 3953 'mxchat_chatbot_section'
3389 3954 );
@@ -3389,21 +3954,14 @@
3389 3954 );
3390 3955
3391 3956 add_settings_field(
3392 3957 'additional_popular_questions',
3393 - esc_html__('Additional Popular Questions', 'mxchat'),
3958 + esc_html__('Additional Quick Questions', 'mxchat'),
3394 3959 array($this, 'mxchat_additional_popular_questions_callback'),
3395 3960 'mxchat-chatbot',
3396 3961 'mxchat_chatbot_section'
3397 3962 );
3398 3963
3399 - // WooCommerce Settings Section
3400 - add_settings_section(
3401 - 'mxchat_woocommerce_section',
3402 - esc_html__('WooCommerce Settings', 'mxchat'),
3403 - null,
3404 - 'mxchat-embed'
3405 - );
3406 3964
3407 3965 // Loops Settings Section
3408 3966 add_settings_section(
3409 3967 'mxchat_loops_section',
@@ -3411,33 +3969,8 @@
3411 3969 null,
3412 3970 'mxchat-embed'
3413 3971 );
3414 3972
3415 - // WooCommerce Settings Fields
3416 - add_settings_field(
3417 - 'enable_woocommerce_integration',
3418 - esc_html__('Automatically Embed Products', 'mxchat'),
3419 - array($this, 'mxchat_enable_woocommerce_integration_callback'),
3420 - 'mxchat-embed',
3421 - 'mxchat_woocommerce_section'
3422 - );
3423 -
3424 - add_settings_field(
3425 - 'woocommerce_consumer_key',
3426 - esc_html__('WooCommerce Consumer Key', 'mxchat'),
3427 - array($this, 'mxchat_woocommerce_consumer_key_callback'),
3428 - 'mxchat-embed',
3429 - 'mxchat_woocommerce_section'
3430 - );
3431 -
3432 - add_settings_field(
3433 - 'woocommerce_consumer_secret',
3434 - esc_html__('WooCommerce Consumer Secret', 'mxchat'),
3435 - array($this, 'mxchat_woocommerce_consumer_secret_callback'),
3436 - 'mxchat-embed',
3437 - 'mxchat_woocommerce_section'
3438 - );
3439 -
3440 3973 // Loops Settings Fields
3441 3974 add_settings_field(
3442 3975 'loops_api_key',
3443 3976 esc_html__('Loops API Key', 'mxchat'),
@@ -3540,8 +4073,26 @@
3540 4073 array($this, 'mxchat_chat_toolbar_toggle_callback'),
3541 4074 'mxchat-embed',
3542 4075 'mxchat_pdf_intent_section'
3543 4076 );
4077 +
4078 + // PDF Upload Button Toggle
4079 + add_settings_field(
4080 + 'show_pdf_upload_button',
4081 + __('Show PDF Upload Button', 'mxchat'),
4082 + array($this, 'mxchat_show_pdf_upload_button_callback'),
4083 + 'mxchat-embed',
4084 + 'mxchat_pdf_intent_section'
4085 + );
4086 +
4087 + // Word Upload Button Toggle
4088 + add_settings_field(
4089 + 'show_word_upload_button',
4090 + __('Show Word Upload Button', 'mxchat'),
4091 + array($this, 'mxchat_show_word_upload_button_callback'),
4092 + 'mxchat-embed',
4093 + 'mxchat_pdf_intent_section'
4094 + );
3544 4095
3545 4096 add_settings_field(
3546 4097 'pdf_intent_trigger_text',
3547 4098 __('Intent Trigger Text', 'mxchat'),
@@ -3638,9 +4189,9 @@
3638 4189
3639 4190 // General Settings Section
3640 4191 add_settings_section(
3641 4192 'mxchat_general_section',
3642 - esc_html__('Frequently Asked Questions (FAQ)', 'mxchat'),
4193 + esc_html__('YouTube Tutorials', 'mxchat'),
3643 4194 null,
3644 4195 'mxchat-general'
3645 4196 );
3646 4197 }
@@ -3883,52 +4434,8 @@
3883 4434 echo '</div>';
3884 4435 }
3885 4436
3886 4437
3887 -public function mxchat_enable_woocommerce_integration_callback() {
3888 - // Load from mxchat_options array
3889 - $options = get_option('mxchat_options', []);
3890 -
3891 - // Get WooCommerce integration status with backwards compatibility
3892 - $woo_integration = isset($options['enable_woocommerce_integration'])
3893 - ? $options['enable_woocommerce_integration']
3894 - : '';
3895 -
3896 - // Support both old ('1') and new ('on') values
3897 - $checked = ($woo_integration === 'on' || $woo_integration === '1') ? 'checked' : '';
3898 -
3899 - // Check if the feature is activated (paid feature)
3900 - $disabled = $this->is_activated ? '' : 'disabled';
3901 - $class = $this->is_activated ? 'pro-feature-wrapper active' : 'pro-feature-wrapper inactive';
3902 -
3903 - echo '<div class="' . esc_attr($class) . '">';
3904 -
3905 - echo '<label class="toggle-switch">';
3906 - echo sprintf(
3907 - '<input type="checkbox" id="enable_woocommerce_integration" name="enable_woocommerce_integration" value="on" %s %s />',
3908 - esc_attr($checked),
3909 - esc_attr($disabled)
3910 - );
3911 - echo '<span class="slider"></span>';
3912 - echo '</label>';
3913 -
3914 - 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>';
3915 -
3916 - // Pro feature overlay for non-activated users
3917 - if (!$this->is_activated) {
3918 - echo '<div class="pro-feature-overlay">';
3919 - echo '<a href="https://mxchat.ai/" target="_blank">';
3920 - echo '<img src="' . esc_url(plugin_dir_url(__FILE__) . '../images/pro-only-dark.png') . '" alt="' . esc_attr__('Pro Only', 'mxchat') . '" />';
3921 - echo '</a>';
3922 - echo '</div>';
3923 - }
3924 -
3925 - echo '</div>';
3926 -}
3927 -
3928 -
3929 -
3930 -
3931 4438 private function mxchat_add_option_field($id, $title, $callback = '') {
3932 4439 add_settings_field(
3933 4440 $id,
3934 4441 __($title, 'mxchat'),
@@ -3937,149 +4444,68 @@
3937 4444 'mxchat_setting_section_id',
3938 4445 $id === 'model' ? ['label_for' => 'model'] : []
3939 4446 );
3940 4447 }
3941 -
4448 +
4449 +// OpenAI API Key
3942 4450 public function api_key_callback() {
3943 - // Retrieve from your stored 'api_key' in the mxchat_options array
3944 4451 $apiKey = isset($this->options['api_key']) ? esc_attr($this->options['api_key']) : '';
3945 -
3946 - // Notice we changed the name to "api_key" (no array notation).
4452 +
4453 + echo '<div class="api-key-wrapper" data-provider="openai">';
3947 4454 echo '<input type="password" id="api_key" name="api_key" value="' . $apiKey . '" class="regular-text" />';
3948 4455 echo '<button type="button" id="toggleApiKeyVisibility">' . esc_html__('Show', 'mxchat') . '</button>';
3949 - 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>';
4456 + echo '<p class="description api-key-notice">' . esc_html__('Required for your selected chat model. Important: You must add credits before use.', 'mxchat') . '</p>';
4457 + echo '</div>';
3950 4458 }
4459 +
4460 +// X.AI API Key
3951 4461 public function xai_api_key_callback() {
3952 - // Check if the feature is activated (paid feature)
3953 - $disabled = $this->is_activated ? '' : 'disabled'; // Disable input if not activated
3954 - $class = $this->is_activated ? 'pro-feature-wrapper active' : 'pro-feature-wrapper inactive'; // CSS class to style the wrapper based on activation status
3955 -
3956 - // Retrieve the X.AI API key value
3957 4462 $xaiApiKey = isset($this->options['xai_api_key']) ? esc_attr($this->options['xai_api_key']) : '';
3958 -
3959 - // Render the input field for the X.AI API key
3960 - echo '<div class="' . esc_attr($class) . '">';
3961 - printf(
3962 - '<input type="password" id="xai_api_key" name="xai_api_key" value="%s" class="regular-text" %s />',
3963 - $xaiApiKey,
3964 - $disabled
3965 - );
4463 +
4464 + echo '<div class="api-key-wrapper" data-provider="xai">';
4465 + echo '<input type="password" id="xai_api_key" name="xai_api_key" value="' . $xaiApiKey . '" class="regular-text" />';
3966 4466 echo '<button type="button" id="toggleXaiApiKeyVisibility">' . esc_html__('Show', 'mxchat') . '</button>';
3967 -
3968 - // If the feature is not activated, show the overlay with a "Pro Only" message
3969 - if (!$this->is_activated) {
3970 - echo '<div class="pro-feature-overlay">';
3971 - 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>';
3972 - echo '</div>';
3973 - }
3974 -
4467 + echo '<p class="description api-key-notice">' . esc_html__('Required for your selected chat model. Important: You must add credits before use.', 'mxchat') . '</p>';
3975 4468 echo '</div>';
3976 4469 }
4470 +
4471 +// Claude API Key
3977 4472 public function claude_api_key_callback() {
3978 - // Check if the feature is activated (paid feature)
3979 - $disabled = $this->is_activated ? '' : 'disabled';
3980 - $class = $this->is_activated ? 'pro-feature-wrapper active' : 'pro-feature-wrapper inactive';
3981 -
3982 - // Retrieve the Claude API key value directly like the others
3983 4473 $claudeApiKey = isset($this->options['claude_api_key']) ? esc_attr($this->options['claude_api_key']) : '';
3984 4474
3985 - // Use direct name field like the other working API keys
3986 - echo '<div class="' . esc_attr($class) . '">';
3987 - printf(
3988 - '<input type="password" id="claude_api_key" name="claude_api_key" value="%s" class="regular-text" %s />',
3989 - $claudeApiKey,
3990 - $disabled
3991 - );
4475 + echo '<div class="api-key-wrapper" data-provider="claude">';
4476 + echo '<input type="password" id="claude_api_key" name="claude_api_key" value="' . $claudeApiKey . '" class="regular-text" />';
3992 4477 echo '<button type="button" id="toggleClaudeApiKeyVisibility">' . esc_html__('Show', 'mxchat') . '</button>';
3993 -
3994 - if (!$this->is_activated) {
3995 - echo '<div class="pro-feature-overlay">';
3996 - 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>';
3997 - echo '</div>';
3998 - }
4478 + echo '<p class="description api-key-notice">' . esc_html__('Required for your selected chat model. Important: You must add credits before use.', 'mxchat') . '</p>';
3999 4479 echo '</div>';
4000 4480 }
4481 +
4482 +// DeepSeek API Key
4001 4483 public function deepseek_api_key_callback() {
4002 - // Retrieve from your stored 'deepseek_api_key' in the mxchat_options array
4003 4484 $apiKey = isset($this->options['deepseek_api_key']) ? esc_attr($this->options['deepseek_api_key']) : '';
4004 -
4005 - // Notice we changed the name to "deepseek_api_key" (no array notation).
4485 +
4486 + echo '<div class="api-key-wrapper" data-provider="deepseek">';
4006 4487 echo '<input type="password" id="deepseek_api_key" name="deepseek_api_key" value="' . $apiKey . '" class="regular-text" />';
4007 4488 echo '<button type="button" id="toggleDeepSeekApiKeyVisibility">' . esc_html__('Show', 'mxchat') . '</button>';
4489 + echo '<p class="description api-key-notice">' . esc_html__('Required for your selected chat model. Important: You must add credits before use.', 'mxchat') . '</p>';
4490 + echo '</div>';
4008 4491 }
4009 4492
4010 -
4011 -public function mxchat_woocommerce_consumer_key_callback() {
4012 - // Load the entire 'mxchat_options' array
4013 - $all_options = get_option('mxchat_options', []);
4014 -
4015 - // Retrieve the WooCommerce consumer key or set a default
4016 - $consumer_key = isset($all_options['woocommerce_consumer_key']) ? $all_options['woocommerce_consumer_key'] : '';
4017 -
4018 - // 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 - echo '<div class="' . esc_attr($class) . '">';
4023 -
4024 - // Render the input field
4025 - printf(
4026 - '<input type="text" id="woocommerce_consumer_key" name="woocommerce_consumer_key" value="%s" class="regular-text" %s />',
4027 - esc_attr($consumer_key),
4028 - esc_attr($disabled)
4029 - );
4030 -
4031 - // Description for the input field
4032 - echo '<p class="description">' . esc_html__('Enter your WooCommerce consumer key for integration.', 'mxchat') . '</p>';
4033 -
4034 - // Pro feature overlay for non-activated users
4035 - if (!$this->is_activated) {
4036 - echo '<div class="pro-feature-overlay">';
4037 - 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>';
4038 - echo '</div>';
4039 - }
4040 -
4493 +// Voyage API Key
4494 +public function voyage_api_key_callback() {
4495 + $apiKey = isset($this->options['voyage_api_key']) ? esc_attr($this->options['voyage_api_key']) : '';
4496 +
4497 + echo '<div class="api-key-wrapper" data-provider="voyage">';
4498 + echo '<input type="password" id="voyage_api_key" name="voyage_api_key" value="' . $apiKey . '" class="regular-text" />';
4499 + echo '<button type="button" id="toggleVoyageAPIKeyVisibility">' . esc_html__('Show', 'mxchat') . '</button>';
4500 + echo '<p class="description api-key-notice">' . esc_html__('Required for your selected embedding model. Important: You must add credits before use.', 'mxchat') . '</p>';
4041 4501 echo '</div>';
4042 4502 }
4043 4503
4044 -public function mxchat_woocommerce_consumer_secret_callback() {
4045 - // Get value with fallback
4046 - $consumer_secret = isset($this->options['woocommerce_consumer_secret'])
4047 - ? esc_attr($this->options['woocommerce_consumer_secret'])
4048 - : '';
4049 4504
4050 - // Check if the feature is activated (paid feature)
4051 - $disabled = $this->is_activated ? '' : 'disabled';
4052 - $class = $this->is_activated ? 'pro-feature-wrapper active' : 'pro-feature-wrapper inactive';
4053 4505
4054 - echo '<div class="' . esc_attr($class) . '">';
4055 4506
4056 - // Output the password input
4057 - echo sprintf(
4058 - '<input type="password"
4059 - id="woocommerce_consumer_secret"
4060 - name="woocommerce_consumer_secret"
4061 - value="%s"
4062 - class="regular-text"
4063 - %s />',
4064 - $consumer_secret,
4065 - esc_attr($disabled)
4066 - );
4067 4507
4068 - // Add show/hide button
4069 - echo '<button type="button" id="toggleWooCommerceSecretVisibility">' . esc_html__('Show', 'mxchat') . '</button>';
4070 -
4071 - // Pro feature overlay
4072 - if (!$this->is_activated) {
4073 - echo '<div class="pro-feature-overlay">';
4074 - echo '<a href="https://mxchat.ai/" target="_blank">';
4075 - echo '<img src="' . esc_url(plugin_dir_url(__FILE__) . '../images/pro-only-dark.png') . '" alt="' . esc_attr__('Pro Only', 'mxchat') . '" />';
4076 - echo '</a>';
4077 - echo '</div>';
4078 - }
4079 -
4080 - echo '</div>';
4081 -}
4082 4508 public function mxchat_loops_api_key_callback() {
4083 4509 // Support both old and new format
4084 4510 $loops_api_key = isset($this->options['loops_api_key']) ? esc_attr($this->options['loops_api_key']) : '';
4085 4511
@@ -4089,9 +4515,9 @@
4089 4515 $loops_api_key
4090 4516 );
4091 4517 echo '<button type="button" id="toggleLoopsApiKeyVisibility">' . esc_html__('Show', 'mxchat') . '</button>';
4092 4518 echo '</div>';
4093 - echo '<p class="description">' . esc_html__('Enter your Loops API Key here. (See FAQ for details)', 'mxchat') . '</p>';
4519 + echo '<p class="description">' . esc_html__('Enter your Loops API Key here. Once entered, refreshed page to load list (See FAQ for details)', 'mxchat') . '</p>';
4094 4520 }
4095 4521
4096 4522 public function mxchat_loops_mailing_list_callback() {
4097 4523 // Add error handling and type checking
@@ -4200,9 +4626,10 @@
4200 4626 esc_html__('DeepSeek Models', 'mxchat') => array(
4201 4627 'deepseek-chat' => esc_html__('DeepSeek-V3', 'mxchat'),
4202 4628 ),
4203 4629 esc_html__('Claude Models', 'mxchat') => array(
4204 - 'claude-3-5-sonnet-20241022' => esc_html__('Claude 3.5 Sonnet (Most Intelligent)', 'mxchat'),
4630 + 'claude-3-7-sonnet-20250219' => esc_html__('Claude 3.7 Sonnet (Most Intelligent)', 'mxchat'),
4631 + 'claude-3-5-sonnet-20241022' => esc_html__('Claude 3.5 Sonnet (Intelligent)', 'mxchat'),
4205 4632 'claude-3-opus-20240229' => esc_html__('Claude 3 Opus (Highly Complex Tasks)', 'mxchat'),
4206 4633 'claude-3-sonnet-20240229' => esc_html__('Claude 3 Sonnet (Balanced)', 'mxchat'),
4207 4634 'claude-3-haiku-20240307' => esc_html__('Claude 3 Haiku (Fastest)', 'mxchat')
4208 4635 ),
@@ -4213,40 +4640,63 @@
4213 4640 'gpt-4' => esc_html__('GPT-4 (High Intelligence)', 'mxchat'),
4214 4641 'gpt-3.5-turbo' => esc_html__('GPT-3.5 Turbo (Affordable and Fast)', 'mxchat')
4215 4642 )
4216 4643 );
4217 -
4644 +
4218 4645 // Retrieve the currently selected model from saved options
4219 4646 $selected_model = isset($this->options['model']) ? esc_attr($this->options['model']) : 'gpt-4o';
4220 -
4647 +
4221 4648 // Begin the select dropdown
4222 - echo '<select id="model" name="model">'; // No array notation in name attribute
4223 -
4649 + echo '<select id="model" name="model">';
4650 +
4224 4651 // Iterate over groups of models
4225 4652 foreach ($models as $group_label => $group_models) {
4226 4653 echo '<optgroup label="' . esc_attr($group_label) . '">';
4227 -
4654 +
4228 4655 foreach ($group_models as $model_value => $model_label) {
4229 - // Disable Pro-only models for non-activated users
4230 - $disabled = (!$this->is_activated && ($group_label === esc_html__('X.AI Models', 'mxchat') || $group_label === esc_html__('Claude Models', 'mxchat'))) ? 'disabled' : '';
4231 - $label_suffix = (!$this->is_activated && ($group_label === esc_html__('X.AI Models', 'mxchat') || $group_label === esc_html__('Claude Models', 'mxchat'))) ? esc_html__(' (Pro Only)', 'mxchat') : '';
4232 -
4233 - // Output the option element
4234 - echo '<option value="' . esc_attr($model_value) . '" ' . selected($selected_model, $model_value, false) . ' ' . $disabled . '>' . esc_html($model_label . $label_suffix) . '</option>';
4656 + // All models enabled - no disabled attribute or Pro Only label
4657 + echo '<option value="' . esc_attr($model_value) . '" ' . selected($selected_model, $model_value, false) . '>' . esc_html($model_label) . '</option>';
4235 4658 }
4236 -
4659 +
4237 4660 echo '</optgroup>';
4238 4661 }
4239 -
4662 +
4240 4663 // Close the select dropdown
4241 4664 echo '</select>';
4665 +
4666 + // Updated description to remove mention of Pro-only models
4667 + echo '<p class="description">' . esc_html__('Select the AI model your chatbot will use for chatting.', 'mxchat') . '</p>';
4668 +}
4242 4669
4243 - // Add a description below the dropdown
4244 - echo '<p class="description">' . esc_html__('Select the AI model to use for your chatbot. Pro-only models are marked accordingly.', 'mxchat') . '</p>';
4670 +// Callback function for embedding model selection
4671 +public function embedding_model_callback() {
4672 + $models = array(
4673 + esc_html__('OpenAI Embeddings', 'mxchat') => array(
4674 + 'text-embedding-3-small' => esc_html__('TE3 Small (1536, Efficient)', 'mxchat'),
4675 + 'text-embedding-ada-002' => esc_html__('Ada 2 (1536, Recommended)', 'mxchat'),
4676 + 'text-embedding-3-large' => esc_html__('TE3 Large (3072, Powerful)', 'mxchat'),
4677 + ),
4678 + esc_html__('Voyage AI Embeddings', 'mxchat') => array(
4679 + 'voyage-3-large' => esc_html__('Voyage-3 Large (2048, Most Capable)', 'mxchat'),
4680 + )
4681 + );
4682 +
4683 + $selected_model = isset($this->options['embedding_model']) ? esc_attr($this->options['embedding_model']) : 'text-embedding-ada-002';
4684 +
4685 + echo '<select id="embedding_model" name="embedding_model">';
4686 + foreach ($models as $group_label => $group_models) {
4687 + echo '<optgroup label="' . esc_attr($group_label) . '">';
4688 + foreach ($group_models as $model_value => $model_label) {
4689 + echo '<option value="' . esc_attr($model_value) . '" ' . selected($selected_model, $model_value, false) . '>' . esc_html($model_label) . '</option>';
4690 + }
4691 + echo '</optgroup>';
4692 + }
4693 + echo '</select>';
4694 +echo '<p class="description"><span class="red-warning">IMPORTANT:</span> Select the model for vector embeddings. Changing models is not recommended; if you do, you must delete all existing knowledge & intent data and reconfigure them.</p>';
4695 +
4245 4696 }
4246 4697
4247 4698
4248 -
4249 4699 public function mxchat_top_bar_title_callback() {
4250 4700 // Retrieve the current value of the top bar title from saved options
4251 4701 $top_bar_title = isset($this->options['top_bar_title']) ? esc_attr($this->options['top_bar_title']) : '';
4252 4702
@@ -4909,13 +5359,13 @@
4909 5359 // Render the input field
4910 5360 printf(
4911 5361 '<input type="text" id="popular_question_1" name="popular_question_1" value="%s" placeholder="%s" class="regular-text" />',
4912 5362 esc_attr($popular_question_1),
4913 - esc_attr__('Enter Popular Question 1', 'mxchat')
5363 + esc_attr__('Enter Quick Question 1', 'mxchat')
4914 5364 );
4915 5365
4916 5366 // Add a description for the field
4917 - echo '<p class="description">' . esc_html__('This will be the first popular question in the chatbot.', 'mxchat') . '</p>';
5367 + echo '<p class="description">' . esc_html__('This will be the first Quick Question in the chatbot, displayed above the input field.', 'mxchat') . '</p>';
4918 5368 }
4919 5369
4920 5370
4921 5371 public function mxchat_popular_question_2_callback() {
@@ -4928,13 +5378,13 @@
4928 5378 // Render the input field
4929 5379 printf(
4930 5380 '<input type="text" id="popular_question_2" name="popular_question_2" value="%s" placeholder="%s" class="regular-text" />',
4931 5381 esc_attr($popular_question_2),
4932 - esc_attr__('Enter Popular Question 2', 'mxchat')
5382 + esc_attr__('Enter Quick Question 2', 'mxchat')
4933 5383 );
4934 5384
4935 5385 // Add a description for the field
4936 - echo '<p class="description">' . esc_html__('This will be the second popular question in the chatbot.', 'mxchat') . '</p>';
5386 + echo '<p class="description">' . esc_html__('This will be the second Quick Question in the chatbot.', 'mxchat') . '</p>';
4937 5387 }
4938 5388
4939 5389
4940 5390 public function mxchat_popular_question_3_callback() {
@@ -4947,13 +5397,13 @@
4947 5397 // Render the input field
4948 5398 printf(
4949 5399 '<input type="text" id="popular_question_3" name="popular_question_3" value="%s" placeholder="%s" class="regular-text" />',
4950 5400 esc_attr($popular_question_3),
4951 - esc_attr(__('Enter Popular Question 3', 'mxchat'))
5401 + esc_attr(__('Enter Quick Question 3', 'mxchat'))
4952 5402 );
4953 5403
4954 5404 // Add a description for the field
4955 - echo '<p class="description">' . esc_html__('This will be the third popular question in the chatbot.', 'mxchat') . '</p>';
5405 + echo '<p class="description">' . esc_html__('This will be the third Quick Question in the chatbot.', 'mxchat') . '</p>';
4956 5406 }
4957 5407
4958 5408 public function mxchat_additional_popular_questions_callback() {
4959 5409 $options = get_option('mxchat_options', []);
@@ -4974,9 +5424,9 @@
4974 5424 <button type="button" class="button mxchat-remove-question"
4975 5425 aria-label="%s">%s</button>
4976 5426 </div>',
4977 5427 esc_attr($question),
4978 - esc_attr(sprintf(__('Enter Additional Popular Question %d', 'mxchat'), $index + 4)),
5428 + esc_attr(sprintf(__('Enter Additional Quick Question %d', 'mxchat'), $index + 4)),
4979 5429 $index,
4980 5430 esc_attr(__('Remove question', 'mxchat')),
4981 5431 esc_html__('Remove', 'mxchat')
4982 5432 );
@@ -4991,9 +5441,9 @@
4991 5441 data-question-index="0" />
4992 5442 <button type="button" class="button mxchat-remove-question"
4993 5443 aria-label="%s">%s</button>
4994 5444 </div>',
4995 - esc_attr(__('Enter Additional Popular Question 4', 'mxchat')),
5445 + esc_attr(__('Enter Additional Quick Question 4', 'mxchat')),
4996 5446 esc_attr(__('Remove question', 'mxchat')),
4997 5447 esc_html__('Remove', 'mxchat')
4998 5448 );
4999 5449 }
@@ -5002,9 +5452,9 @@
5002 5452 '<button type="button" class="button mxchat-add-question" aria-label="%s">%s</button>',
5003 5453 esc_attr(__('Add question', 'mxchat')),
5004 5454 esc_html__('Add Question', 'mxchat')
5005 5455 );
5006 - echo '<p class="description">' . esc_html__('Add as many popular questions as you need.', 'mxchat') . '</p>';
5456 + echo '<p class="description">' . esc_html__('Add as many Quick Questions as you need.', 'mxchat') . '</p>';
5007 5457 echo '</div>';
5008 5458 }
5009 5459
5010 5460 public function mxchat_brave_api_key_callback() {
@@ -5136,9 +5586,78 @@
5136 5586 echo '</div>';
5137 5587 echo '<p class="description">' . esc_html__('Enable to display the chat toolbar, adding two icons below the chatbot input field for uploading PDF and Word documents (default is hidden).', 'mxchat') . '</p>';
5138 5588 }
5139 5589
5590 +/**
5591 + * Callback for PDF upload button toggle setting
5592 + */
5593 +public function mxchat_show_pdf_upload_button_callback() {
5594 + // Get toggle value with fallback
5595 + $show_pdf_button = isset($this->options['show_pdf_upload_button']) ? $this->options['show_pdf_upload_button'] : 'on';
5596 + $checked = ($show_pdf_button === 'on') ? 'checked' : '';
5597 + // Check if the plugin is activated (paid feature)
5598 + $disabled = $this->is_activated ? '' : 'disabled';
5599 + $class = $this->is_activated ? 'pro-feature-wrapper active' : 'pro-feature-wrapper inactive';
5600 +
5601 + echo '<div class="' . esc_attr($class) . '">';
5602 + // Output the toggle switch
5603 + echo '<label class="toggle-switch">';
5604 + echo sprintf(
5605 + '<input type="checkbox" id="show_pdf_upload_button" name="show_pdf_upload_button" value="on" %s %s />',
5606 + esc_attr($checked),
5607 + esc_attr($disabled)
5608 + );
5609 + echo '<span class="slider"></span>';
5610 + echo '</label>';
5611 +
5612 + // Pro feature overlay if needed
5613 + if (!$this->is_activated) {
5614 + echo '<div class="pro-feature-overlay">';
5615 + echo '<a href="https://mxchat.ai/" target="_blank">';
5616 + echo '<img src="' . esc_url(plugin_dir_url(__FILE__) . '../images/pro-only-dark.png') . '" alt="' . esc_attr__('Pro Only', 'mxchat') . '" />';
5617 + echo '</a>';
5618 + echo '</div>';
5619 + }
5620 +
5621 + echo '</div>';
5622 + echo '<p class="description">' . esc_html__('Enable to show the PDF upload button in the chatbot toolbar. Disable to hide it.', 'mxchat') . '</p>';
5623 +}
5140 5624
5625 +/**
5626 + * Callback for Word upload button toggle setting
5627 + */
5628 +public function mxchat_show_word_upload_button_callback() {
5629 + // Get toggle value with fallback
5630 + $show_word_button = isset($this->options['show_word_upload_button']) ? $this->options['show_word_upload_button'] : 'on';
5631 + $checked = ($show_word_button === 'on') ? 'checked' : '';
5632 + // Check if the plugin is activated (paid feature)
5633 + $disabled = $this->is_activated ? '' : 'disabled';
5634 + $class = $this->is_activated ? 'pro-feature-wrapper active' : 'pro-feature-wrapper inactive';
5635 +
5636 + echo '<div class="' . esc_attr($class) . '">';
5637 + // Output the toggle switch
5638 + echo '<label class="toggle-switch">';
5639 + echo sprintf(
5640 + '<input type="checkbox" id="show_word_upload_button" name="show_word_upload_button" value="on" %s %s />',
5641 + esc_attr($checked),
5642 + esc_attr($disabled)
5643 + );
5644 + echo '<span class="slider"></span>';
5645 + echo '</label>';
5646 +
5647 + // Pro feature overlay if needed
5648 + if (!$this->is_activated) {
5649 + echo '<div class="pro-feature-overlay">';
5650 + echo '<a href="https://mxchat.ai/" target="_blank">';
5651 + echo '<img src="' . esc_url(plugin_dir_url(__FILE__) . '../images/pro-only-dark.png') . '" alt="' . esc_attr__('Pro Only', 'mxchat') . '" />';
5652 + echo '</a>';
5653 + echo '</div>';
5654 + }
5655 +
5656 + echo '</div>';
5657 + echo '<p class="description">' . esc_html__('Enable to show the Word document upload button in the chatbot toolbar. Disable to hide it.', 'mxchat') . '</p>';
5658 +}
5659 +
5141 5660 public function mxchat_pdf_intent_trigger_text_callback() {
5142 5661 $disabled = $this->is_activated ? '' : 'disabled';
5143 5662 $class = $this->is_activated ? 'pro-feature-wrapper active' : 'pro-feature-wrapper inactive';
5144 5663 $default_text = __("Please provide the URL to the PDF you'd like to discuss.", 'mxchat');
@@ -5359,24 +5878,21 @@
5359 5878 }
5360 5879 echo '</div>';
5361 5880 }
5362 5881
5363 -
5364 5882 public function mxchat_similarity_threshold_callback() {
5365 5883 // Load from mxchat_options array
5366 5884 $options = get_option('mxchat_options', []);
5367 -
5368 - // Get value with backwards compatibility
5369 - $threshold = isset($options['similarity_threshold'])
5370 - ? $options['similarity_threshold']
5371 - : get_option('mxchat_similarity_threshold', 80);
5372 -
5885 +
5886 + // Get value from options array with default of 80
5887 + $threshold = isset($options['similarity_threshold']) ? $options['similarity_threshold'] : 35;
5888 +
5373 5889 echo '<div class="slider-container">';
5374 5890 echo sprintf(
5375 5891 '<input type="range"
5376 5892 id="similarity_threshold"
5377 5893 name="similarity_threshold"
5378 - min="70"
5894 + min="20"
5379 5895 max="85"
5380 5896 step="1"
5381 5897 value="%s"
5382 5898 class="range-slider" />',
@@ -5386,16 +5902,14 @@
5386 5902 '<span id="threshold_value" class="range-value">%s</span>',
5387 5903 esc_html($threshold)
5388 5904 );
5389 5905 echo '</div>';
5390 -
5391 5906 echo '<p class="description">';
5392 - echo esc_html__('Set the similarity threshold (recommended: 75) to balance accuracy; too high might limit your bot\'s ability to find relevant knowledge.', 'mxchat');
5907 + echo esc_html__('Set the similarity threshold to balance accuracy; too high might limit your bot\'s ability to find relevant knowledge. If your bot is not matching content, move to lowest setting to test.', 'mxchat');
5393 5908 echo '</p>';
5394 5909 }
5395 5910
5396 5911
5397 -
5398 5912 public function mxchat_live_agent_secret_key_callback() {
5399 5913 $disabled = $this->is_activated ? '' : 'disabled';
5400 5914 $class = $this->is_activated ? 'pro-feature-wrapper active' : 'pro-feature-wrapper inactive';
5401 5915
@@ -5440,9 +5954,9 @@
5440 5954 public function mxchat_enqueue_admin_assets() {
5441 5955 wp_enqueue_style('wp-color-picker');
5442 5956
5443 5957 // Get the plugin version or file modification time for cache busting
5444 - $plugin_version = '2.0.3'; // Replace this with your plugin's version
5958 + $plugin_version = '2.1.1'; // Replace this with your plugin's version
5445 5959
5446 5960 // File paths
5447 5961 $color_picker_js_path = plugin_dir_path(__FILE__) . '../js/my-color-picker.js';
5448 5962 $embedding_check_js_path = plugin_dir_path(__FILE__) . '../js/embedding-check.js';
@@ -5448,10 +5962,12 @@
5448 5962 $embedding_check_js_path = plugin_dir_path(__FILE__) . '../js/embedding-check.js';
5449 5963 $admin_css_path = plugin_dir_path(__FILE__) . '../css/admin-style.css';
5450 5964 $knowledge_css_path = plugin_dir_path(__FILE__) . '../css/knowledge-style.css';
5451 5965 $intent_css_path = plugin_dir_path(__FILE__) . '../css/intent-style.css';
5966 + $transcripts_css_path = plugin_dir_path(__FILE__) . '../css/chat-transcripts.css';
5452 5967 $transcripts_js_path = plugin_dir_path(__FILE__) . '../js/mxchat_transcripts.js';
5453 5968
5969 +
5454 5970 // Check if files exist and get modification times
5455 5971 $color_picker_version = file_exists($color_picker_js_path) ? filemtime($color_picker_js_path) : $plugin_version;
5456 5972 $embedding_check_version = file_exists($embedding_check_js_path) ? filemtime($embedding_check_js_path) : $plugin_version;
5457 5973 $admin_css_version = file_exists($admin_css_path) ? filemtime($admin_css_path) : $plugin_version;
@@ -5456,10 +5972,36 @@
5456 5972 $embedding_check_version = file_exists($embedding_check_js_path) ? filemtime($embedding_check_js_path) : $plugin_version;
5457 5973 $admin_css_version = file_exists($admin_css_path) ? filemtime($admin_css_path) : $plugin_version;
5458 5974 $knowledge_css_version = file_exists($knowledge_css_path) ? filemtime($knowledge_css_path) : $plugin_version;
5459 5975 $intent_css_version = file_exists($intent_css_path) ? filemtime($intent_css_path) : $plugin_version;
5976 + $transcripts_css_version = file_exists($transcripts_css_path) ? filemtime($transcripts_css_path) : $plugin_version;
5460 5977 $transcripts_js_version = file_exists($transcripts_js_path) ? filemtime($transcripts_js_path) : $plugin_version;
5461 -
5978 +
5979 + $admin_status_js_path = plugin_dir_path(__FILE__) . '../js/admin-status.js';
5980 + $admin_status_js_version = file_exists($admin_status_js_path) ? filemtime($admin_status_js_path) : $plugin_version;
5981 +
5982 +
5983 + // Only enqueue on the prompts page
5984 + if (isset($_GET['page']) && $_GET['page'] === 'mxchat-prompts') {
5985 + wp_enqueue_script(
5986 + 'mxchat-status-updater',
5987 + plugin_dir_url(__FILE__) . '../js/admin-status.js',
5988 + array('jquery'),
5989 + $admin_status_js_version,
5990 + true
5991 + );
5992 +
5993 + // Add the nonce for the status updater
5994 + wp_localize_script(
5995 + 'mxchat-status-updater',
5996 + 'mxchat_status_data',
5997 + array(
5998 + 'ajax_url' => admin_url('admin-ajax.php'),
5999 + 'nonce' => wp_create_nonce('mxchat_status_nonce')
6000 + )
6001 + );
6002 + }
6003 +
5462 6004 // Enqueue scripts and styles with corrected paths
5463 6005 wp_enqueue_script(
5464 6006 'mxchat-color-picker',
5465 6007 plugin_dir_url(__FILE__) . '../js/my-color-picker.js',
@@ -5476,16 +6018,8 @@
5476 6018 true
5477 6019 );
5478 6020
5479 6021 wp_enqueue_script(
5480 - 'mxchat-transcripts-js',
5481 - plugin_dir_url(__FILE__) . '../js/mxchat_transcripts.js',
5482 - array('jquery'),
5483 - $transcripts_js_version,
5484 - true
5485 - );
5486 -
5487 - wp_enqueue_script(
5488 6022 'mxchat-admin-js',
5489 6023 plugin_dir_url(__FILE__) . '../js/mxchat-admin.js',
5490 6024 array('jquery'),
5491 6025 $plugin_version,
@@ -5496,8 +6030,9 @@
5496 6030 'ajax_url' => admin_url('admin-ajax.php'),
5497 6031 'license_nonce' => wp_create_nonce('mxchat_activate_license_nonce'),
5498 6032 'inline_edit_nonce' => wp_create_nonce('mxchat_save_inline_nonce'),
5499 6033 'setting_nonce' => wp_create_nonce('mxchat_save_setting_nonce'),
6034 + 'export_nonce' => wp_create_nonce('mxchat_export_transcripts'),
5500 6035 ));
5501 6036
5502 6037 // Enqueue the admin CSS
5503 6038 wp_enqueue_style(
@@ -5505,9 +6040,26 @@
5505 6040 plugin_dir_url(__FILE__) . '../css/admin-style.css',
5506 6041 array(),
5507 6042 $admin_css_version
5508 6043 );
5509 -
6044 +
6045 + if (isset($_GET['page']) && $_GET['page'] === 'mxchat-transcripts') {
6046 + wp_enqueue_style(
6047 + 'mxchat-chat-transcripts-css',
6048 + plugin_dir_url(__FILE__) . '../css/chat-transcripts.css',
6049 + array(),
6050 + $transcripts_css_version
6051 + );
6052 +
6053 + wp_enqueue_script(
6054 + 'mxchat-transcripts-js',
6055 + plugin_dir_url(__FILE__) . '../js/mxchat_transcripts.js',
6056 + array('jquery'),
6057 + $transcripts_js_version,
6058 + true
6059 + );
6060 + }
6061 +
5510 6062 wp_enqueue_style(
5511 6063 'mxchat-knowledge-css',
5512 6064 plugin_dir_url(__FILE__) . '../css/knowledge-style.css',
5513 6065 array(),
@@ -5557,8 +6109,10 @@
5557 6109 'live_agent_bot_token' => $this->options['live_agent_bot_token'] ?? '',
5558 6110 'live_agent_message_bg_color' => $this->options['live_agent_message_bg_color'] ?? '#ffffff',
5559 6111 'live_agent_message_font_color' => $this->options['live_agent_message_font_color'] ?? '#333333',
5560 6112 'chat_toolbar_toggle' => $this->options['chat_toolbar_toggle'] ?? 'off',
6113 + 'show_pdf_upload_button' => $this->options['show_pdf_upload_button'] ?? 'on', // Add this line
6114 + 'show_word_upload_button' => $this->options['show_word_upload_button'] ?? 'on', // Add this line
5561 6115 'mode_indicator_bg_color' => $this->options['mode_indicator_bg_color'] ?? '#767676',
5562 6116 'mode_indicator_font_color' => $this->options['mode_indicator_font_color'] ?? '#ffffff',
5563 6117 'toolbar_icon_color' => $this->options['toolbar_icon_color'] ?? '#212121',
5564 6118 ));
@@ -5573,9 +6127,9 @@
5573 6127 }
5574 6128
5575 6129 if (isset($input['similarity_threshold'])) {
5576 6130 $new_input['similarity_threshold'] = absint($input['similarity_threshold']); // Ensure it's an integer
5577 - $new_input['similarity_threshold'] = min(max($new_input['similarity_threshold'], 70), 85); // Enforce range
6131 + $new_input['similarity_threshold'] = min(max($new_input['similarity_threshold'], 20), 85); // Enforce range
5578 6132 }
5579 6133
5580 6134 if (isset($input['xai_api_key'])) {
5581 6135 $new_input['xai_api_key'] = sanitize_text_field($input['xai_api_key']);
@@ -5679,8 +6233,25 @@
5679 6233
5680 6234 if (isset($input['pre_chat_message'])) {
5681 6235 $new_input['pre_chat_message'] = sanitize_textarea_field($input['pre_chat_message']);
5682 6236 }
6237 +
6238 + if (isset($input['voyage_api_key'])) {
6239 + $new_input['voyage_api_key'] = sanitize_text_field($input['voyage_api_key']);
6240 + }
6241 +
6242 + // Add to your sanitize function
6243 + if (isset($input['embedding_model'])) {
6244 + $allowed_models = array(
6245 + 'text-embedding-ada-002',
6246 + 'text-embedding-3-small',
6247 + 'text-embedding-3-large',
6248 + 'voyage-3-large'
6249 + );
6250 + if (in_array($input['embedding_model'], $allowed_models)) {
6251 + $new_input['embedding_model'] = sanitize_text_field($input['embedding_model']);
6252 + }
6253 + }
5683 6254
5684 6255 if (isset($input['model'])) {
5685 6256 $allowed_models = array(
5686 6257 'grok-beta',
@@ -5685,8 +6256,9 @@
5685 6256 $allowed_models = array(
5686 6257 'grok-beta',
5687 6258 'grok-2',
5688 6259 'deepseek-chat',
6260 + 'claude-3-7-sonnet-20250219',
5689 6261 'claude-3-5-sonnet-20241022',
5690 6262 'claude-3-opus-20240229',
5691 6263 'claude-3-sonnet-20240229',
5692 6264 'claude-3-haiku-20240307',
@@ -5855,8 +6427,22 @@
5855 6427
5856 6428 if (isset($input['chat_toolbar_toggle'])) {
5857 6429 $new_input['chat_toolbar_toggle'] = $input['chat_toolbar_toggle'] === 'on' ? 'on' : 'off';
5858 6430 }
6431 +
6432 + // Sanitize PDF upload button toggle
6433 + if (isset($input['show_pdf_upload_button'])) {
6434 + $new_input['show_pdf_upload_button'] = $input['show_pdf_upload_button'] === 'on' ? 'on' : 'off';
6435 + } else {
6436 + $new_input['show_pdf_upload_button'] = 'off'; // If checkbox is unchecked
6437 + }
6438 +
6439 + // Sanitize Word upload button toggle
6440 + if (isset($input['show_word_upload_button'])) {
6441 + $new_input['show_word_upload_button'] = $input['show_word_upload_button'] === 'on' ? 'on' : 'off';
6442 + } else {
6443 + $new_input['show_word_upload_button'] = 'off'; // If checkbox is unchecked
6444 + }
5859 6445
5860 6446 if (isset($input['pdf_intent_trigger_text'])) {
5861 6447 $new_input['pdf_intent_trigger_text'] = sanitize_text_field($input['pdf_intent_trigger_text']);
5862 6448 }
@@ -6011,8 +6597,69 @@
6011 6597 }
6012 6598 }
6013 6599
6014 6600
6601 +/**
6602 + * Display admin notices from transients
6603 + */
6604 +public function display_admin_notices() {
6605 + // Check if we're on the right admin page
6606 + $screen = get_current_screen();
6607 + if (!$screen || $screen->base !== 'toplevel_page_mxchat-prompts') {
6608 + return;
6609 + }
6610 +
6611 + // Check for error notices
6612 + $error_notice = get_transient('mxchat_admin_notice_error');
6613 + if ($error_notice) {
6614 + echo '<div class="notice notice-error is-dismissible"><p>' . esc_html($error_notice) . '</p></div>';
6615 + delete_transient('mxchat_admin_notice_error');
6616 + }
6617 +
6618 + // Check for success notices
6619 + $success_notice = get_transient('mxchat_admin_notice_success');
6620 + if ($success_notice) {
6621 + echo '<div class="notice notice-success is-dismissible"><p>' . esc_html($success_notice) . '</p></div>';
6622 + delete_transient('mxchat_admin_notice_success');
6623 + }
6624 +
6625 + // Check for info notices
6626 + $info_notice = get_transient('mxchat_admin_notice_info');
6627 + if ($info_notice) {
6628 + echo '<div class="notice notice-info is-dismissible"><p>' . esc_html($info_notice) . '</p></div>';
6629 + delete_transient('mxchat_admin_notice_info');
6630 + }
6631 +
6632 + // Display active processing status
6633 + $this->display_processing_status();
6634 +}
6635 +
6636 +/**
6637 + * Display current processing status
6638 + */
6639 +private function display_processing_status() {
6640 + $pdf_url = get_transient('mxchat_last_pdf_url');
6641 + $sitemap_url = get_transient('mxchat_last_sitemap_url');
6642 +
6643 + if (!$pdf_url && !$sitemap_url) {
6644 + return;
6645 + }
6646 +
6647 + $pdf_status = $pdf_url ? $this->get_pdf_processing_status($pdf_url) : false;
6648 + $sitemap_status = $sitemap_url ? $this->get_sitemap_processing_status($sitemap_url) : false;
6649 +
6650 + if ($sitemap_status && isset($sitemap_status['error']) && !empty($sitemap_status['error'])) {
6651 + echo '<div class="notice notice-error is-dismissible">';
6652 + echo '<p><strong>' . esc_html__('Sitemap Processing Error:', 'mxchat') . '</strong> ' . esc_html($sitemap_status['error']) . '</p>';
6653 + echo '</div>';
6654 + }
6655 +
6656 + if ($pdf_status && isset($pdf_status['error']) && !empty($pdf_status['error'])) {
6657 + echo '<div class="notice notice-error is-dismissible">';
6658 + echo '<p><strong>' . esc_html__('PDF Processing Error:', 'mxchat') . '</strong> ' . esc_html($pdf_status['error']) . '</p>';
6659 + echo '</div>';
6660 + }
6661 +}
6015 6662
6016 6663
6017 6664 }
6018 6665 ?>