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 +891 -359 2.0.62.1.1 View file →
@@ -56,8 +56,12 @@
56 56 add_action('wp_insert_post', array($this, 'mxchat_handle_product_change'), 10, 3);
57 57 add_action('wp_trash_post', array($this, 'mxchat_handle_product_delete'));
58 58 add_action('before_delete_post', array($this, 'mxchat_handle_product_delete'));
59 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 +
60 64 }
61 65
62 66 // Method to check if the license is active
63 67 private function is_license_active() {
@@ -117,8 +121,10 @@
117 121 'pdf_intent_trigger_text' => esc_html__("Please provide the URL to the PDF you'd like to discuss.", 'mxchat'),
118 122 'pdf_intent_success_text' => esc_html__("I've processed the PDF. What questions do you have about it?", 'mxchat'),
119 123 'pdf_intent_error_text' => esc_html__("Sorry, I couldn't process the PDF. Please ensure it's a valid file.", 'mxchat'),
120 124 'pdf_max_pages' => 69,
125 + 'show_pdf_upload_button' => 'on',
126 + 'show_word_upload_button' => 'on',
121 127
122 128 // Live Agent Integration
123 129 'live_agent_webhook_url' => '',
124 130 'live_agent_secret_key' => '',
@@ -186,14 +192,14 @@
186 192 array($this, 'mxchat_create_transcripts_page')
187 193 );
188 194
189 195 add_submenu_page(
190 - 'mxchat-max',
191 - esc_html__('MxChat Intents', 'mxchat'),
192 - esc_html__('Intents', 'mxchat'),
193 - 'manage_options',
194 - 'mxchat-intents',
195 - array($this, 'mxchat_intents_page_html')
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')
196 202 );
197 203
198 204 add_submenu_page(
199 205 'mxchat-max',
@@ -225,16 +231,20 @@
225 231 check_ajax_referer('mxchat_save_setting_nonce');
226 232 if (!current_user_can('manage_options')) {
227 233 wp_send_json_error(['message' => esc_html__('Unauthorized', 'mxchat')]);
228 234 }
235 +
229 236 $name = isset($_POST['name']) ? $_POST['name'] : '';
230 237 // Strip slashes from the value before saving
231 238 $value = isset($_POST['value']) ? stripslashes($_POST['value']) : '';
239 +
232 240 if (empty($name)) {
233 241 wp_send_json_error(['message' => esc_html__('Invalid field name', 'mxchat')]);
234 242 }
243 +
235 244 // Load the full options array
236 245 $options = get_option('mxchat_options', []);
246 +
237 247 // Handle special cases
238 248 switch ($name) {
239 249 case 'additional_popular_questions':
240 250 $questions = json_decode($value, true); // No need for stripslashes here
@@ -243,8 +253,12 @@
243 253 // Also update old option for backwards compatibility
244 254 update_option('additional_popular_questions', $questions);
245 255 }
246 256 break;
257 + case 'similarity_threshold':
258 + // Save to the options array
259 + $options[$name] = $value;
260 + break;
247 261 case 'user_message_bg_color':
248 262 case 'user_message_font_color':
249 263 case 'bot_message_bg_color':
250 264 case 'bot_message_font_color':
@@ -289,9 +303,11 @@
289 303 if (strpos($name, 'toggle') !== false || in_array($name, [
290 304 'chat_persistence_toggle',
291 305 'privacy_toggle',
292 306 'complianz_toggle',
293 - 'chat_toolbar_toggle' // Removed live_agent_status from here
307 + 'chat_toolbar_toggle',
308 + 'show_pdf_upload_button',
309 + 'show_word_upload_button'
294 310 ])) {
295 311 $options[$name] = ($value === 'on') ? 'on' : 'off';
296 312 } else {
297 313 // Store all other values directly
@@ -298,17 +314,12 @@
298 314 $options[$name] = $value;
299 315 }
300 316 break;
301 317 }
302 - // Save all updates
318 +
319 + // Save all updates to the options array
303 320 $updated = update_option('mxchat_options', $options);
304 - // Handle backwards compatibility for certain fields
305 - $legacy_fields = ['brave_api_key', 'brave_image_count', 'brave_safe_search', 'brave_news_count',
306 - 'brave_country', 'brave_language', 'similarity_threshold'];
307 - if (in_array($name, $legacy_fields)) {
308 - // Also update the individual option for backwards compatibility
309 - update_option($name, $value);
310 - }
321 +
311 322 if ($updated) {
312 323 wp_send_json_success(['message' => esc_html__('Setting saved', 'mxchat')]);
313 324 } else {
314 325 wp_send_json_error(['message' => esc_html__('Update failed or no changes', 'mxchat')]);
@@ -313,9 +324,8 @@
313 324 } else {
314 325 wp_send_json_error(['message' => esc_html__('Update failed or no changes', 'mxchat')]);
315 326 }
316 327 }
317 -
318 328 /**
319 329 * Handles AJAX auto-save for prompts and auto-sync settings.
320 330 */
321 331 public function mxchat_save_prompts_setting_callback() {
@@ -399,181 +409,215 @@
399 409
400 410 public function mxchat_create_admin_page() {
401 411
402 412 ?>
403 - <div class="wrap mxchat-admin">
404 - <?php if (!$this->is_activated): ?>
405 - <div class="mxchat-pro-banner">
406 - <p>
407 - <?php echo esc_html__('For a limited time, get lifetime access and save $20 on MxChat Pro!', 'mxchat'); ?>
408 - <a href="https://mxchat.ai/" target="_blank"><?php echo esc_html__('Upgrade to Pro today', 'mxchat'); ?></a>
409 - </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>
410 422 </div>
411 - <?php endif; ?>
412 423
413 - <div class="mxchat-agents-banner">
414 - <p>
415 - <strong><?php echo esc_html__('The MxChat Add-Ons Platform', 'mxchat'); ?></strong><?php echo esc_html__(' is here! Pro users get unlimited access to our growing collection of powerful add-ons. ', 'mxchat'); ?><a href="<?php echo admin_url('admin.php?page=mxchat-addons'); ?>"><?php echo esc_html__('Explore all add-ons', 'mxchat'); ?></a><?php echo esc_html__(' including Forms Builder, Theme Customizer, Content Moderation, and more – all included with your lifetime Pro license!', 'mxchat'); ?>
416 - </p>
417 - </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; ?>
418 439
419 - <h2 class="mxchat-nav-tab-wrapper">
420 - <a href="#chatbot" class="mxchat-nav-tab mxchat-nav-tab-active" data-tab="chatbot"><?php echo esc_html__('Chatbot', 'mxchat'); ?></a>
421 - <a href="#embed" class="mxchat-nav-tab" data-tab="embed"><?php echo esc_html__('Integrations', 'mxchat'); ?></a>
422 - <a href="#general" class="mxchat-nav-tab" data-tab="general"><?php echo esc_html__('FAQ', 'mxchat'); ?></a>
423 - </h2>
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>
445 + </div>
424 446
425 - <div id="chatbot" class="mxchat-tab-content active">
426 - <div class="mxchat-autosave-section">
427 - <?php do_settings_sections('mxchat-chatbot'); ?>
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>
453 + </div>
428 454 </div>
429 - </div>
430 455
431 - <div id="embed" class="mxchat-tab-content">
432 - <div class="mxchat-autosave-section">
433 -
434 - <div class="mxchat-settings-section">
435 - <h2><?php echo esc_html__('Loops Settings', 'mxchat'); ?></h2>
436 - <table class="form-table">
437 - <?php do_settings_fields('mxchat-embed', 'mxchat_loops_section'); ?>
438 - </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>
439 464 </div>
440 465
441 - <div class="section-divider"></div>
442 -
443 - <div class="mxchat-settings-section">
444 - <h2><?php echo esc_html__('Brave Search Settings', 'mxchat'); ?></h2>
445 - <table class="form-table">
446 - <?php do_settings_fields('mxchat-embed', 'mxchat_brave_section'); ?>
447 - </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>
448 473 </div>
449 474
450 - <div class="section-divider"></div>
451 -
452 - <div class="mxchat-settings-section">
453 - <h2><?php echo esc_html__('Toolbar Settings & Intents', 'mxchat'); ?></h2>
454 - <table class="form-table">
455 - <?php do_settings_fields('mxchat-embed', 'mxchat_pdf_intent_section'); ?>
456 - </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>
457 482 </div>
458 483
459 - <div class="section-divider"></div>
460 -
461 - <!-- Live Agent Settings Section -->
462 - <div class="mxchat-settings-section">
463 - <h2><?php echo esc_html__('Live Agent Settings', 'mxchat'); ?></h2>
464 - <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>
465 - <table class="form-table">
466 - <?php do_settings_fields('mxchat-embed', 'mxchat_live_agent_section'); ?>
467 - </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>
468 492 </div>
469 493 </div>
470 - </div>
471 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">
472 499
473 - <div id="general" class="mxchat-tab-content">
474 - <?php do_settings_sections('mxchat-general'); ?>
475 - <p>
476 - <?php echo esc_html__('If you’re having trouble with setup or getting the responses you need, we encourage you to review our', 'mxchat'); ?>
477 - <a href="https://mxchat.ai/documentation/" target="_blank" rel="noopener noreferrer"><?php echo esc_html__('documentation', 'mxchat'); ?></a> <?php echo esc_html__('or', 'mxchat'); ?>
478 - <a href="https://wordpress.org/support/plugin/mxchat-basic/" target="_blank" rel="noopener noreferrer"><?php echo esc_html__('create a support ticket', 'mxchat'); ?></a>.
479 - </p>
480 - <p>
481 - <?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>.
482 - </p>
483 -
484 - <div class="faq-item">
485 - <h3><?php echo esc_html__('How does the Claude API integration work?', 'mxchat'); ?></h3>
486 - <p>
487 - <?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'); ?>
488 - </p>
489 - <p>
490 - <?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'); ?>
491 - </p>
492 - <p>
493 - <?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>.
494 - </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>
495 509 </div>
510 + </div>
496 511
497 - <div class="faq-item">
498 - <h3><?php echo esc_html__('How does the X.AI API integration work?', 'mxchat'); ?></h3>
499 - <p>
500 - <?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'); ?>
501 - </p>
502 - <p>
503 - <?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>.
504 - </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>
505 520 </div>
521 + </div>
506 522
507 - <div class="faq-item">
508 - <h3><?php echo esc_html__('Do I need an OpenAI API key to use the chatbot?', 'mxchat'); ?></h3>
509 - <p>
510 - <?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'); ?>
511 - </p>
512 - <p>
513 - <?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'); ?>
514 - </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>
515 531 </div>
532 + </div>
516 533
517 - <div class="faq-item">
518 - <h3><?php echo esc_html__('How do I add the chatbot to my site?', 'mxchat'); ?></h3>
519 - <p>
520 - <?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'); ?>
521 - </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>
522 543 </div>
544 + </div>
523 545
524 - <div class="faq-item">
525 - <h3><?php echo esc_html__('How does the chatbot use my content to generate responses?', 'mxchat'); ?></h3>
526 - <p>
527 - <?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'); ?>
528 - </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>
529 554 </div>
530 -
531 - <div class="faq-item">
532 - <h3><?php echo esc_html__('Why does the chatbot sometimes make up links or information?', 'mxchat'); ?></h3>
533 - <p>
534 - <?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'); ?>
535 - </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>
536 565 </div>
566 + </div>
537 567
538 - <div class="faq-item">
539 - <h3><?php echo esc_html__('How do intents work in MxChat?', 'mxchat'); ?></h3>
540 - <p>
541 - <?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>.
542 - </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>
543 576 </div>
577 + </div>
544 578
545 - <div class="faq-item">
546 - <h3><?php echo esc_html__('How does the Complianz integration work?', 'mxchat'); ?></h3>
547 - <p>
548 - <?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'); ?>
549 - </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>
550 588 </div>
589 + </div>
551 590
552 - <div class="faq-item">
553 - <h3><?php echo esc_html__('How does the WooCommerce integration work?', 'mxchat'); ?></h3>
554 - <p>
555 - <?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'); ?>
556 - </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>
557 600 </div>
601 + </div>
602 + </div>
558 603
559 - <div class="faq-item">
560 - <h3><?php echo esc_html__('Why isn\'t my chatbot responding as expected?', 'mxchat'); ?></h3>
561 - <p>
562 - <?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'); ?>
563 - </p>
564 - <p>
565 - <?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'); ?>
566 - </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>
567 619 </div>
568 -
569 - <div class="faq-item">
570 - <h3><?php echo esc_html__('What is Loops, and how do I get an API key?', 'mxchat'); ?></h3>
571 - <p>
572 - <?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'); ?>
573 - </p>
574 - </div>
575 -
576 620 </div>
577 621 </div>
578 622 <?php
579 623 }
@@ -581,20 +625,20 @@
581 625
582 626 public function mxchat_create_transcripts_page() {
583 627 global $wpdb;
584 628 $table_name = $wpdb->prefix . 'mxchat_chat_transcripts';
585 -
629 +
586 630 // Get basic stats
587 631 $total_chats = $wpdb->get_var("SELECT COUNT(DISTINCT session_id) FROM $table_name");
588 632 $total_messages = $wpdb->get_var("SELECT COUNT(*) FROM $table_name");
589 -
633 +
590 634 // Count unique users with detailed breakdown
591 635 $total_users = $wpdb->get_var("
592 - SELECT COUNT(DISTINCT
593 - CASE
636 + SELECT COUNT(DISTINCT
637 + CASE
594 638 WHEN user_email != '' AND user_email IS NOT NULL THEN user_email
595 639 WHEN user_id != 0 THEN CONCAT('user_', user_id)
596 - WHEN user_identifier NOT LIKE 'Tech-Savvy User'
640 + WHEN user_identifier NOT LIKE 'Tech-Savvy User'
597 641 AND user_identifier NOT LIKE 'Detail-Oriented User'
598 642 AND user_identifier NOT LIKE 'Language Learner'
599 643 AND user_identifier NOT LIKE 'Casual Browser'
600 644 AND user_identifier NOT LIKE 'Policy Enforcer'
@@ -602,11 +646,11 @@
602 646 AND user_identifier NOT LIKE 'Loyalty Member'
603 647 AND user_identifier NOT LIKE 'Gift Buyer'
604 648 AND user_identifier NOT LIKE 'Parent or Caregiver'
605 649 THEN user_identifier
606 - ELSE session_id
650 + ELSE session_id
607 651 END
608 - )
652 + )
609 653 FROM $table_name
610 654 WHERE role != 'assistant'
611 655 ");
612 656
@@ -611,16 +655,16 @@
611 655 ");
612 656
613 657 // Get user type breakdown
614 658 $registered_users = $wpdb->get_var("
615 - SELECT COUNT(DISTINCT user_email)
616 - FROM $table_name
659 + SELECT COUNT(DISTINCT user_email)
660 + FROM $table_name
617 661 WHERE user_email != '' AND user_email IS NOT NULL
618 662 ");
619 663
620 664 $guest_users = $wpdb->get_var("
621 - SELECT COUNT(DISTINCT user_identifier)
622 - FROM $table_name
665 + SELECT COUNT(DISTINCT user_identifier)
666 + FROM $table_name
623 667 WHERE (user_email = '' OR user_email IS NULL)
624 668 AND role != 'assistant'
625 669 AND user_identifier NOT LIKE 'Tech-Savvy User'
626 670 AND user_identifier NOT LIKE 'Detail-Oriented User'
@@ -634,10 +678,10 @@
634 678 ");
635 679
636 680 // Get agent test messages count
637 681 $agent_tests = $wpdb->get_var("
638 - SELECT COUNT(DISTINCT session_id)
639 - FROM $table_name
682 + SELECT COUNT(DISTINCT session_id)
683 + FROM $table_name
640 684 WHERE user_identifier IN (
641 685 'Tech-Savvy User',
642 686 'Detail-Oriented User',
643 687 'Language Learner',
@@ -682,15 +726,15 @@
682 726 <div class="stat-content">
683 727 <span class="stat-value"><?php echo esc_html($total_users); ?></span>
684 728 <span class="stat-label"><?php esc_html_e('Unique Users', 'mxchat'); ?></span>
685 729 <span class="stat-sublabel">
686 - <?php
730 + <?php
687 731 echo sprintf(
688 732 esc_html__('%d registered, %d guests, %d agent tests', 'mxchat'),
689 733 $registered_users,
690 734 $guest_users,
691 735 $agent_tests
692 - );
736 + );
693 737 ?>
694 738 </span>
695 739 </div>
696 740 </div>
@@ -738,10 +782,10 @@
738 782 $table_name = $wpdb->prefix . 'mxchat_chat_transcripts';
739 783
740 784 // Get all transcripts ordered by session and timestamp
741 785 $results = $wpdb->get_results(
742 - "SELECT session_id, user_email, user_identifier, role, message, timestamp
743 - FROM {$table_name}
786 + "SELECT session_id, user_email, user_identifier, role, message, timestamp
787 + FROM {$table_name}
744 788 ORDER BY session_id, timestamp ASC"
745 789 );
746 790
747 791 if (empty($results)) {
@@ -1000,10 +1044,39 @@
1000 1044 <div class="mxchat-content">
1001 1045 <!-- Import Settings Card -->
1002 1046 <div class="mxchat-card">
1003 1047 <h2><?php esc_html_e('Knowledge Import Settings', 'mxchat'); ?></h2>
1004 - <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']);
1005 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 +
1006 1079 <!-- Tab Contents -->
1007 1080 <div class="mxchat-tab-contents">
1008 1081 <!-- Default Database Tab -->
1009 1082 <div id="default-db" class="mxchat-tab-content active">
@@ -1161,8 +1234,10 @@
1161 1234 <?php endif; ?>
1162 1235 </div>
1163 1236 </div>
1164 1237 <?php endif; ?>
1238 +
1239 +
1165 1240 </div>
1166 1241
1167 1242
1168 1243 </div>
@@ -1362,43 +1437,57 @@
1362 1437 }
1363 1438
1364 1439
1365 1440 public function mxchat_generate_embedding($text) {
1366 - //error_log('Starting embedding generation for text: ' . substr($text, 0, 100) . '...');
1367 -
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 +
1368 1444 $options = get_option('mxchat_options');
1369 1445 $selected_model = $options['embedding_model'] ?? 'text-embedding-ada-002';
1370 - //error_log('Selected embedding model: ' . $selected_model);
1371 -
1446 + //error_log('[MXCHAT-EMBED] Selected embedding model: ' . $selected_model);
1447 +
1372 1448 // Determine provider and endpoint
1373 1449 if (strpos($selected_model, 'voyage') === 0) {
1374 1450 $api_key = $options['voyage_api_key'] ?? '';
1375 1451 $endpoint = 'https://api.voyageai.com/v1/embeddings';
1452 + //error_log('[MXCHAT-EMBED] Using Voyage AI API');
1376 1453 } else {
1377 1454 $api_key = $options['api_key'] ?? '';
1378 1455 $endpoint = 'https://api.openai.com/v1/embeddings';
1456 + //error_log('[MXCHAT-EMBED] Using OpenAI API');
1379 1457 }
1380 - //error_log('Using endpoint: ' . $endpoint);
1381 -
1458 +
1459 + //error_log('[MXCHAT-EMBED] Using endpoint: ' . $endpoint);
1460 +
1382 1461 if (empty($api_key)) {
1383 - //error_log('Error: API key not configured');
1384 - return null;
1462 + //error_log('[MXCHAT-EMBED] Error: API key not configured');
1463 + return 'Missing API key. Please configure your API key in the settings.';
1385 1464 }
1386 -
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 +
1387 1475 // Prepare request body
1388 1476 $request_body = array(
1389 1477 'model' => $selected_model,
1390 1478 'input' => $text
1391 1479 );
1392 -
1480 +
1393 1481 // Add output_dimension for voyage-3-large model
1394 1482 if ($selected_model === 'voyage-3-large') {
1395 1483 $request_body['output_dimension'] = 2048;
1396 1484 }
1397 -
1398 - //error_log('Request body prepared: ' . wp_json_encode($request_body));
1399 -
1485 +
1486 + //error_log('[MXCHAT-EMBED] Request prepared with model: ' . $selected_model);
1487 +
1400 1488 // Make API request
1489 + //error_log('[MXCHAT-EMBED] Sending API request to: ' . $endpoint);
1401 1490 $response = wp_remote_post($endpoint, array(
1402 1491 'body' => wp_json_encode($request_body),
1403 1492 'headers' => array(
1404 1493 'Authorization' => 'Bearer ' . $api_key,
@@ -1403,46 +1492,76 @@
1403 1492 'headers' => array(
1404 1493 'Authorization' => 'Bearer ' . $api_key,
1405 1494 'Content-Type' => 'application/json'
1406 1495 ),
1407 - 'timeout' => 30
1496 + 'timeout' => 60 // Increased timeout for large inputs
1408 1497 ));
1409 -
1498 +
1410 1499 // Handle wp_remote_post errors
1411 1500 if (is_wp_error($response)) {
1412 - //error_log('WP Remote Post Error: ' . $response->get_error_message());
1413 - return null;
1501 + $error_message = $response->get_error_message();
1502 + //error_log('[MXCHAT-EMBED] WP Remote Post Error: ' . $error_message);
1503 + return 'Connection error: ' . $error_message;
1414 1504 }
1415 -
1505 +
1416 1506 // Get and check HTTP response code
1417 1507 $http_code = wp_remote_retrieve_response_code($response);
1418 - //error_log('API Response Code: ' . $http_code);
1419 -
1508 + //error_log('[MXCHAT-EMBED] API Response Code: ' . $http_code);
1509 +
1420 1510 if ($http_code !== 200) {
1421 - //error_log('API Error Response Body: ' . wp_remote_retrieve_body($response));
1422 - return null;
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";
1522 + }
1523 +
1524 + return "API Error (HTTP $http_code): Unable to generate embedding";
1423 1525 }
1424 -
1526 +
1425 1527 // Parse response body
1426 - $response_data = json_decode(wp_remote_retrieve_body($response), true);
1427 -
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 +
1428 1533 if (json_last_error() !== JSON_ERROR_NONE) {
1429 - //error_log('JSON Parse Error: ' . json_last_error_msg());
1430 - return null;
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";
1431 1538 }
1432 -
1539 +
1433 1540 // Both APIs use the same structure, so we can extract the embedding the same way
1434 1541 if (isset($response_data['data'][0]['embedding'])) {
1435 - //error_log('Successfully extracted embedding');
1436 - //error_log('Embedding dimension: ' . count($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 +
1437 1550 return $response_data['data'][0]['embedding'];
1438 1551 } else {
1439 - //error_log('Error: No embedding found in response. Response structure: ' . wp_json_encode($response_data));
1440 - return null;
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";
1441 1561 }
1442 1562 }
1443 1563
1444 -
1445 1564 public function mxchat_delete_chat_history() {
1446 1565 if (!current_user_can('manage_options')) {
1447 1566 echo wp_json_encode(['error' => esc_html__('You do not have sufficient permissions.', 'mxchat')]);
1448 1567 wp_die();
@@ -1667,8 +1786,10 @@
1667 1786 'success' => true,
1668 1787 'message' => 'Successfully stored in Pinecone'
1669 1788 );
1670 1789 }
1790 +
1791 +
1671 1792 // Helper method for WordPress DB storage
1672 1793 private function store_in_wordpress_db($content, $url, $embedding_vector) {
1673 1794 global $wpdb;
1674 1795 $table_name = $wpdb->prefix . 'mxchat_system_prompt_content';
@@ -2044,19 +2165,26 @@
2044 2165 'status' => sanitize_text_field($status['status']),
2045 2166 'last_update' => human_time_diff(absint($status['last_update']), time()) . ' ' . esc_html__('ago', 'mxchat')
2046 2167 );
2047 2168 }
2169 +
2048 2170 public function mxchat_handle_sitemap_submission() {
2171 + // Start logging the submission process
2172 + //error_log('[MXCHAT-URL] ===== Starting URL submission process =====');
2173 +
2049 2174 // Check if the form was submitted and verify permissions
2050 2175 if (!isset($_POST['submit_sitemap']) || !current_user_can('manage_options')) {
2176 + //error_log('[MXCHAT-URL] Error: Unauthorized access or form not submitted properly');
2051 2177 wp_die(esc_html__('Unauthorized access', 'mxchat'));
2052 2178 }
2053 2179
2054 2180 // Verify nonce
2181 + //error_log('[MXCHAT-URL] Verifying nonce');
2055 2182 check_admin_referer('mxchat_submit_sitemap_action', 'mxchat_submit_sitemap_nonce');
2056 2183
2057 2184 // Validate URL
2058 2185 if (!isset($_POST['sitemap_url']) || empty($_POST['sitemap_url'])) {
2186 + //error_log('[MXCHAT-URL] Error: Empty or missing URL');
2059 2187 set_transient('mxchat_admin_notice_error',
2060 2188 esc_html__('Please provide a valid URL.', 'mxchat'),
2061 2189 30
2062 2190 );
@@ -2064,12 +2192,16 @@
2064 2192 exit;
2065 2193 }
2066 2194
2067 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');
2068 2199 $response = wp_remote_get($submitted_url, array('timeout' => 30));
2069 2200
2070 2201 if (is_wp_error($response) || wp_remote_retrieve_response_code($response) !== 200) {
2071 - $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);
2072 2204 set_transient('mxchat_admin_notice_error',
2073 2205 sprintf(
2074 2206 esc_html__('Failed to fetch the URL: %s', 'mxchat'),
2075 2207 esc_html($error_message)
@@ -2080,11 +2212,13 @@
2080 2212 exit;
2081 2213 }
2082 2214
2083 2215 $content_type = wp_remote_retrieve_header($response, 'content-type');
2216 + //error_log('[MXCHAT-URL] Content type: ' . $content_type);
2084 2217 $body_content = wp_remote_retrieve_body($response);
2085 2218
2086 2219 if (empty($body_content)) {
2220 + //error_log('[MXCHAT-URL] Error: Empty response body');
2087 2221 set_transient('mxchat_admin_notice_error',
2088 2222 esc_html__('Empty response received from URL.', 'mxchat'),
2089 2223 30
2090 2224 );
@@ -2090,12 +2224,15 @@
2090 2224 );
2091 2225 wp_safe_redirect(esc_url(admin_url('admin.php?page=mxchat-prompts')));
2092 2226 exit;
2093 2227 }
2228 + //error_log('[MXCHAT-URL] Retrieved body content length: ' . strlen($body_content) . ' bytes');
2094 2229
2095 2230 // Handle PDF URL
2096 2231 if ($this->is_pdf_url($submitted_url, $response)) {
2232 + //error_log('[MXCHAT-URL] Detected PDF URL, handling PDF for knowledge base');
2097 2233 $result = $this->handle_pdf_for_knowledge_base($submitted_url, $response);
2234 + //error_log('[MXCHAT-URL] PDF handling result: ' . $result);
2098 2235
2099 2236 if ($result === 'scheduled') {
2100 2237 set_transient(
2101 2238 'mxchat_last_pdf_url',
@@ -2107,9 +2244,9 @@
2107 2244 30
2108 2245 );
2109 2246 } else {
2110 2247 set_transient('mxchat_admin_notice_error',
2111 - esc_html__('Failed to start PDF processing. Please try again.', 'mxchat'),
2248 + esc_html__('Failed to start PDF processing: ', 'mxchat') . esc_html($result),
2112 2249 30
2113 2250 );
2114 2251 }
2115 2252
@@ -2118,8 +2255,9 @@
2118 2255 }
2119 2256
2120 2257 // Handle Sitemap XML
2121 2258 if (strpos($content_type, 'xml') !== false || strpos($body_content, '<urlset') !== false) {
2259 + //error_log('[MXCHAT-URL] Detected XML content, processing as sitemap');
2122 2260 libxml_use_internal_errors(true);
2123 2261 $xml = simplexml_load_string($body_content);
2124 2262 $xml_errors = libxml_get_errors();
2125 2263 libxml_clear_errors();
@@ -2124,8 +2262,15 @@
2124 2262 $xml_errors = libxml_get_errors();
2125 2263 libxml_clear_errors();
2126 2264
2127 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 +
2128 2273 set_transient('mxchat_admin_notice_error',
2129 2274 esc_html__('Invalid sitemap XML. Please provide a valid sitemap.', 'mxchat'),
2130 2275 30
2131 2276 );
@@ -2132,9 +2277,11 @@
2132 2277 wp_safe_redirect(esc_url(admin_url('admin.php?page=mxchat-prompts')));
2133 2278 exit;
2134 2279 }
2135 2280
2281 + //error_log('[MXCHAT-URL] Valid XML found, handling sitemap for knowledge base');
2136 2282 $result = $this->handle_sitemap_for_knowledge_base($xml, $submitted_url);
2283 + //error_log('[MXCHAT-URL] Sitemap handling result: ' . $result);
2137 2284
2138 2285 if ($result === 'scheduled') {
2139 2286 set_transient(
2140 2287 'mxchat_last_sitemap_url',
@@ -2145,10 +2292,12 @@
2145 2292 esc_html__('Sitemap processing has started in the background. You can check the progress in the Knowledge Base section.', 'mxchat'),
2146 2293 30
2147 2294 );
2148 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
2149 2298 set_transient('mxchat_admin_notice_error',
2150 - 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'),
2151 2300 30
2152 2301 );
2153 2302 }
2154 2303
@@ -2156,12 +2305,17 @@
2156 2305 exit;
2157 2306 }
2158 2307
2159 2308 // Handle Regular URL
2309 + //error_log('[MXCHAT-URL] Processing as regular webpage');
2160 2310 $page_content = $this->mxchat_extract_main_content($body_content);
2311 + //error_log('[MXCHAT-URL] Extracted content length: ' . strlen($page_content) . ' bytes');
2312 +
2161 2313 $sanitized_content = $this->mxchat_sanitize_content_for_api($page_content);
2314 + //error_log('[MXCHAT-URL] Sanitized content length: ' . strlen($sanitized_content) . ' bytes');
2162 2315
2163 2316 if (empty($sanitized_content)) {
2317 + //error_log('[MXCHAT-URL] Error: No valid content after sanitization');
2164 2318 set_transient('mxchat_admin_notice_error',
2165 2319 esc_html__('No valid content found on the provided URL.', 'mxchat'),
2166 2320 30
2167 2321 );
@@ -2168,29 +2322,59 @@
2168 2322 wp_safe_redirect(esc_url(admin_url('admin.php?page=mxchat-prompts')));
2169 2323 exit;
2170 2324 }
2171 2325
2326 + //error_log('[MXCHAT-URL] Generating embedding for content');
2172 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 +
2173 2340 if (is_array($embedding_vector)) {
2174 - 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(
2175 2344 $sanitized_content,
2176 2345 $submitted_url,
2177 2346 $this->options['api_key']
2178 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');
2179 2360 set_transient('mxchat_admin_notice_success',
2180 2361 esc_html__('URL content successfully submitted!', 'mxchat'),
2181 2362 30
2182 2363 );
2183 2364 } else {
2365 + //error_log('[MXCHAT-URL] Error: Failed to generate embedding. Unexpected result type: ' . gettype($embedding_vector));
2184 2366 set_transient('mxchat_admin_notice_error',
2185 - 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'),
2186 2368 30
2187 2369 );
2188 2370 }
2189 2371
2372 + //error_log('[MXCHAT-URL] ===== Completed URL submission process =====');
2190 2373 wp_safe_redirect(esc_url(admin_url('admin.php?page=mxchat-prompts')));
2191 2374 exit;
2192 2375 }
2376 +
2193 2377 private function handle_sitemap_for_knowledge_base($xml, $sitemap_url) {
2194 2378 if (!current_user_can('manage_options')) {
2195 2379 //error_log(esc_html__('Unauthorized sitemap processing attempt', 'mxchat'));
2196 2380 return false;
@@ -2202,8 +2386,40 @@
2202 2386 if (!$xml || !is_object($xml)) {
2203 2387 throw new Exception(__('Invalid XML object provided', 'mxchat'));
2204 2388 }
2205 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 +
2206 2422 $urls = [];
2207 2423 foreach ($xml->url as $url_element) {
2208 2424 $url = esc_url_raw((string)$url_element->loc);
2209 2425 if ($url) {
@@ -2240,12 +2456,36 @@
2240 2456
2241 2457 return __('scheduled', 'mxchat');
2242 2458
2243 2459 } catch (\Exception $e) {
2244 - //error_log(sprintf(esc_html__('Error preparing sitemap for processing: %s', 'mxchat'), esc_html($e->getMessage())));
2245 - 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;
2246 2485 }
2247 2486 }
2487 +
2248 2488 public static function process_sitemap_urls_cron($urls, $sitemap_url, $total_urls, $batch_size, $batch_pause) {
2249 2489 // Validate inputs
2250 2490 $sitemap_url = esc_url_raw($sitemap_url);
2251 2491 $total_urls = absint($total_urls);
@@ -2271,11 +2511,38 @@
2271 2511 // Track failures in batch
2272 2512 $batch_stats = [
2273 2513 'processed' => 0,
2274 2514 'failed' => 0,
2275 - 'last_error' => ''
2515 + 'last_error' => '',
2516 + 'embedding_errors' => 0 // Track specifically embedding errors
2276 2517 ];
2277 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 +
2278 2545 for ($i = $start_url; $i < $end_url; $i++) {
2279 2546 $page_url = esc_url_raw($urls[$i]);
2280 2547 $page_response = wp_remote_get($page_url);
2281 2548
@@ -2280,8 +2547,10 @@
2280 2547 $page_response = wp_remote_get($page_url);
2281 2548
2282 2549 if (is_wp_error($page_response) || wp_remote_retrieve_response_code($page_response) !== 200) {
2283 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;
2284 2553 continue;
2285 2554 }
2286 2555
2287 2556 $page_html = wp_remote_retrieve_body($page_response);
@@ -2290,8 +2559,22 @@
2290 2559
2291 2560 if (!empty($sanitized_content)) {
2292 2561 $embedding_vector = $instance->mxchat_generate_embedding($sanitized_content);
2293 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)
2294 2577 if (is_array($embedding_vector)) {
2295 2578 $options = get_option('mxchat_options');
2296 2579 $submission_result = MxChat_Utils::submit_content_to_db($sanitized_content, $page_url, $options['api_key']);
2297 2580
@@ -2303,9 +2586,15 @@
2303 2586
2304 2587 $batch_stats['processed']++;
2305 2588 } else {
2306 2589 $batch_stats['failed']++;
2307 - $batch_stats['last_error'] = 'Failed to generate embedding. Please check embedding 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 + }
2308 2597 }
2309 2598 }
2310 2599
2311 2600 $status['processed_urls'] = absint($i + 1);
@@ -2346,8 +2635,9 @@
2346 2635 set_transient($status_key, array_map('sanitize_text_field', $status), DAY_IN_SECONDS);
2347 2636 }
2348 2637 }
2349 2638
2639 +
2350 2640 public function get_sitemap_processing_status($sitemap_url) {
2351 2641 $sitemap_url = esc_url_raw($sitemap_url);
2352 2642 $status = get_transient(sanitize_key('mxchat_sitemap_status_' . md5($sitemap_url)));
2353 2643
@@ -2368,8 +2658,42 @@
2368 2658 'last_error' => isset($status['last_error']) ? sanitize_text_field($status['last_error']) : ''
2369 2659 );
2370 2660 }
2371 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 +
2372 2696 public function mxchat_stop_processing() {
2373 2697 // Verify permissions
2374 2698 if (!current_user_can('manage_options')) {
2375 2699 wp_die(esc_html__('Unauthorized access', 'mxchat'));
@@ -2405,27 +2729,53 @@
2405 2729 );
2406 2730 wp_safe_redirect(admin_url('admin.php?page=mxchat-prompts'));
2407 2731 exit;
2408 2732 }
2733 +
2734 +
2409 2735 private function mxchat_sanitize_content_for_api($content) {
2736 + //error_log('[MXCHAT-SANITIZE] Original content preview: ' . substr($content, 0, 500) . '...');
2737 +
2410 2738 // Remove script, style tags, and HTML comments
2411 2739 $content = preg_replace('/<script\b[^>]*>(.*?)<\/script>/is', '', $content);
2412 2740 $content = preg_replace('/<style\b[^>]*>(.*?)<\/style>/is', '', $content);
2413 2741 $content = preg_replace('/<!--(.|\s)*?-->/', '', $content);
2414 -
2742 +
2415 2743 // Remove all HTML tags and decode HTML entities
2416 2744 $content = wp_strip_all_tags($content);
2417 2745 $content = html_entity_decode($content, ENT_QUOTES | ENT_HTML5);
2418 -
2746 +
2419 2747 // Trim and normalize whitespace
2420 2748 $content = trim(preg_replace('/\s+/', ' ', $content));
2421 -
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) . '...');
2422 2775 return $content;
2423 2776 }
2424 2777
2425 -
2426 -
2427 -
2428 2778 public function mxchat_handle_product_change($post_id, $post, $update) {
2429 2779 if ($post->post_type !== 'product') {
2430 2780 return;
2431 2781 }
@@ -2874,15 +3224,15 @@
2874 3224 : $callback_function;
2875 3225 $threshold_value = isset($intent->similarity_threshold)
2876 3226 ? round($intent->similarity_threshold * 100)
2877 3227 : 85;
2878 -
3228 +
2879 3229 // Check if this is a form intent (its intent_label starts with "Form ")
2880 3230 $is_form_intent = strpos($intent->intent_label, 'Form ') === 0;
2881 3231 ?>
2882 3232 <tr<?php echo $is_form_intent ? ' class="mxchat-form-intent"' : ''; ?>>
2883 3233 <td>
2884 - <?php
3234 + <?php
2885 3235 if ($is_form_intent) {
2886 3236 // Attempt to extract the form ID from the intent_label.
2887 3237 preg_match('/Form (\d+)/', $intent->intent_label, $matches);
2888 3238 $form_id = isset($matches[1]) ? intval($matches[1]) : 0;
@@ -2963,9 +3313,9 @@
2963 3313 <?php
2964 3314 preg_match('/Form (\d+)/', $intent->intent_label, $matches);
2965 3315 $form_id = isset($matches[1]) ? $matches[1] : '';
2966 3316 ?>
2967 - <a href="<?php echo esc_url(admin_url('admin.php?page=mxchat-forms&action=edit&form_id=' . $form_id)); ?>"
3317 + <a href="<?php echo esc_url(admin_url('admin.php?page=mxchat-forms&action=edit&form_id=' . $form_id)); ?>"
2968 3318 class="mxchat-button-secondary">
2969 3319 <?php esc_html_e('Manage in Forms', 'mxchat'); ?>
2970 3320 </a>
2971 3321 <?php endif; ?>
@@ -3238,9 +3588,9 @@
3238 3588
3239 3589 private function mxchat_get_available_callbacks($grouped = false) {
3240 3590 $callbacks = [
3241 3591 'mxchat_handle_email_capture' => [
3242 - 'label' => __('Email Capture', 'mxchat'),
3592 + 'label' => __('Loops Email Capture', 'mxchat'),
3243 3593 'pro_only' => false,
3244 3594 'group' => __('Customer Engagement', 'mxchat'),
3245 3595 ],
3246 3596 'mxchat_generate_image' => [
@@ -3380,49 +3730,68 @@
3380 3730 );
3381 3731
3382 3732
3383 3733 // Existing fields...
3384 - add_settings_field(
3385 - 'api_key',
3386 - esc_html__('OpenAI API Key', 'mxchat'),
3387 - array($this, 'api_key_callback'),
3388 - 'mxchat-chatbot',
3389 - 'mxchat_chatbot_section'
3390 - );
3391 -
3392 - add_settings_field(
3393 - 'xai_api_key',
3394 - esc_html__('X.AI API Key', 'mxchat'),
3395 - array($this, 'xai_api_key_callback'),
3396 - 'mxchat-chatbot',
3397 - 'mxchat_chatbot_section'
3398 - );
3399 -
3400 - add_settings_field(
3401 - 'claude_api_key',
3402 - esc_html__('Claude API Key', 'mxchat'),
3403 - array($this, 'claude_api_key_callback'),
3404 - 'mxchat-chatbot',
3405 - 'mxchat_chatbot_section'
3406 - );
3407 -
3408 - add_settings_field(
3409 - 'deepseek_api_key',
3410 - esc_html__('DeepSeek API Key', 'mxchat'),
3411 - array($this, 'deepseek_api_key_callback'),
3412 - 'mxchat-chatbot',
3413 - 'mxchat_chatbot_section'
3414 - );
3415 -
3416 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(
3417 3783 'voyage_api_key',
3418 3784 esc_html__('Voyage AI API Key', 'mxchat'),
3419 3785 array($this, 'voyage_api_key_callback'),
3420 3786 'mxchat-chatbot',
3421 - 'mxchat_chatbot_section'
3787 + 'mxchat_chatbot_section',
3788 + array(
3789 + 'class' => 'mxchat-setting-row',
3790 + 'data-provider' => 'voyage'
3791 + )
3422 3792 );
3423 3793
3424 -
3425 3794 add_settings_field(
3426 3795 'model',
3427 3796 esc_html__('Chat Model', 'mxchat'),
3428 3797 array($this, 'mxchat_model_callback'),
@@ -3428,9 +3797,9 @@
3428 3797 array($this, 'mxchat_model_callback'),
3429 3798 'mxchat-chatbot',
3430 3799 'mxchat_chatbot_section'
3431 3800 );
3432 -
3801 +
3433 3802 // Add the settings field
3434 3803 add_settings_field(
3435 3804 'embedding_model',
3436 3805 esc_html__('Embedding Model', 'mxchat'),
@@ -3437,9 +3806,9 @@
3437 3806 array($this, 'embedding_model_callback'),
3438 3807 'mxchat-chatbot',
3439 3808 'mxchat_chatbot_section'
3440 3809 );
3441 -
3810 +
3442 3811 add_settings_field(
3443 3812 'system_prompt_instructions',
3444 3813 esc_html__('AI Instructions (Behavior)', 'mxchat'),
3445 3814 array($this, 'system_prompt_instructions_callback'),
@@ -3704,8 +4073,26 @@
3704 4073 array($this, 'mxchat_chat_toolbar_toggle_callback'),
3705 4074 'mxchat-embed',
3706 4075 'mxchat_pdf_intent_section'
3707 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 + );
3708 4095
3709 4096 add_settings_field(
3710 4097 'pdf_intent_trigger_text',
3711 4098 __('Intent Trigger Text', 'mxchat'),
@@ -3802,9 +4189,9 @@
3802 4189
3803 4190 // General Settings Section
3804 4191 add_settings_section(
3805 4192 'mxchat_general_section',
3806 - esc_html__('Frequently Asked Questions (FAQ)', 'mxchat'),
4193 + esc_html__('YouTube Tutorials', 'mxchat'),
3807 4194 null,
3808 4195 'mxchat-general'
3809 4196 );
3810 4197 }
@@ -4057,80 +4444,68 @@
4057 4444 'mxchat_setting_section_id',
4058 4445 $id === 'model' ? ['label_for' => 'model'] : []
4059 4446 );
4060 4447 }
4061 -
4448 +
4449 +// OpenAI API Key
4062 4450 public function api_key_callback() {
4063 - // Retrieve from your stored 'api_key' in the mxchat_options array
4064 4451 $apiKey = isset($this->options['api_key']) ? esc_attr($this->options['api_key']) : '';
4065 -
4066 - // Notice we changed the name to "api_key" (no array notation).
4452 +
4453 + echo '<div class="api-key-wrapper" data-provider="openai">';
4067 4454 echo '<input type="password" id="api_key" name="api_key" value="' . $apiKey . '" class="regular-text" />';
4068 4455 echo '<button type="button" id="toggleApiKeyVisibility">' . esc_html__('Show', 'mxchat') . '</button>';
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>';
4069 4458 }
4459 +
4460 +// X.AI API Key
4070 4461 public function xai_api_key_callback() {
4071 - // Check if the feature is activated (paid feature)
4072 - $disabled = $this->is_activated ? '' : 'disabled'; // Disable input if not activated
4073 - $class = $this->is_activated ? 'pro-feature-wrapper active' : 'pro-feature-wrapper inactive'; // CSS class to style the wrapper based on activation status
4074 -
4075 - // Retrieve the X.AI API key value
4076 4462 $xaiApiKey = isset($this->options['xai_api_key']) ? esc_attr($this->options['xai_api_key']) : '';
4077 -
4078 - // Render the input field for the X.AI API key
4079 - echo '<div class="' . esc_attr($class) . '">';
4080 - printf(
4081 - '<input type="password" id="xai_api_key" name="xai_api_key" value="%s" class="regular-text" %s />',
4082 - $xaiApiKey,
4083 - $disabled
4084 - );
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" />';
4085 4466 echo '<button type="button" id="toggleXaiApiKeyVisibility">' . esc_html__('Show', 'mxchat') . '</button>';
4086 -
4087 - // If the feature is not activated, show the overlay with a "Pro Only" message
4088 - if (!$this->is_activated) {
4089 - echo '<div class="pro-feature-overlay">';
4090 - 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>';
4091 - echo '</div>';
4092 - }
4093 -
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>';
4094 4468 echo '</div>';
4095 4469 }
4470 +
4471 +// Claude API Key
4096 4472 public function claude_api_key_callback() {
4097 - // Check if the feature is activated (paid feature)
4098 - $disabled = $this->is_activated ? '' : 'disabled';
4099 - $class = $this->is_activated ? 'pro-feature-wrapper active' : 'pro-feature-wrapper inactive';
4100 -
4101 - // Retrieve the Claude API key value directly like the others
4102 4473 $claudeApiKey = isset($this->options['claude_api_key']) ? esc_attr($this->options['claude_api_key']) : '';
4103 -
4104 - // Use direct name field like the other working API keys
4105 - echo '<div class="' . esc_attr($class) . '">';
4106 - printf(
4107 - '<input type="password" id="claude_api_key" name="claude_api_key" value="%s" class="regular-text" %s />',
4108 - $claudeApiKey,
4109 - $disabled
4110 - );
4474 +
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" />';
4111 4477 echo '<button type="button" id="toggleClaudeApiKeyVisibility">' . esc_html__('Show', 'mxchat') . '</button>';
4112 -
4113 - if (!$this->is_activated) {
4114 - echo '<div class="pro-feature-overlay">';
4115 - echo '<a href="https://mxchat.ai/" target="_blank"><img src="' . plugin_dir_url(__FILE__) . '../images/pro-only-dark.png" alt="' . esc_attr__('Pro Only', 'mxchat') . '" /></a>';
4116 - echo '</div>';
4117 - }
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>';
4118 4479 echo '</div>';
4119 4480 }
4481 +
4482 +// DeepSeek API Key
4120 4483 public function deepseek_api_key_callback() {
4121 - // Retrieve from your stored 'deepseek_api_key' in the mxchat_options array
4122 4484 $apiKey = isset($this->options['deepseek_api_key']) ? esc_attr($this->options['deepseek_api_key']) : '';
4123 -
4124 - // Notice we changed the name to "deepseek_api_key" (no array notation).
4485 +
4486 + echo '<div class="api-key-wrapper" data-provider="deepseek">';
4125 4487 echo '<input type="password" id="deepseek_api_key" name="deepseek_api_key" value="' . $apiKey . '" class="regular-text" />';
4126 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>';
4127 4491 }
4128 4492
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>';
4501 + echo '</div>';
4502 +}
4129 4503
4130 4504
4131 4505
4132 4506
4507 +
4133 4508 public function mxchat_loops_api_key_callback() {
4134 4509 // Support both old and new format
4135 4510 $loops_api_key = isset($this->options['loops_api_key']) ? esc_attr($this->options['loops_api_key']) : '';
4136 4511
@@ -4140,9 +4515,9 @@
4140 4515 $loops_api_key
4141 4516 );
4142 4517 echo '<button type="button" id="toggleLoopsApiKeyVisibility">' . esc_html__('Show', 'mxchat') . '</button>';
4143 4518 echo '</div>';
4144 - 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>';
4145 4520 }
4146 4521
4147 4522 public function mxchat_loops_mailing_list_callback() {
4148 4523 // Add error handling and type checking
@@ -4251,9 +4626,10 @@
4251 4626 esc_html__('DeepSeek Models', 'mxchat') => array(
4252 4627 'deepseek-chat' => esc_html__('DeepSeek-V3', 'mxchat'),
4253 4628 ),
4254 4629 esc_html__('Claude Models', 'mxchat') => array(
4255 - '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'),
4256 4632 'claude-3-opus-20240229' => esc_html__('Claude 3 Opus (Highly Complex Tasks)', 'mxchat'),
4257 4633 'claude-3-sonnet-20240229' => esc_html__('Claude 3 Sonnet (Balanced)', 'mxchat'),
4258 4634 'claude-3-haiku-20240307' => esc_html__('Claude 3 Haiku (Fastest)', 'mxchat')
4259 4635 ),
@@ -4264,50 +4640,40 @@
4264 4640 'gpt-4' => esc_html__('GPT-4 (High Intelligence)', 'mxchat'),
4265 4641 'gpt-3.5-turbo' => esc_html__('GPT-3.5 Turbo (Affordable and Fast)', 'mxchat')
4266 4642 )
4267 4643 );
4268 -
4644 +
4269 4645 // Retrieve the currently selected model from saved options
4270 4646 $selected_model = isset($this->options['model']) ? esc_attr($this->options['model']) : 'gpt-4o';
4271 -
4647 +
4272 4648 // Begin the select dropdown
4273 - echo '<select id="model" name="model">'; // No array notation in name attribute
4274 -
4649 + echo '<select id="model" name="model">';
4650 +
4275 4651 // Iterate over groups of models
4276 4652 foreach ($models as $group_label => $group_models) {
4277 4653 echo '<optgroup label="' . esc_attr($group_label) . '">';
4278 -
4654 +
4279 4655 foreach ($group_models as $model_value => $model_label) {
4280 - // Disable Pro-only models for non-activated users
4281 - $disabled = (!$this->is_activated && ($group_label === esc_html__('X.AI Models', 'mxchat') || $group_label === esc_html__('Claude Models', 'mxchat'))) ? 'disabled' : '';
4282 - $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') : '';
4283 -
4284 - // Output the option element
4285 - 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>';
4286 4658 }
4287 -
4659 +
4288 4660 echo '</optgroup>';
4289 4661 }
4290 -
4662 +
4291 4663 // Close the select dropdown
4292 4664 echo '</select>';
4293 -
4294 - // Add a description below the dropdown
4295 - echo '<p class="description">' . esc_html__('Select the AI model your chatbot will use for chatting. Pro-only models are marked accordingly.', 'mxchat') . '</p>';
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>';
4296 4668 }
4297 4669
4298 -public function voyage_api_key_callback() {
4299 - $apiKey = isset($this->options['voyage_api_key']) ? esc_attr($this->options['voyage_api_key']) : '';
4300 - echo '<input type="password" id="voyage_api_key" name="voyage_api_key" value="' . $apiKey . '" class="regular-text" />';
4301 - echo '<button type="button" id="toggleVoyageAPIKeyVisibility">' . esc_html__('Show', 'mxchat') . '</button>';
4302 -}
4303 -
4304 4670 // Callback function for embedding model selection
4305 4671 public function embedding_model_callback() {
4306 4672 $models = array(
4307 4673 esc_html__('OpenAI Embeddings', 'mxchat') => array(
4308 4674 'text-embedding-3-small' => esc_html__('TE3 Small (1536, Efficient)', 'mxchat'),
4309 - 'text-embedding-ada-002' => esc_html__('Ada 2 (1536, Original)', 'mxchat'),
4675 + 'text-embedding-ada-002' => esc_html__('Ada 2 (1536, Recommended)', 'mxchat'),
4310 4676 'text-embedding-3-large' => esc_html__('TE3 Large (3072, Powerful)', 'mxchat'),
4311 4677 ),
4312 4678 esc_html__('Voyage AI Embeddings', 'mxchat') => array(
4313 4679 'voyage-3-large' => esc_html__('Voyage-3 Large (2048, Most Capable)', 'mxchat'),
@@ -4325,9 +4691,9 @@
4325 4691 echo '</optgroup>';
4326 4692 }
4327 4693 echo '</select>';
4328 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>';
4329 -
4695 +
4330 4696 }
4331 4697
4332 4698
4333 4699 public function mxchat_top_bar_title_callback() {
@@ -5220,9 +5586,78 @@
5220 5586 echo '</div>';
5221 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>';
5222 5588 }
5223 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 +}
5224 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 +
5225 5660 public function mxchat_pdf_intent_trigger_text_callback() {
5226 5661 $disabled = $this->is_activated ? '' : 'disabled';
5227 5662 $class = $this->is_activated ? 'pro-feature-wrapper active' : 'pro-feature-wrapper inactive';
5228 5663 $default_text = __("Please provide the URL to the PDF you'd like to discuss.", 'mxchat');
@@ -5443,24 +5878,21 @@
5443 5878 }
5444 5879 echo '</div>';
5445 5880 }
5446 5881
5447 -
5448 5882 public function mxchat_similarity_threshold_callback() {
5449 5883 // Load from mxchat_options array
5450 5884 $options = get_option('mxchat_options', []);
5451 -
5452 - // Get value with backwards compatibility
5453 - $threshold = isset($options['similarity_threshold'])
5454 - ? $options['similarity_threshold']
5455 - : get_option('mxchat_similarity_threshold', 80);
5456 -
5885 +
5886 + // Get value from options array with default of 80
5887 + $threshold = isset($options['similarity_threshold']) ? $options['similarity_threshold'] : 35;
5888 +
5457 5889 echo '<div class="slider-container">';
5458 5890 echo sprintf(
5459 5891 '<input type="range"
5460 5892 id="similarity_threshold"
5461 5893 name="similarity_threshold"
5462 - min="70"
5894 + min="20"
5463 5895 max="85"
5464 5896 step="1"
5465 5897 value="%s"
5466 5898 class="range-slider" />',
@@ -5470,16 +5902,14 @@
5470 5902 '<span id="threshold_value" class="range-value">%s</span>',
5471 5903 esc_html($threshold)
5472 5904 );
5473 5905 echo '</div>';
5474 -
5475 5906 echo '<p class="description">';
5476 - 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');
5477 5908 echo '</p>';
5478 5909 }
5479 5910
5480 5911
5481 -
5482 5912 public function mxchat_live_agent_secret_key_callback() {
5483 5913 $disabled = $this->is_activated ? '' : 'disabled';
5484 5914 $class = $this->is_activated ? 'pro-feature-wrapper active' : 'pro-feature-wrapper inactive';
5485 5915
@@ -5524,9 +5954,9 @@
5524 5954 public function mxchat_enqueue_admin_assets() {
5525 5955 wp_enqueue_style('wp-color-picker');
5526 5956
5527 5957 // Get the plugin version or file modification time for cache busting
5528 - $plugin_version = '2.0.6'; // Replace this with your plugin's version
5958 + $plugin_version = '2.1.1'; // Replace this with your plugin's version
5529 5959
5530 5960 // File paths
5531 5961 $color_picker_js_path = plugin_dir_path(__FILE__) . '../js/my-color-picker.js';
5532 5962 $embedding_check_js_path = plugin_dir_path(__FILE__) . '../js/embedding-check.js';
@@ -5544,10 +5974,34 @@
5544 5974 $knowledge_css_version = file_exists($knowledge_css_path) ? filemtime($knowledge_css_path) : $plugin_version;
5545 5975 $intent_css_version = file_exists($intent_css_path) ? filemtime($intent_css_path) : $plugin_version;
5546 5976 $transcripts_css_version = file_exists($transcripts_css_path) ? filemtime($transcripts_css_path) : $plugin_version;
5547 5977 $transcripts_js_version = file_exists($transcripts_js_path) ? filemtime($transcripts_js_path) : $plugin_version;
5548 -
5549 -
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 +
5550 6004 // Enqueue scripts and styles with corrected paths
5551 6005 wp_enqueue_script(
5552 6006 'mxchat-color-picker',
5553 6007 plugin_dir_url(__FILE__) . '../js/my-color-picker.js',
@@ -5586,9 +6040,9 @@
5586 6040 plugin_dir_url(__FILE__) . '../css/admin-style.css',
5587 6041 array(),
5588 6042 $admin_css_version
5589 6043 );
5590 -
6044 +
5591 6045 if (isset($_GET['page']) && $_GET['page'] === 'mxchat-transcripts') {
5592 6046 wp_enqueue_style(
5593 6047 'mxchat-chat-transcripts-css',
5594 6048 plugin_dir_url(__FILE__) . '../css/chat-transcripts.css',
@@ -5594,9 +6048,9 @@
5594 6048 plugin_dir_url(__FILE__) . '../css/chat-transcripts.css',
5595 6049 array(),
5596 6050 $transcripts_css_version
5597 6051 );
5598 -
6052 +
5599 6053 wp_enqueue_script(
5600 6054 'mxchat-transcripts-js',
5601 6055 plugin_dir_url(__FILE__) . '../js/mxchat_transcripts.js',
5602 6056 array('jquery'),
@@ -5603,9 +6057,9 @@
5603 6057 $transcripts_js_version,
5604 6058 true
5605 6059 );
5606 6060 }
5607 -
6061 +
5608 6062 wp_enqueue_style(
5609 6063 'mxchat-knowledge-css',
5610 6064 plugin_dir_url(__FILE__) . '../css/knowledge-style.css',
5611 6065 array(),
@@ -5655,8 +6109,10 @@
5655 6109 'live_agent_bot_token' => $this->options['live_agent_bot_token'] ?? '',
5656 6110 'live_agent_message_bg_color' => $this->options['live_agent_message_bg_color'] ?? '#ffffff',
5657 6111 'live_agent_message_font_color' => $this->options['live_agent_message_font_color'] ?? '#333333',
5658 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
5659 6115 'mode_indicator_bg_color' => $this->options['mode_indicator_bg_color'] ?? '#767676',
5660 6116 'mode_indicator_font_color' => $this->options['mode_indicator_font_color'] ?? '#ffffff',
5661 6117 'toolbar_icon_color' => $this->options['toolbar_icon_color'] ?? '#212121',
5662 6118 ));
@@ -5671,9 +6127,9 @@
5671 6127 }
5672 6128
5673 6129 if (isset($input['similarity_threshold'])) {
5674 6130 $new_input['similarity_threshold'] = absint($input['similarity_threshold']); // Ensure it's an integer
5675 - $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
5676 6132 }
5677 6133
5678 6134 if (isset($input['xai_api_key'])) {
5679 6135 $new_input['xai_api_key'] = sanitize_text_field($input['xai_api_key']);
@@ -5777,20 +6233,20 @@
5777 6233
5778 6234 if (isset($input['pre_chat_message'])) {
5779 6235 $new_input['pre_chat_message'] = sanitize_textarea_field($input['pre_chat_message']);
5780 6236 }
5781 -
6237 +
5782 6238 if (isset($input['voyage_api_key'])) {
5783 6239 $new_input['voyage_api_key'] = sanitize_text_field($input['voyage_api_key']);
5784 6240 }
5785 -
6241 +
5786 6242 // Add to your sanitize function
5787 6243 if (isset($input['embedding_model'])) {
5788 6244 $allowed_models = array(
5789 - 'text-embedding-ada-002',
5790 - 'text-embedding-3-small',
5791 - 'text-embedding-3-large',
5792 - 'voyage-3-large'
6245 + 'text-embedding-ada-002',
6246 + 'text-embedding-3-small',
6247 + 'text-embedding-3-large',
6248 + 'voyage-3-large'
5793 6249 );
5794 6250 if (in_array($input['embedding_model'], $allowed_models)) {
5795 6251 $new_input['embedding_model'] = sanitize_text_field($input['embedding_model']);
5796 6252 }
@@ -5800,8 +6256,9 @@
5800 6256 $allowed_models = array(
5801 6257 'grok-beta',
5802 6258 'grok-2',
5803 6259 'deepseek-chat',
6260 + 'claude-3-7-sonnet-20250219',
5804 6261 'claude-3-5-sonnet-20241022',
5805 6262 'claude-3-opus-20240229',
5806 6263 'claude-3-sonnet-20240229',
5807 6264 'claude-3-haiku-20240307',
@@ -5970,8 +6427,22 @@
5970 6427
5971 6428 if (isset($input['chat_toolbar_toggle'])) {
5972 6429 $new_input['chat_toolbar_toggle'] = $input['chat_toolbar_toggle'] === 'on' ? 'on' : 'off';
5973 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 + }
5974 6445
5975 6446 if (isset($input['pdf_intent_trigger_text'])) {
5976 6447 $new_input['pdf_intent_trigger_text'] = sanitize_text_field($input['pdf_intent_trigger_text']);
5977 6448 }
@@ -6126,8 +6597,69 @@
6126 6597 }
6127 6598 }
6128 6599
6129 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 +}
6130 6662
6131 6663
6132 6664 }
6133 6665 ?>