PluginProbe
MxChat – AI Chatbot & Content Generation for WordPress / 2.0.0
MxChat – AI Chatbot & Content Generation for WordPress v2.0.0
3.2.21 3.2.20 3.2.19 3.2.18 3.2.17 3.2.16 3.2.15 3.2.14 3.2.12 3.2.13 3.2.11 3.2.10 3.2.9 3.2.8 3.2.7 3.2.6 3.2.5 3.2.4 3.2.3 3.2.2 3.2.1 2.0.3 2.0.4 2.0.5 2.0.6 All 152 releases
← All changes | includes/class-mxchat-admin.php +522 -427 2.0.32.0.0 View file →
@@ -43,15 +43,14 @@
43 43 add_action('admin_post_mxchat_edit_intent', array($this, 'handle_edit_intent'));
44 44 add_action('save_post', array($this, 'handle_post_update'), 10, 3);
45 45 add_action('post_updated', array($this, 'handle_post_update'), 10, 3);
46 46 add_action('wp_ajax_mxchat_save_setting', array($this, 'mxchat_save_setting_callback'));
47 - add_action('wp_trash_post', array($this, 'mxchat_handle_post_delete'));
48 - add_action('before_delete_post', array($this, 'mxchat_handle_post_delete'));
47 +
49 48 add_action('wp_ajax_mxchat_save_prompts_setting', array($this, 'mxchat_save_prompts_setting_callback'));
50 49 if (isset($this->options['enable_woocommerce_integration']) &&
51 50 ($this->options['enable_woocommerce_integration'] === '1' ||
52 51 $this->options['enable_woocommerce_integration'] === 'on')) {
53 -
52 +
54 53 //error_log('MxChat Admin: WooCommerce integration is enabled, adding hooks');
55 54 add_action('wp_insert_post', array($this, 'mxchat_handle_product_change'), 10, 3);
56 55 add_action('wp_trash_post', array($this, 'mxchat_handle_product_delete'));
57 56 add_action('before_delete_post', array($this, 'mxchat_handle_product_delete'));
@@ -73,9 +72,9 @@
73 72 'deepseek_api_key' => '',
74 73 'system_prompt_instructions' => esc_html__('[EXAMPLE INSTRUCTIONS] You are an AI Chatbot assistant for this website. The primary subject you should focus on is [insert proper subject here]. Your main goal is to assist visitors with questions related to this specific topic. Here are some key things to keep in mind:
75 74 - Your name is [Chatbot Name].
76 75 - Stay focused on topics related to [insert proper subject here]. If a visitor asks about an unrelated topic, politely redirect the conversation to how you can assist them with this subject.
77 - - Do not make up links to pages. Only use specific links you see in your knowledgebase from [insert your domain]. Do not make assumptions or make up URLs.
76 + - Do not make up links to pages. Only use specific links you see in your knowledgebase.
78 77 - Keep your responses short, concise, and to the point. Provide clear and direct answers suitable for a chatbot interaction.
79 78 - Provide answers based on the knowledge available to you. If you do not have an answer to a specific question, let the visitor know that you don’t have the information.', 'mxchat'),
80 79 'model' => esc_html__('gpt-4o', 'mxchat'),
81 80 'rate_limit_logged_out' => esc_html__('100', 'mxchat'),
@@ -192,9 +191,9 @@
192 191 'manage_options', // Capability
193 192 'mxchat-intents', // Menu slug
194 193 array($this, 'mxchat_intents_page_html') // Callback function
195 194 );
196 -
195 +
197 196 add_submenu_page(
198 197 'mxchat-max',
199 198 esc_html__('Add Ons', 'mxchat'),
200 199 esc_html__('Add Ons', 'mxchat'),
@@ -242,8 +241,9 @@
242 241 // Also update old option for backwards compatibility
243 242 update_option('additional_popular_questions', $questions);
244 243 }
245 244 break;
245 + case 'close_button_color':
246 246 case 'user_message_bg_color':
247 247 case 'user_message_font_color':
248 248 case 'bot_message_bg_color':
249 249 case 'bot_message_font_color':
@@ -410,15 +410,16 @@
410 410 <?php endif; ?>
411 411
412 412 <div class="mxchat-agents-banner">
413 413 <p>
414 - <strong><?php echo esc_html__('The MxChat Add-Ons Platform', 'mxchat'); ?></strong><?php echo esc_html__(' is here! Pro users get unlimited access to our growing collection of powerful add-ons. ', 'mxchat'); ?><a href="<?php echo admin_url('admin.php?page=mxchat-addons'); ?>"><?php echo esc_html__('Explore all add-ons', 'mxchat'); ?></a><?php echo esc_html__(' including Forms Builder, Theme Customizer, Content Moderation, and more – all included with your lifetime Pro license!', 'mxchat'); ?>
415 - </p>
414 + <?php echo esc_html__('Pro users get exclusive access to', 'mxchat'); ?> <a href="https://mxchat.ai/agents/" target="_blank"><?php echo esc_html__('MxChat AI Agents', 'mxchat'); ?></a> <?php echo esc_html__('– our groundbreaking platform to test, refine, and deploy your chatbot with confidence. Take your AI assistant to the next level!', 'mxchat'); ?>
415 + </p>
416 416 </div>
417 417
418 418 <h2 class="mxchat-nav-tab-wrapper">
419 419 <a href="#chatbot" class="mxchat-nav-tab mxchat-nav-tab-active" data-tab="chatbot"><?php echo esc_html__('Chatbot', 'mxchat'); ?></a>
420 420 <a href="#embed" class="mxchat-nav-tab" data-tab="embed"><?php echo esc_html__('Integrations', 'mxchat'); ?></a>
421 + <a href="#theme" class="mxchat-nav-tab" data-tab="theme"><?php echo esc_html__('Theme', 'mxchat'); ?></a>
421 422 <a href="#general" class="mxchat-nav-tab" data-tab="general"><?php echo esc_html__('FAQ', 'mxchat'); ?></a>
422 423 </h2>
423 424
424 425 <div id="chatbot" class="mxchat-tab-content active">
@@ -474,8 +475,13 @@
474 475 </div>
475 476 </div>
476 477 </div>
477 478
479 + <div id="theme" class="mxchat-tab-content">
480 + <div class="mxchat-autosave-section">
481 + <?php do_settings_sections('mxchat-theme'); ?>
482 + </div>
483 + </div>
478 484
479 485 <div id="general" class="mxchat-tab-content">
480 486 <?php do_settings_sections('mxchat-general'); ?>
481 487 <p>
@@ -683,9 +689,9 @@
683 689 $per_page,
684 690 $offset
685 691 )
686 692 );
687 -
693 +
688 694 // Add the pagination links generation here
689 695 $page_links = paginate_links(array(
690 696 'base' => add_query_arg(array(
691 697 'paged' => '%#%',
@@ -741,9 +747,9 @@
741 747 <!-- Auto-Sync Settings -->
742 748 <div class="mxchat-settings-section">
743 749 <h3><?php esc_html_e('Auto-Sync Settings', 'mxchat'); ?></h3>
744 750 <p class="mxchat-description">
745 - <?php esc_html_e('Note: Auto-sync works only for newly published content. Existing posts and pages must be imported manually below. Works with Pinecone if enabled', 'mxchat'); ?>
751 + <?php esc_html_e('Note: Auto-sync works only for newly published content. Existing posts and pages must be imported manually below.', 'mxchat'); ?>
746 752 </p>
747 753 <div class="mxchat-autosave-section"> <!-- Add this wrapper -->
748 754 <div class="mxchat-toggle-group">
749 755 <div class="mxchat-toggle-container">
@@ -749,11 +755,11 @@
749 755 <div class="mxchat-toggle-container">
750 756 <label class="mxchat-toggle-switch">
751 757 <input type="checkbox"
752 758 name="mxchat_auto_sync_posts"
753 - class="mxchat-autosave-field"
759 + class="mxchat-autosave-field"
754 760 value="1"
755 - data-nonce="<?php echo wp_create_nonce('mxchat_prompts_setting_nonce'); ?>"
761 + data-nonce="<?php echo wp_create_nonce('mxchat_prompts_setting_nonce'); ?>"
756 762 <?php checked(get_option('mxchat_auto_sync_posts', '0'), '1'); ?>>
757 763 <span class="mxchat-toggle-slider"></span>
758 764 </label>
759 765 <span class="mxchat-toggle-label">
@@ -765,9 +771,9 @@
765 771 <input type="checkbox"
766 772 name="mxchat_auto_sync_pages"
767 773 class="mxchat-autosave-field"
768 774 value="1"
769 - data-nonce="<?php echo wp_create_nonce('mxchat_prompts_setting_nonce'); ?>"
775 + data-nonce="<?php echo wp_create_nonce('mxchat_prompts_setting_nonce'); ?>"
770 776 <?php checked(get_option('mxchat_auto_sync_pages', '0'), '1'); ?>>
771 777 <span class="mxchat-toggle-slider"></span>
772 778 </label>
773 779 <span class="mxchat-toggle-label">
@@ -800,9 +806,9 @@
800 806
801 807 <!-- Import Form -->
802 808 <?php if (!$is_processing) : ?>
803 809 <div class="mxchat-import-form">
804 - <form id="mxchat-sitemap-form" method="post"
810 + <form id="mxchat-sitemap-form" method="post"
805 811 action="<?php echo esc_url(admin_url('admin-post.php?action=mxchat_submit_sitemap')); ?>">
806 812 <?php wp_nonce_field('mxchat_submit_sitemap_action', 'mxchat_submit_sitemap_nonce'); ?>
807 813 <div class="mxchat-url-input-group">
808 814 <input type="url"
@@ -859,9 +865,9 @@
859 865
860 866 <?php if ($sitemap_status && $sitemap_status['status'] !== 'complete') : ?>
861 867 <div class="mxchat-status-card">
862 868 <div class="mxchat-status-header">
863 - <h4><?php esc_html_e('Sitemap Processing Status (Refresh for update)', 'mxchat'); ?></h4>
869 + <h4><?php esc_html_e('Sitemap Processing Status', 'mxchat'); ?></h4>
864 870 <?php if ($is_processing) : ?>
865 871 <form method="post" class="mxchat-stop-form"
866 872 action="<?php echo esc_url(admin_url('admin-post.php?action=mxchat_stop_processing')); ?>">
867 873 <?php wp_nonce_field('mxchat_stop_processing_action', 'mxchat_stop_processing_nonce'); ?>
@@ -904,19 +910,19 @@
904 910 <div class="mxchat-card">
905 911 <div class="mxchat-card-header">
906 912 <h2><?php esc_html_e('Submit Direct Content', 'mxchat'); ?></h2>
907 913 </div>
908 - <form id="mxchat-content-form" method="post"
914 + <form id="mxchat-content-form" method="post"
909 915 action="<?php echo esc_url(admin_url('admin-post.php?action=mxchat_submit_content')); ?>">
910 916 <?php wp_nonce_field('mxchat_submit_content_action', 'mxchat_submit_content_nonce'); ?>
911 917 <div class="mxchat-form-group">
912 918 <label for="article_content"><?php esc_html_e('Content:', 'mxchat'); ?></label>
913 - <textarea name="article_content" id="article_content" required
919 + <textarea name="article_content" id="article_content" required
914 920 placeholder="<?php esc_attr_e('Enter your content here...', 'mxchat'); ?>"></textarea>
915 921 </div>
916 922 <div class="mxchat-form-group">
917 923 <label for="article_url"><?php esc_html_e('Source URL (Optional):', 'mxchat'); ?></label>
918 - <input type="url" name="article_url" id="article_url"
924 + <input type="url" name="article_url" id="article_url"
919 925 placeholder="<?php esc_attr_e('Enter source URL', 'mxchat'); ?>">
920 926 </div>
921 927 <button type="submit" name="submit_content" class="mxchat-button-primary">
922 928 <?php esc_html_e('Submit Content', 'mxchat'); ?>
@@ -990,13 +996,13 @@
990 996 <span class="mxchat-na"><?php esc_html_e('N/A', 'mxchat'); ?></span>
991 997 <?php endif; ?>
992 998 </td>
993 999 <td class="mxchat-actions-cell">
994 - <button class="mxchat-button-icon edit-button"
1000 + <button class="mxchat-button-icon edit-button"
995 1001 data-id="<?php echo esc_attr($prompt->id); ?>">
996 1002 <span class="dashicons dashicons-edit"></span>
997 1003 </button>
998 - <button class="mxchat-button-icon save-button"
1004 + <button class="mxchat-button-icon save-button"
999 1005 data-id="<?php echo esc_attr($prompt->id); ?>"
1000 1006 style="display:none;"
1001 1007 data-nonce="<?php echo wp_create_nonce('mxchat_save_inline_nonce'); ?>">
1002 1008 <span class="dashicons dashicons-saved"></span>
@@ -1003,9 +1009,9 @@
1003 1009 </button>
1004 1010 <a href="<?php echo esc_url(admin_url(
1005 1011 'admin-post.php?action=mxchat_delete_prompt&id=' . esc_attr($prompt->id)
1006 1012 . '&_wpnonce=' . wp_create_nonce('mxchat_delete_prompt_nonce')
1007 - )); ?>"
1013 + )); ?>"
1008 1014 class="mxchat-button-icon delete-button"
1009 1015 onclick="return confirm('<?php esc_attr_e('Are you sure you want to delete this entry?', 'mxchat'); ?>');">
1010 1016 <span class="dashicons dashicons-trash"></span>
1011 1017 </a>
@@ -1242,9 +1248,9 @@
1242 1248
1243 1249 if ($pinecone_settings && is_array($pinecone_settings)) {
1244 1250 // Check if Pinecone is enabled and all required settings are present
1245 1251 $use_pinecone = (
1246 - isset($pinecone_settings['mxchat_use_pinecone']) &&
1252 + isset($pinecone_settings['mxchat_use_pinecone']) &&
1247 1253 $pinecone_settings['mxchat_use_pinecone'] === '1' &&
1248 1254 !empty($pinecone_settings['mxchat_pinecone_api_key']) &&
1249 1255 !empty($pinecone_settings['mxchat_pinecone_host']) &&
1250 1256 !empty($pinecone_settings['mxchat_pinecone_index']) &&
@@ -1263,9 +1269,9 @@
1263 1269 $pinecone_settings['mxchat_pinecone_index']
1264 1270 );
1265 1271
1266 1272 if (!$pinecone_result['success']) {
1267 - //error_log('MXChat: Pinecone sync failed - falling back to WordPress DB');
1273 + error_log('MXChat: Pinecone sync failed - falling back to WordPress DB');
1268 1274 $this->store_in_wordpress_db($content, $url, $embedding_vector);
1269 1275 }
1270 1276 } else {
1271 1277 // Fallback to WordPress DB storage
@@ -1271,25 +1277,28 @@
1271 1277 // Fallback to WordPress DB storage
1272 1278 $this->store_in_wordpress_db($content, $url, $embedding_vector);
1273 1279 }
1274 1280 }
1275 -// Modified storage function to add type field
1281 +
1276 1282 private function store_in_pinecone_main($embedding_vector, $content, $url, $api_key, $environment, $index_name, $vector_id = null) {
1283 + // Generate vector ID based on URL for consistent updates/inserts
1277 1284 $vector_id = $vector_id ?: md5($url);
1285 +
1286 + // Get the Pinecone host from options
1278 1287 $options = get_option('mxchat_pinecone_addon_options');
1279 1288 $host = $options['mxchat_pinecone_host'] ?? '';
1280 -
1289 +
1281 1290 if (empty($host)) {
1291 + //error_log('Pinecone host is not configured');
1282 1292 return array(
1283 1293 'success' => false,
1284 1294 'message' => 'Pinecone host is not configured. Please set the host in your settings.'
1285 1295 );
1286 1296 }
1287 -
1288 - // Determine if this is a product URL
1289 - $is_product = (strpos($url, '/product/') !== false || strpos($url, '/shop/') !== false);
1290 -
1297 +
1298 + // Build API endpoint using the configured host
1291 1299 $api_endpoint = "https://{$host}/vectors/upsert";
1300 +
1292 1301 $request_body = array(
1293 1302 'vectors' => array(
1294 1303 array(
1295 1304 'id' => $vector_id,
@@ -1296,15 +1305,14 @@
1296 1305 'values' => $embedding_vector,
1297 1306 'metadata' => array(
1298 1307 'text' => $content,
1299 1308 'source_url' => $url,
1300 - 'type' => $is_product ? 'product' : 'content',
1301 1309 'last_updated' => time()
1302 1310 )
1303 1311 )
1304 1312 )
1305 1313 );
1306 -
1314 +
1307 1315 $response = wp_remote_post($api_endpoint, array(
1308 1316 'headers' => array(
1309 1317 'Api-Key' => $api_key,
1310 1318 'accept' => 'application/json',
@@ -1313,24 +1321,27 @@
1313 1321 'body' => wp_json_encode($request_body),
1314 1322 'timeout' => 30,
1315 1323 'data_format' => 'body'
1316 1324 ));
1317 -
1325 +
1318 1326 if (is_wp_error($response)) {
1327 + //error_log('Pinecone API WP Error: ' . $response->get_error_message());
1319 1328 return array(
1320 1329 'success' => false,
1321 1330 'message' => $response->get_error_message()
1322 1331 );
1323 1332 }
1324 -
1333 +
1325 1334 $response_code = wp_remote_retrieve_response_code($response);
1326 1335 if ($response_code !== 200) {
1327 1336 $body = wp_remote_retrieve_body($response);
1337 + //error_log('Pinecone API Error Body: ' . $body);
1338 + //error_log('Pinecone API Request: ' . wp_json_encode($request_body));
1328 1339 return array(
1329 1340 'success' => false,
1330 1341 'message' => sprintf(
1331 - 'Pinecone API error (HTTP %d): %s',
1332 - $response_code,
1342 + 'Pinecone API error (HTTP %d): %s',
1343 + $response_code,
1333 1344 $body
1334 1345 )
1335 1346 );
1336 1347 }
@@ -1339,8 +1350,10 @@
1339 1350 'success' => true,
1340 1351 'message' => 'Successfully stored in Pinecone'
1341 1352 );
1342 1353 }
1354 +
1355 +
1343 1356 // Helper method for WordPress DB storage
1344 1357 private function store_in_wordpress_db($content, $url, $embedding_vector) {
1345 1358 global $wpdb;
1346 1359 $table_name = $wpdb->prefix . 'mxchat_system_prompt_content';
@@ -1372,109 +1385,16 @@
1372 1385 array('%s', '%s', '%s', '%s')
1373 1386 );
1374 1387 }
1375 1388 }
1376 -/**
1377 - * Handle deletion of posts and pages from both Pinecone and WordPress DB
1378 - *
1379 - * @param int $post_id The ID of the post being deleted
1380 - * @return void
1381 - */
1382 -public function mxchat_handle_post_delete($post_id) {
1383 - // Get post data before it's deleted
1384 - $post = get_post($post_id);
1385 1389
1386 - // Basic validation
1387 - if (!$post || wp_is_post_revision($post_id)) {
1388 - return;
1389 - }
1390 1390
1391 - // Check post type
1392 - $post_type = $post->post_type;
1393 - if (!in_array($post_type, array('post', 'page'))) {
1394 - return;
1395 - }
1396 -
1397 - // Check if sync is enabled for this post type
1398 - $sync_option = ($post_type === 'post') ? 'mxchat_auto_sync_posts' : 'mxchat_auto_sync_pages';
1399 - if (get_option($sync_option) != '1') {
1400 - return;
1401 - }
1402 -
1403 - // Get the URL before post is deleted
1404 - $source_url = get_permalink($post_id);
1405 - if (!$source_url) {
1406 - //error_log('MXChat: Failed to get permalink for post ' . $post_id);
1407 - return;
1408 - }
1409 -
1410 - // Check for Pinecone addon and its settings
1411 - $pinecone_settings = get_option('mxchat_pinecone_addon_options');
1412 - $use_pinecone = false;
1413 - if ($pinecone_settings && is_array($pinecone_settings)) {
1414 - $use_pinecone = (
1415 - isset($pinecone_settings['mxchat_use_pinecone']) &&
1416 - $pinecone_settings['mxchat_use_pinecone'] === '1' &&
1417 - !empty($pinecone_settings['mxchat_pinecone_api_key']) &&
1418 - !empty($pinecone_settings['mxchat_pinecone_host']) &&
1419 - !empty($pinecone_settings['mxchat_pinecone_index']) &&
1420 - !empty($pinecone_settings['mxchat_pinecone_environment'])
1421 - );
1422 - }
1423 -
1424 - $deletion_successful = false;
1425 -
1426 - if ($use_pinecone) {
1427 - try {
1428 - $pinecone_result = $this->delete_from_pinecone(
1429 - array($source_url),
1430 - $pinecone_settings['mxchat_pinecone_api_key'],
1431 - $pinecone_settings['mxchat_pinecone_environment'],
1432 - $pinecone_settings['mxchat_pinecone_index']
1433 - );
1434 -
1435 - if (!$pinecone_result['success']) {
1436 - //error_log('MXChat: Pinecone deletion failed for URL: ' . $source_url . ' - ' . $pinecone_result['message']);
1437 - } else {
1438 - $deletion_successful = true;
1439 - }
1440 - } catch (Exception $e) {
1441 - //error_log('MXChat: Exception during Pinecone deletion - ' . $e->getMessage());
1442 - }
1443 - }
1444 -
1445 - // Always attempt WordPress DB deletion, regardless of Pinecone status
1446 - try {
1447 - global $wpdb;
1448 - $table_name = $wpdb->prefix . 'mxchat_system_prompt_content';
1449 -
1450 - $result = $wpdb->delete(
1451 - $table_name,
1452 - array('source_url' => $source_url),
1453 - array('%s')
1454 - );
1455 -
1456 - if ($result === false) {
1457 - //error_log('MXChat: WordPress DB deletion failed for URL: ' . $source_url);
1458 - } else {
1459 - $deletion_successful = true;
1460 - }
1461 - } catch (Exception $e) {
1462 - //error_log('MXChat: Exception during WordPress DB deletion - ' . $e->getMessage());
1463 - }
1464 -
1465 - if (!$deletion_successful) {
1466 - //error_log('MXChat: Complete deletion failure for post ID: ' . $post_id . ' URL: ' . $source_url);
1467 - }
1468 -}
1469 -
1470 -
1471 1391 public function mxchat_handle_content_submission() {
1472 1392 // Check if the form was submitted and the user has permission.
1473 1393 if (!isset($_POST['submit_content']) || !current_user_can('manage_options')) {
1474 1394 return;
1475 1395 }
1476 -
1396 +
1477 1397 // Verify the nonce.
1478 1398 $nonce = isset($_POST['mxchat_submit_content_nonce']) ? sanitize_text_field(wp_unslash($_POST['mxchat_submit_content_nonce'])) : '';
1479 1399 if (!wp_verify_nonce($nonce, 'mxchat_submit_content_action')) {
1480 1400 wp_die(esc_html__('Nonce verification failed.', 'mxchat'));
@@ -1486,10 +1406,10 @@
1486 1406
1487 1407 // Generate the embedding vector.
1488 1408 $embedding_vector = $this->mxchat_generate_embedding($article_content);
1489 1409 if (!is_array($embedding_vector)) {
1490 - set_transient('mxchat_admin_notice_error',
1491 - esc_html__('Embedding generation failed. Please ensure your API key is correct and try again.', 'mxchat'),
1410 + set_transient('mxchat_admin_notice_error',
1411 + esc_html__('Embedding generation failed. Please ensure your API key is correct and try again.', 'mxchat'),
1492 1412 30
1493 1413 );
1494 1414 wp_safe_redirect(esc_url(admin_url('admin.php?page=mxchat-prompts')));
1495 1415 exit;
@@ -1516,15 +1436,15 @@
1516 1436 array('%s', '%s', '%s')
1517 1437 );
1518 1438
1519 1439 if ($inserted === false) {
1520 - set_transient('mxchat_admin_notice_error',
1521 - esc_html__('Error inserting content into the database. Please try again.', 'mxchat'),
1440 + set_transient('mxchat_admin_notice_error',
1441 + esc_html__('Error inserting content into the database. Please try again.', 'mxchat'),
1522 1442 30
1523 1443 );
1524 1444 } else {
1525 - set_transient('mxchat_admin_notice_success',
1526 - esc_html__('Content successfully submitted!', 'mxchat'),
1445 + set_transient('mxchat_admin_notice_success',
1446 + esc_html__('Content successfully submitted!', 'mxchat'),
1527 1447 30
1528 1448 );
1529 1449 }
1530 1450
@@ -1709,11 +1629,9 @@
1709 1629
1710 1630 return array(
1711 1631 'total_pages' => absint($status['total_pages']),
1712 1632 'processed_pages' => absint($status['processed_pages']),
1713 - 'percentage' => ($status['total_pages'] > 0)
1714 - ? round((absint($status['processed_pages']) / absint($status['total_pages'])) * 100)
1715 - : 0,
1633 + 'percentage' => round((absint($status['processed_pages']) / absint($status['total_pages'])) * 100),
1716 1634 'status' => sanitize_text_field($status['status']),
1717 1635 'last_update' => human_time_diff(absint($status['last_update']), time()) . ' ' . esc_html__('ago', 'mxchat')
1718 1636 );
1719 1637 }
@@ -1922,25 +1840,25 @@
1922 1840 $sitemap_url = esc_url_raw($sitemap_url);
1923 1841 $total_urls = absint($total_urls);
1924 1842 $batch_size = absint($batch_size);
1925 1843 $batch_pause = absint($batch_pause);
1926 -
1844 +
1927 1845 if (!is_array($urls) || empty($urls)) {
1928 1846 return;
1929 1847 }
1930 -
1848 +
1931 1849 try {
1932 1850 $status_key = sanitize_key('mxchat_sitemap_status_' . md5($sitemap_url));
1933 1851 $status = get_transient($status_key);
1934 -
1852 +
1935 1853 if (!$status || !is_array($status)) {
1936 1854 throw new Exception('Invalid status data retrieved from transient');
1937 1855 }
1938 -
1856 +
1939 1857 $start_url = absint($status['processed_urls']);
1940 1858 $end_url = min($start_url + $batch_size, $total_urls);
1941 1859 $instance = new self();
1942 -
1860 +
1943 1861 // Track failures in batch
1944 1862 $batch_stats = [
1945 1863 'processed' => 0,
1946 1864 'failed' => 0,
@@ -1949,31 +1867,31 @@
1949 1867
1950 1868 for ($i = $start_url; $i < $end_url; $i++) {
1951 1869 $page_url = esc_url_raw($urls[$i]);
1952 1870 $page_response = wp_remote_get($page_url);
1953 -
1871 +
1954 1872 if (is_wp_error($page_response) || wp_remote_retrieve_response_code($page_response) !== 200) {
1955 1873 $batch_stats['failed']++;
1956 1874 continue;
1957 1875 }
1958 -
1876 +
1959 1877 $page_html = wp_remote_retrieve_body($page_response);
1960 1878 $page_content = $instance->mxchat_extract_main_content($page_html);
1961 1879 $sanitized_content = $instance->mxchat_sanitize_content_for_api($page_content);
1962 -
1880 +
1963 1881 if (!empty($sanitized_content)) {
1964 1882 $embedding_vector = $instance->mxchat_generate_embedding($sanitized_content);
1965 -
1883 +
1966 1884 if (is_array($embedding_vector)) {
1967 1885 $options = get_option('mxchat_options');
1968 1886 $submission_result = MxChat_Utils::submit_content_to_db($sanitized_content, $page_url, $options['api_key']);
1969 -
1887 +
1970 1888 if (is_wp_error($submission_result)) {
1971 1889 $batch_stats['failed']++;
1972 1890 $batch_stats['last_error'] = $submission_result->get_error_message();
1973 1891 continue;
1974 1892 }
1975 -
1893 +
1976 1894 $batch_stats['processed']++;
1977 1895 } else {
1978 1896 $batch_stats['failed']++;
1979 1897 $batch_stats['last_error'] = 'Failed to generate embedding. Please check OpenAI API key.';
@@ -1978,14 +1896,14 @@
1978 1896 $batch_stats['failed']++;
1979 1897 $batch_stats['last_error'] = 'Failed to generate embedding. Please check OpenAI API key.';
1980 1898 }
1981 1899 }
1982 -
1900 +
1983 1901 $status['processed_urls'] = absint($i + 1);
1984 1902 $status['last_update'] = time();
1985 1903 $status['failed_urls'] = absint($status['failed_urls'] ?? 0) + $batch_stats['failed'];
1986 1904 $status['last_error'] = $batch_stats['last_error'];
1987 -
1905 +
1988 1906 set_transient($status_key, array_map('sanitize_text_field', $status), DAY_IN_SECONDS);
1989 1907 }
1990 1908
1991 1909 // If all URLs in this batch failed, stop processing
@@ -2021,20 +1939,18 @@
2021 1939
2022 1940 public function get_sitemap_processing_status($sitemap_url) {
2023 1941 $sitemap_url = esc_url_raw($sitemap_url);
2024 1942 $status = get_transient(sanitize_key('mxchat_sitemap_status_' . md5($sitemap_url)));
2025 -
1943 +
2026 1944 if (!$status || !is_array($status)) {
2027 1945 return false;
2028 1946 }
2029 -
1947 +
2030 1948 return array(
2031 1949 'total_urls' => absint($status['total_urls']),
2032 1950 'processed_urls' => absint($status['processed_urls']),
2033 1951 'failed_urls' => absint($status['failed_urls'] ?? 0),
2034 - 'percentage' => ($status['total_urls'] > 0)
2035 - ? round((absint($status['processed_urls']) / absint($status['total_urls'])) * 100)
2036 - : 0,
1952 + 'percentage' => round((absint($status['processed_urls']) / absint($status['total_urls'])) * 100),
2037 1953 'status' => sanitize_text_field($status['status']),
2038 1954 'last_update' => human_time_diff(absint($status['last_update']), time()) . ' ' . esc_html__('ago', 'mxchat'),
2039 1955 'error' => isset($status['error']) ? sanitize_text_field($status['error']) : '',
2040 1956 'last_error' => isset($status['last_error']) ? sanitize_text_field($status['last_error']) : ''
@@ -2140,9 +2056,9 @@
2140 2056 $use_pinecone = false;
2141 2057
2142 2058 if ($pinecone_settings && is_array($pinecone_settings)) {
2143 2059 $use_pinecone = (
2144 - isset($pinecone_settings['mxchat_use_pinecone']) &&
2060 + isset($pinecone_settings['mxchat_use_pinecone']) &&
2145 2061 $pinecone_settings['mxchat_use_pinecone'] === '1' &&
2146 2062 !empty($pinecone_settings['mxchat_pinecone_api_key']) &&
2147 2063 !empty($pinecone_settings['mxchat_pinecone_host']) &&
2148 2064 !empty($pinecone_settings['mxchat_pinecone_index']) &&
@@ -2173,11 +2089,11 @@
2173 2089 public function mxchat_handle_product_delete($post_id) {
2174 2090 if (get_post_type($post_id) !== 'product') {
2175 2091 return;
2176 2092 }
2177 -
2093 +
2178 2094 $source_url = get_permalink($post_id);
2179 -
2095 +
2180 2096 // Check for Pinecone addon and its settings
2181 2097 $pinecone_settings = get_option('mxchat_pinecone_addon_options');
2182 2098 $use_pinecone = false;
2183 2099
@@ -2182,9 +2098,9 @@
2182 2098 $use_pinecone = false;
2183 2099
2184 2100 if ($pinecone_settings && is_array($pinecone_settings)) {
2185 2101 $use_pinecone = (
2186 - isset($pinecone_settings['mxchat_use_pinecone']) &&
2102 + isset($pinecone_settings['mxchat_use_pinecone']) &&
2187 2103 $pinecone_settings['mxchat_use_pinecone'] === '1' &&
2188 2104 !empty($pinecone_settings['mxchat_pinecone_api_key']) &&
2189 2105 !empty($pinecone_settings['mxchat_pinecone_host']) &&
2190 2106 !empty($pinecone_settings['mxchat_pinecone_index']) &&
@@ -2206,98 +2122,8 @@
2206 2122 $wpdb->delete($table_name, array('source_url' => $source_url), array('%s'));
2207 2123 }
2208 2124 }
2209 2125
2210 -/**
2211 - * Delete vectors from Pinecone by source URL
2212 - *
2213 - * @param array $urls Array of source URLs to delete
2214 - * @param string $api_key Pinecone API key
2215 - * @param string $environment Pinecone environment
2216 - * @param string $index_name Pinecone index name
2217 - * @return array Associative array with 'success' boolean and 'message' string
2218 - */
2219 -private function delete_from_pinecone($urls, $api_key, $environment, $index_name) {
2220 - // Get the Pinecone host from options (matching your store_in_pinecone_main pattern)
2221 - $options = get_option('mxchat_pinecone_addon_options');
2222 - $host = $options['mxchat_pinecone_host'] ?? '';
2223 -
2224 - if (empty($host)) {
2225 - return array(
2226 - 'success' => false,
2227 - 'message' => 'Pinecone host is not configured. Please set the host in your settings.'
2228 - );
2229 - }
2230 -
2231 - // Build API endpoint using the configured host
2232 - $api_endpoint = "https://{$host}/vectors/delete";
2233 -
2234 - // Create vector IDs from URLs (matching your store method's ID generation)
2235 - $vector_ids = array_map('md5', $urls);
2236 -
2237 - // Prepare the delete request body
2238 - $request_body = array(
2239 - 'ids' => $vector_ids,
2240 - 'filter' => array(
2241 - 'source_url' => array(
2242 - '$in' => $urls
2243 - )
2244 - )
2245 - );
2246 -
2247 - // Make the deletion request
2248 - $response = wp_remote_post($api_endpoint, array(
2249 - 'headers' => array(
2250 - 'Api-Key' => $api_key,
2251 - 'accept' => 'application/json',
2252 - 'content-type' => 'application/json'
2253 - ),
2254 - 'body' => wp_json_encode($request_body),
2255 - 'timeout' => 30,
2256 - 'data_format' => 'body'
2257 - ));
2258 -
2259 - // Handle WordPress HTTP API errors
2260 - if (is_wp_error($response)) {
2261 - return array(
2262 - 'success' => false,
2263 - 'message' => $response->get_error_message()
2264 - );
2265 - }
2266 -
2267 - // Check response status
2268 - $response_code = wp_remote_retrieve_response_code($response);
2269 - if ($response_code !== 200) {
2270 - $body = wp_remote_retrieve_body($response);
2271 - return array(
2272 - 'success' => false,
2273 - 'message' => sprintf(
2274 - 'Pinecone API error (HTTP %d): %s',
2275 - $response_code,
2276 - $body
2277 - )
2278 - );
2279 - }
2280 -
2281 - // Parse response body
2282 - $body = wp_remote_retrieve_body($response);
2283 - $response_data = json_decode($body, true);
2284 -
2285 - // Final validation of the response
2286 - if (json_last_error() !== JSON_ERROR_NONE) {
2287 - return array(
2288 - 'success' => false,
2289 - 'message' => 'Failed to parse Pinecone response: ' . json_last_error_msg()
2290 - );
2291 - }
2292 -
2293 - return array(
2294 - 'success' => true,
2295 - 'message' => sprintf('Successfully deleted %d vectors from Pinecone', count($vector_ids))
2296 - );
2297 -}
2298 -
2299 -
2300 2126 public function mxchat_fetch_chat_history() {
2301 2127 global $wpdb;
2302 2128 $table_name = $wpdb->prefix . 'mxchat_chat_transcripts';
2303 2129
@@ -2473,15 +2299,15 @@
2473 2299 </div>
2474 2300 </form>
2475 2301 <!-- License Status Display -->
2476 2302 <div class="mxchat-pro-status">
2477 - <h3><?php esc_html_e('License Status:', 'mxchat'); ?>
2303 + <h3><?php esc_html_e('License Status:', 'mxchat'); ?>
2478 2304 <span id="mxchat-license-status" class="mxchat-status-badge <?php echo $license_status; ?>">
2479 2305 <?php echo $license_status === 'active' ? esc_html__('Active', 'mxchat') : esc_html__('Inactive', 'mxchat'); ?>
2480 2306 </span>
2481 2307 </h3>
2482 2308 </div>
2483 -
2309 +
2484 2310 </div>
2485 2311 <?php
2486 2312 }
2487 2313
@@ -2510,9 +2336,9 @@
2510 2336 $callback_filter = isset($_GET['callback_filter']) ? sanitize_text_field($_GET['callback_filter']) : '';
2511 2337
2512 2338 if ($search_term) {
2513 2339 $search_term_like = '%' . $wpdb->esc_like($search_term) . '%';
2514 - $where .= $wpdb->prepare(' AND (intent_label LIKE %s OR phrases LIKE %s)',
2340 + $where .= $wpdb->prepare(' AND (intent_label LIKE %s OR phrases LIKE %s)',
2515 2341 $search_term_like, $search_term_like);
2516 2342 }
2517 2343
2518 2344 if ($callback_filter) {
@@ -2524,9 +2350,9 @@
2524 2350 $total_pages = ceil($total_intents / $per_page);
2525 2351
2526 2352 // Get intents
2527 2353 $intents = $wpdb->get_results($wpdb->prepare(
2528 - "SELECT * FROM $table_name WHERE $where LIMIT %d OFFSET %d",
2354 + "SELECT * FROM $table_name WHERE $where LIMIT %d OFFSET %d",
2529 2355 $per_page, $offset
2530 2356 ));
2531 2357
2532 2358 // Get callbacks
@@ -2549,9 +2375,9 @@
2549 2375 <div class="mxchat-card">
2550 2376 <div class="mxchat-card-header">
2551 2377 <h2><?php esc_html_e('Add New Intent', 'mxchat'); ?></h2>
2552 2378 </div>
2553 -
2379 +
2554 2380 <div class="mxchat-intent-documentation">
2555 2381 <p>
2556 2382 <?php esc_html_e('We highly encourage users to quickly read our ', 'mxchat'); ?>
2557 2383 <a href="https://mxchat.ai/documentation/#intents" target="_blank" rel="noopener noreferrer">
@@ -2560,9 +2386,9 @@
2560 2386 <?php esc_html_e(' to better understand intents. Some intents require setup in the Integration tab. If your intent is not triggering lower similarity threshold test.', 'mxchat'); ?>
2561 2387 </p>
2562 2388 </div>
2563 2389
2564 - <form id="mxchat-add-intent-form" method="post"
2390 + <form id="mxchat-add-intent-form" method="post"
2565 2391 action="<?php echo esc_url(admin_url('admin-post.php')); ?>">
2566 2392 <input type="hidden" name="action" value="mxchat_add_intent">
2567 2393 <?php wp_nonce_field('mxchat_add_intent_nonce'); ?>
2568 2394
@@ -2587,9 +2413,9 @@
2587 2413 <div class="mxchat-form-group">
2588 2414 <label for="callback_function">
2589 2415 <?php esc_html_e('Callback Function', 'mxchat'); ?>
2590 2416 </label>
2591 - <select name="callback_function" id="callback_function"
2417 + <select name="callback_function" id="callback_function"
2592 2418 class="mxchat-intent-select" required>
2593 2419 <option value="">
2594 2420 <?php esc_html_e('Select a Callback', 'mxchat'); ?>
2595 2421 </option>
@@ -2602,9 +2428,9 @@
2602 2428 $pro_only = $data['pro_only'];
2603 2429 $disabled = (!$this->is_activated && $pro_only) ? 'disabled' : '';
2604 2430 $label_suffix = (!$this->is_activated && $pro_only) ? ' (Pro Only)' : '';
2605 2431 ?>
2606 - <option value="<?php echo esc_attr($function); ?>"
2432 + <option value="<?php echo esc_attr($function); ?>"
2607 2433 <?php echo $disabled; ?>>
2608 2434 <?php echo esc_html($label . $label_suffix); ?>
2609 2435 </option>
2610 2436 <?php
@@ -2629,9 +2455,9 @@
2629 2455 <form method="get" class="mxchat-search-form">
2630 2456 <input type="hidden" name="page" value="mxchat-intents">
2631 2457 <div class="mxchat-search-group">
2632 2458 <span class="dashicons dashicons-search"></span>
2633 - <input type="text" name="s"
2459 + <input type="text" name="s"
2634 2460 placeholder="<?php esc_attr_e('Search Intents', 'mxchat'); ?>"
2635 2461 value="<?php echo esc_attr($search_term); ?>">
2636 2462 <select name="callback_filter" class="mxchat-intent-filter">
2637 2463 <option value="">
@@ -2638,9 +2464,9 @@
2638 2464 <?php esc_html_e('All Callbacks', 'mxchat'); ?>
2639 2465 </option>
2640 2466 <?php foreach ($available_callbacks as $function => $callback_data) :
2641 2467 $label = $callback_data['label']; ?>
2642 - <option value="<?php echo esc_attr($function); ?>"
2468 + <option value="<?php echo esc_attr($function); ?>"
2643 2469 <?php selected($callback_filter, $function); ?>>
2644 2470 <?php echo esc_html($label); ?>
2645 2471 </option>
2646 2472 <?php endforeach; ?>
@@ -2663,123 +2489,83 @@
2663 2489 <th><?php esc_html_e('Similarity Threshold', 'mxchat'); ?></th>
2664 2490 <th><?php esc_html_e('Actions', 'mxchat'); ?></th>
2665 2491 </tr>
2666 2492 </thead>
2667 - <tbody>
2668 - <?php if ($intents) :
2669 - foreach ($intents as $intent) :
2670 - $callback_function = $intent->callback_function;
2671 - $callback_label = isset($available_callbacks[$callback_function]['label'])
2672 - ? $available_callbacks[$callback_function]['label']
2673 - : $callback_function;
2674 - $threshold_value = isset($intent->similarity_threshold)
2675 - ? round($intent->similarity_threshold * 100)
2676 - : 85;
2677 -
2678 - // Check if this is a form intent (its intent_label starts with "Form ")
2679 - $is_form_intent = strpos($intent->intent_label, 'Form ') === 0;
2680 - ?>
2681 - <tr<?php echo $is_form_intent ? ' class="mxchat-form-intent"' : ''; ?>>
2682 - <td>
2683 - <?php
2684 - if ($is_form_intent) {
2685 - // Attempt to extract the form ID from the intent_label.
2686 - preg_match('/Form (\d+)/', $intent->intent_label, $matches);
2687 - $form_id = isset($matches[1]) ? intval($matches[1]) : 0;
2688 - if ($form_id) {
2689 - global $wpdb;
2690 - $forms_table = $wpdb->prefix . 'mxchat_forms';
2691 - $form = $wpdb->get_row($wpdb->prepare("SELECT title FROM $forms_table WHERE id = %d", $form_id));
2692 - if ($form && !empty($form->title)) {
2693 - echo esc_html($form->title);
2694 - } else {
2695 - echo esc_html($intent->intent_label);
2696 - }
2697 - } else {
2698 - echo esc_html($intent->intent_label);
2699 - }
2700 - echo ' <span class="mxchat-badge">Form Intent</span>';
2701 - } else {
2702 - echo esc_html($intent->intent_label);
2703 - }
2704 - ?>
2705 - </td>
2706 - <td class="mxchat-content-cell">
2707 - <?php echo esc_html($intent->phrases); ?>
2708 - </td>
2709 - <td><?php echo esc_html($callback_label); ?></td>
2710 - <td>
2711 - <!-- Similarity threshold adjustment (shown for all intents) -->
2712 - <form method="post"
2713 - action="<?php echo esc_url(admin_url('admin-post.php')); ?>"
2714 - class="mxchat-threshold-form">
2715 - <?php wp_nonce_field('mxchat_update_intent_threshold_nonce'); ?>
2716 - <input type="hidden" name="action"
2717 - value="mxchat_update_intent_threshold">
2718 - <input type="hidden" name="intent_id"
2719 - value="<?php echo esc_attr($intent->id); ?>">
2720 - <div class="mxchat-slider-group">
2721 - <input type="range"
2722 - name="intent_threshold"
2723 - id="intent_threshold_<?php echo esc_attr($intent->id); ?>"
2724 - min="70"
2725 - max="95"
2726 - value="<?php echo esc_attr($threshold_value); ?>"
2727 - class="mxchat-intent-slider"
2728 - oninput="document.getElementById('threshold_output_<?php echo esc_attr($intent->id); ?>').value = this.value + '%'">
2729 - <output id="threshold_output_<?php echo esc_attr($intent->id); ?>"
2730 - class="mxchat-intent-output">
2731 - <?php echo esc_html($threshold_value); ?>%
2732 - </output>
2733 - </div>
2734 - <button type="submit" class="mxchat-button-icon">
2735 - <span class="dashicons dashicons-saved"></span>
2736 - </button>
2737 - </form>
2738 - </td>
2739 - <td class="mxchat-actions-cell">
2740 - <?php if (!$is_form_intent) : ?>
2741 - <!-- Standard intents: allow edit and delete -->
2742 - <button type="button"
2743 - class="mxchat-button-icon mxchat-edit-button"
2744 - data-intent-id="<?php echo esc_attr($intent->id); ?>"
2745 - data-phrases="<?php echo esc_attr($intent->phrases); ?>">
2746 - <span class="dashicons dashicons-edit"></span>
2747 - </button>
2748 - <form method="post"
2749 - action="<?php echo esc_url(admin_url('admin-post.php')); ?>"
2750 - class="mxchat-delete-form"
2751 - onsubmit="return confirm('<?php esc_attr_e('Are you sure you want to delete this intent?', 'mxchat'); ?>');">
2752 - <?php wp_nonce_field('mxchat_delete_intent_nonce'); ?>
2753 - <input type="hidden" name="action" value="mxchat_delete_intent">
2754 - <input type="hidden" name="intent_id"
2755 - value="<?php echo esc_attr($intent->id); ?>">
2756 - <button type="submit" class="mxchat-button-icon">
2757 - <span class="dashicons dashicons-trash"></span>
2758 - </button>
2759 - </form>
2760 - <?php else : ?>
2761 - <!-- Form intents: show manage in forms button -->
2762 - <?php
2763 - preg_match('/Form (\d+)/', $intent->intent_label, $matches);
2764 - $form_id = isset($matches[1]) ? $matches[1] : '';
2765 - ?>
2766 - <a href="<?php echo esc_url(admin_url('admin.php?page=mxchat-forms&action=edit&form_id=' . $form_id)); ?>"
2767 - class="mxchat-button-secondary">
2768 - <?php esc_html_e('Manage in Forms', 'mxchat'); ?>
2769 - </a>
2770 - <?php endif; ?>
2771 - </td>
2772 - </tr>
2773 - <?php endforeach;
2774 - else : ?>
2493 + <tbody>
2494 + <?php if ($intents) :
2495 + foreach ($intents as $intent) :
2496 + $callback_function = $intent->callback_function;
2497 + $callback_label = isset($available_callbacks[$callback_function]['label'])
2498 + ? $available_callbacks[$callback_function]['label']
2499 + : $callback_function;
2500 + $threshold_value = isset($intent->similarity_threshold)
2501 + ? round($intent->similarity_threshold * 100)
2502 + : 85;
2503 + ?>
2775 2504 <tr>
2776 - <td colspan="5" class="mxchat-no-records">
2777 - <?php esc_html_e('No intents found.', 'mxchat'); ?>
2505 + <td><?php echo esc_html($intent->intent_label); ?></td>
2506 + <td class="mxchat-content-cell">
2507 + <?php echo esc_html($intent->phrases); ?>
2778 2508 </td>
2509 + <td><?php echo esc_html($callback_label); ?></td>
2510 + <td>
2511 + <form method="post"
2512 + action="<?php echo esc_url(admin_url('admin-post.php')); ?>"
2513 + class="mxchat-threshold-form">
2514 + <?php wp_nonce_field('mxchat_update_intent_threshold_nonce'); ?>
2515 + <input type="hidden" name="action"
2516 + value="mxchat_update_intent_threshold">
2517 + <input type="hidden" name="intent_id"
2518 + value="<?php echo esc_attr($intent->id); ?>">
2519 + <div class="mxchat-slider-group">
2520 + <input type="range"
2521 + name="intent_threshold"
2522 + id="intent_threshold_<?php echo esc_attr($intent->id); ?>"
2523 + min="70"
2524 + max="95"
2525 + value="<?php echo esc_attr($threshold_value); ?>"
2526 + class="mxchat-intent-slider"
2527 + oninput="document.getElementById('threshold_output_<?php echo esc_attr($intent->id); ?>').value = this.value + '%'">
2528 + <output id="threshold_output_<?php echo esc_attr($intent->id); ?>"
2529 + class="mxchat-intent-output">
2530 + <?php echo esc_html($threshold_value); ?>%
2531 + </output>
2532 + </div>
2533 + <button type="submit" class="mxchat-button-icon">
2534 + <span class="dashicons dashicons-saved"></span>
2535 + </button>
2536 + </form>
2537 + </td>
2538 + <td class="mxchat-actions-cell">
2539 + <button type="button"
2540 + class="mxchat-button-icon mxchat-edit-button"
2541 + data-intent-id="<?php echo esc_attr($intent->id); ?>"
2542 + data-phrases="<?php echo esc_attr($intent->phrases); ?>">
2543 + <span class="dashicons dashicons-edit"></span>
2544 + </button>
2545 + <form method="post"
2546 + action="<?php echo esc_url(admin_url('admin-post.php')); ?>"
2547 + class="mxchat-delete-form"
2548 + onsubmit="return confirm('<?php esc_attr_e('Are you sure you want to delete this intent?', 'mxchat'); ?>');">
2549 + <?php wp_nonce_field('mxchat_delete_intent_nonce'); ?>
2550 + <input type="hidden" name="action" value="mxchat_delete_intent">
2551 + <input type="hidden" name="intent_id"
2552 + value="<?php echo esc_attr($intent->id); ?>">
2553 + <button type="submit" class="mxchat-button-icon">
2554 + <span class="dashicons dashicons-trash"></span>
2555 + </button>
2556 + </form>
2557 + </td>
2779 2558 </tr>
2780 - <?php endif; ?>
2781 - </tbody>
2559 + <?php endforeach;
2560 + else : ?>
2561 + <tr>
2562 + <td colspan="5" class="mxchat-no-records">
2563 + <?php esc_html_e('No intents found.', 'mxchat'); ?>
2564 + </td>
2565 + </tr>
2566 + <?php endif; ?>
2567 + </tbody>
2782 2568 </table>
2783 2569 </div>
2784 2570
2785 2571 <?php if ($total_pages > 1) : ?>
@@ -2805,26 +2591,26 @@
2805 2591 <span class="mxchat-modal-close">&times;</span>
2806 2592 <div class="mxchat-card-header">
2807 2593 <h2><?php esc_html_e('Edit Intent Phrases', 'mxchat'); ?></h2>
2808 2594 </div>
2809 -
2810 - <form id="mxchat-edit-intent-form" method="post"
2595 +
2596 + <form id="mxchat-edit-intent-form" method="post"
2811 2597 action="<?php echo esc_url(admin_url('admin-post.php')); ?>">
2812 2598 <?php wp_nonce_field('mxchat_edit_intent_nonce'); ?>
2813 2599 <input type="hidden" name="action" value="mxchat_edit_intent">
2814 2600 <input type="hidden" name="intent_id" id="edit_intent_id">
2815 -
2601 +
2816 2602 <div class="mxchat-form-group">
2817 2603 <label for="edit_phrases">
2818 2604 <?php esc_html_e('Phrases (comma-separated)', 'mxchat'); ?>
2819 2605 </label>
2820 - <textarea name="phrases"
2821 - id="edit_phrases"
2822 - rows="5"
2823 - class="mxchat-intent-textarea"
2606 + <textarea name="phrases"
2607 + id="edit_phrases"
2608 + rows="5"
2609 + class="mxchat-intent-textarea"
2824 2610 required></textarea>
2825 2611 </div>
2826 -
2612 +
2827 2613 <div class="mxchat-modal-actions">
2828 2614 <button type="submit" class="mxchat-button-primary">
2829 2615 <?php esc_html_e('Update Phrases', 'mxchat'); ?>
2830 2616 </button>
@@ -3632,11 +3418,162 @@
3632 3418 'mxchat-embed',
3633 3419 'mxchat_live_agent_section'
3634 3420 );
3635 3421
3422 + // Theme Settings Section
3423 + add_settings_section(
3424 + 'mxchat_theme_section',
3425 + esc_html__('Theme Settings', 'mxchat'),
3426 + null,
3427 + 'mxchat-theme'
3428 + );
3636 3429
3430 + add_settings_field(
3431 + 'close_button_color',
3432 + esc_html__('Close Button & Title Color', 'mxchat'),
3433 + array($this, 'mxchat_close_button_color_callback'),
3434 + 'mxchat-theme',
3435 + 'mxchat_theme_section'
3436 + );
3637 3437
3438 + add_settings_field(
3439 + 'chatbot_bg_color',
3440 + esc_html__('Chatbot Background Color', 'mxchat'),
3441 + array($this, 'mxchat_chatbot_bg_color_callback'),
3442 + 'mxchat-theme',
3443 + 'mxchat_theme_section'
3444 + );
3638 3445
3446 + add_settings_field(
3447 + 'user_message_bg_color',
3448 + esc_html__('User Message Background Color', 'mxchat'),
3449 + array($this, 'mxchat_user_message_bg_color_callback'),
3450 + 'mxchat-theme',
3451 + 'mxchat_theme_section'
3452 + );
3453 +
3454 + add_settings_field(
3455 + 'user_message_font_color',
3456 + esc_html__('User Message Font Color', 'mxchat'),
3457 + array($this, 'mxchat_user_message_font_color_callback'),
3458 + 'mxchat-theme',
3459 + 'mxchat_theme_section'
3460 + );
3461 +
3462 + add_settings_field(
3463 + 'bot_message_bg_color',
3464 + esc_html__('Bot Message Background Color', 'mxchat'),
3465 + array($this, 'mxchat_bot_message_bg_color_callback'),
3466 + 'mxchat-theme',
3467 + 'mxchat_theme_section'
3468 + );
3469 +
3470 + add_settings_field(
3471 + 'bot_message_font_color',
3472 + esc_html__('Bot Message Font Color', 'mxchat'),
3473 + array($this, 'mxchat_bot_message_font_color_callback'),
3474 + 'mxchat-theme',
3475 + 'mxchat_theme_section'
3476 + );
3477 +
3478 + add_settings_field(
3479 + 'top_bar_bg_color',
3480 + esc_html__('Top Bar Background Color', 'mxchat'),
3481 + array($this, 'mxchat_top_bar_bg_color_callback'),
3482 + 'mxchat-theme',
3483 + 'mxchat_theme_section'
3484 + );
3485 +
3486 + add_settings_field(
3487 + 'send_button_font_color',
3488 + esc_html__('Send Button Color', 'mxchat'),
3489 + array($this, 'mxchat_send_button_font_color_callback'),
3490 + 'mxchat-theme',
3491 + 'mxchat_theme_section'
3492 + );
3493 +
3494 + add_settings_field(
3495 + 'chat_input_font_color',
3496 + esc_html__('Chat Input Font Color', 'mxchat'),
3497 + array($this, 'mxchat_chat_input_font_color_callback'),
3498 + 'mxchat-theme',
3499 + 'mxchat_theme_section'
3500 + );
3501 +
3502 + add_settings_field(
3503 + 'chatbot_background_color',
3504 + esc_html__('Floating Widget Background Color', 'mxchat'),
3505 + array($this, 'mxchat_chatbot_background_color_callback'),
3506 + 'mxchat-theme',
3507 + 'mxchat_theme_section'
3508 + );
3509 +
3510 + add_settings_field(
3511 + 'icon_color',
3512 + esc_html__('Chatbot Icon Color', 'mxchat'),
3513 + array($this, 'mxchat_icon_color_callback'),
3514 + 'mxchat-theme',
3515 + 'mxchat_theme_section'
3516 + );
3517 +
3518 + add_settings_field(
3519 + 'custom_icon',
3520 + esc_html__('Custom Chatbot Icon (PNG)', 'mxchat'),
3521 + array($this, 'mxchat_custom_icon_callback'),
3522 + 'mxchat-theme',
3523 + 'mxchat_theme_section'
3524 + );
3525 +
3526 + add_settings_field(
3527 + 'title_icon',
3528 + esc_html__('Title Bar Icon (PNG)', 'mxchat'),
3529 + array($this, 'mxchat_title_icon_callback'),
3530 + 'mxchat-theme',
3531 + 'mxchat_theme_section'
3532 + );
3533 +
3534 + add_settings_field(
3535 + 'live_agent_message_bg_color',
3536 + esc_html__('Live Agent Background Color', 'mxchat'),
3537 + array($this, 'mxchat_live_agent_message_bg_color_callback'),
3538 + 'mxchat-theme',
3539 + 'mxchat_theme_section'
3540 + );
3541 +
3542 + add_settings_field(
3543 + 'live_agent_message_font_color',
3544 + esc_html__('Live Agent Font Color', 'mxchat'),
3545 + array($this, 'mxchat_live_agent_message_font_color_callback'),
3546 + 'mxchat-theme',
3547 + 'mxchat_theme_section'
3548 + );
3549 +
3550 + // Mode Indicator Background Color
3551 + add_settings_field(
3552 + 'mode_indicator_bg_color',
3553 + esc_html__('Mode Indicator Background Color', 'mxchat'),
3554 + array($this, 'mxchat_mode_indicator_bg_color_callback'),
3555 + 'mxchat-theme',
3556 + 'mxchat_theme_section'
3557 + );
3558 +
3559 + // Mode Indicator Font Color
3560 + add_settings_field(
3561 + 'mode_indicator_font_color',
3562 + esc_html__('Mode Indicator Font Color', 'mxchat'),
3563 + array($this, 'mxchat_mode_indicator_font_color_callback'),
3564 + 'mxchat-theme',
3565 + 'mxchat_theme_section'
3566 + );
3567 +
3568 + add_settings_field(
3569 + 'toolbar_icon_color',
3570 + esc_html__('Toolbar Icon Color', 'mxchat'),
3571 + array($this, 'mxchat_toolbar_icon_color_callback'),
3572 + 'mxchat-theme',
3573 + 'mxchat_theme_section'
3574 + );
3575 +
3639 3576 // General Settings Section
3640 3577 add_settings_section(
3641 3578 'mxchat_general_section',
3642 3579 esc_html__('Frequently Asked Questions (FAQ)', 'mxchat'),
@@ -3671,9 +3608,9 @@
3671 3608 }
3672 3609
3673 3610 /**
3674 3611 * Sanitize all prompts options
3675 - *
3612 + *
3676 3613 * @param array $input The unsanitized options array
3677 3614 * @return array The sanitized options array
3678 3615 */
3679 3616 public function sanitize_prompts_options($input) {
@@ -3678,16 +3615,16 @@
3678 3615 */
3679 3616 public function sanitize_prompts_options($input) {
3680 3617 // Log the incoming input.
3681 3618 //error_log('Sanitizing inputs: ' . print_r($input, true));
3682 -
3619 +
3683 3620 $sanitized = array();
3684 -
3621 +
3685 3622 // Boolean options
3686 3623 $sanitized['mxchat_auto_sync_posts'] = isset($input['mxchat_auto_sync_posts']) ? 1 : 0;
3687 3624 $sanitized['mxchat_auto_sync_pages'] = isset($input['mxchat_auto_sync_pages']) ? 1 : 0;
3688 3625 $sanitized['mxchat_use_pinecone'] = !empty($input['mxchat_use_pinecone']) ? 1 : 0;
3689 -
3626 +
3690 3627 // API Key: if less than 32 characters, flag as invalid.
3691 3628 $api_key = sanitize_text_field($input['mxchat_pinecone_api_key'] ?? '');
3692 3629 if (!empty($api_key) && strlen($api_key) < 32) {
3693 3630 add_settings_error(
@@ -3699,13 +3636,13 @@
3699 3636 $sanitized['mxchat_pinecone_api_key'] = $existing_options['mxchat_pinecone_api_key'] ?? '';
3700 3637 } else {
3701 3638 $sanitized['mxchat_pinecone_api_key'] = $api_key;
3702 3639 }
3703 -
3640 +
3704 3641 // Environment and Index Name
3705 3642 $sanitized['mxchat_pinecone_environment'] = sanitize_text_field($input['mxchat_pinecone_environment'] ?? '');
3706 3643 $sanitized['mxchat_pinecone_index'] = sanitize_text_field($input['mxchat_pinecone_index'] ?? '');
3707 -
3644 +
3708 3645 // Host: Remove protocol and validate format.
3709 3646 $host = sanitize_text_field($input['mxchat_pinecone_host'] ?? '');
3710 3647 $host = preg_replace('#^https?://#', '', $host);
3711 3648 //error_log('Host after removing protocol: ' . $host);
@@ -3723,11 +3660,11 @@
3723 3660 }
3724 3661 } else {
3725 3662 $sanitized['mxchat_pinecone_host'] = '';
3726 3663 }
3727 -
3664 +
3728 3665 //error_log('Final sanitized array: ' . print_r($sanitized, true));
3729 -
3666 +
3730 3667 return $sanitized;
3731 3668 }
3732 3669
3733 3670
@@ -3975,15 +3912,15 @@
3975 3912 echo '</div>';
3976 3913 }
3977 3914 public function claude_api_key_callback() {
3978 3915 // Check if the feature is activated (paid feature)
3979 - $disabled = $this->is_activated ? '' : 'disabled';
3980 - $class = $this->is_activated ? 'pro-feature-wrapper active' : 'pro-feature-wrapper inactive';
3981 -
3982 - // Retrieve the Claude API key value directly like the others
3916 + $disabled = $this->is_activated ? '' : 'disabled'; // Disable input if not activated
3917 + $class = $this->is_activated ? 'pro-feature-wrapper active' : 'pro-feature-wrapper inactive'; // CSS class to style the wrapper based on activation status
3918 +
3919 + // Retrieve the Claude API key value
3983 3920 $claudeApiKey = isset($this->options['claude_api_key']) ? esc_attr($this->options['claude_api_key']) : '';
3984 -
3985 - // Use direct name field like the other working API keys
3921 +
3922 + // Render the input field for the Claude API key
3986 3923 echo '<div class="' . esc_attr($class) . '">';
3987 3924 printf(
3988 3925 '<input type="password" id="claude_api_key" name="claude_api_key" value="%s" class="regular-text" %s />',
3989 3926 $claudeApiKey,
@@ -3989,14 +3926,16 @@
3989 3926 $claudeApiKey,
3990 3927 $disabled
3991 3928 );
3992 3929 echo '<button type="button" id="toggleClaudeApiKeyVisibility">' . esc_html__('Show', 'mxchat') . '</button>';
3993 -
3930 +
3931 + // If the feature is not activated, show the overlay with a "Pro Only" message
3994 3932 if (!$this->is_activated) {
3995 3933 echo '<div class="pro-feature-overlay">';
3996 3934 echo '<a href="https://mxchat.ai/" target="_blank"><img src="' . plugin_dir_url(__FILE__) . '../images/pro-only-dark.png" alt="' . esc_attr__('Pro Only', 'mxchat') . '" /></a>';
3997 3935 echo '</div>';
3998 3936 }
3937 +
3999 3938 echo '</div>';
4000 3939 }
4001 3940 public function deepseek_api_key_callback() {
4002 3941 // Retrieve from your stored 'deepseek_api_key' in the mxchat_options array
@@ -4359,8 +4298,91 @@
4359 4298 }
4360 4299
4361 4300
4362 4301
4302 +
4303 +
4304 +public function mxchat_close_button_color_callback() {
4305 + $disabled = $this->is_activated ? '' : 'disabled';
4306 + $class = $this->is_activated ? 'pro-feature-wrapper active' : 'pro-feature-wrapper inactive';
4307 +
4308 + echo '<div class="' . esc_attr($class) . '">';
4309 + echo sprintf(
4310 + '<input type="text"
4311 + id="close_button_color"
4312 + name="close_button_color"
4313 + value="%s"
4314 + class="my-color-field"
4315 + data-default-color="#4a4a4a"
4316 + %s />',
4317 + isset($this->options['close_button_color']) ? esc_attr($this->options['close_button_color']) : '#4a4a4a',
4318 + esc_attr($disabled)
4319 + );
4320 +
4321 + if (!$this->is_activated) {
4322 + echo '<div class="pro-feature-overlay">';
4323 + echo '<a href="https://mxchat.ai/" target="_blank">';
4324 + echo '<img src="' . esc_url(plugin_dir_url(__FILE__) . '../images/pro-only-dark.png') . '" alt="' . esc_attr__('Pro Only', 'mxchat') . '" />';
4325 + echo '</a>';
4326 + echo '</div>';
4327 + }
4328 + echo '</div>';
4329 +}
4330 +
4331 +public function mxchat_chatbot_bg_color_callback() {
4332 + $disabled = $this->is_activated ? '' : 'disabled';
4333 + $class = $this->is_activated ? 'pro-feature-wrapper active' : 'pro-feature-wrapper inactive';
4334 +
4335 + echo '<div class="' . esc_attr($class) . '">';
4336 + echo sprintf(
4337 + '<input type="text"
4338 + id="chatbot_bg_color"
4339 + name="chatbot_bg_color"
4340 + value="%s"
4341 + class="my-color-field"
4342 + data-default-color="#f9f9f9"
4343 + %s />',
4344 + isset($this->options['chatbot_bg_color']) ? esc_attr($this->options['chatbot_bg_color']) : '#f9f9f9',
4345 + esc_attr($disabled)
4346 + );
4347 +
4348 + if (!$this->is_activated) {
4349 + echo '<div class="pro-feature-overlay">';
4350 + echo '<a href="https://mxchat.ai/" target="_blank">';
4351 + echo '<img src="' . esc_url(plugin_dir_url(__FILE__) . '../images/pro-only-dark.png') . '" alt="' . esc_attr__('Pro Only', 'mxchat') . '" />';
4352 + echo '</a>';
4353 + echo '</div>';
4354 + }
4355 + echo '</div>';
4356 +}
4357 +
4358 +public function mxchat_user_message_bg_color_callback() {
4359 + $disabled = $this->is_activated ? '' : 'disabled';
4360 + $class = $this->is_activated ? 'pro-feature-wrapper active' : 'pro-feature-wrapper inactive';
4361 +
4362 + echo '<div class="' . esc_attr($class) . '">';
4363 + echo sprintf(
4364 + '<input type="text"
4365 + id="user_message_bg_color"
4366 + name="user_message_bg_color"
4367 + value="%s"
4368 + class="my-color-field"
4369 + data-default-color="#0078d7"
4370 + %s />',
4371 + isset($this->options['user_message_bg_color']) ? esc_attr($this->options['user_message_bg_color']) : '#0078d7',
4372 + esc_attr($disabled)
4373 + );
4374 +
4375 + if (!$this->is_activated) {
4376 + echo '<div class="pro-feature-overlay">';
4377 + echo '<a href="https://mxchat.ai/" target="_blank">';
4378 + echo '<img src="' . esc_url(plugin_dir_url(__FILE__) . '../images/pro-only-dark.png') . '" alt="' . esc_attr__('Pro Only', 'mxchat') . '" />';
4379 + echo '</a>';
4380 + echo '</div>';
4381 + }
4382 + echo '</div>';
4383 +}
4384 +
4363 4385 public function mxchat_user_message_font_color_callback() {
4364 4386 $disabled = $this->is_activated ? '' : 'disabled';
4365 4387 $class = $this->is_activated ? 'pro-feature-wrapper active' : 'pro-feature-wrapper inactive';
4366 4388
@@ -4847,20 +4869,39 @@
4847 4869 // Get complianz toggle value with fallback
4848 4870 $complianz_toggle = isset($options['complianz_toggle']) ? $options['complianz_toggle'] : 'off';
4849 4871 $checked = ($complianz_toggle === 'on') ? 'checked' : '';
4850 4872
4873 + // Check if the plugin is activated (paid feature)
4874 + $disabled = $this->is_activated ? '' : 'disabled';
4875 + $class = $this->is_activated ? 'pro-feature-wrapper active' : 'pro-feature-wrapper inactive';
4876 +
4877 + echo '<div class="' . esc_attr($class) . '">';
4878 +
4851 4879 // Output the toggle switch
4852 4880 echo '<label class="toggle-switch">';
4853 4881 echo sprintf(
4854 - '<input type="checkbox" id="complianz_toggle" name="complianz_toggle" value="on" %s />',
4855 - esc_attr($checked)
4882 + '<input type="checkbox" id="complianz_toggle" name="complianz_toggle" value="on" %s %s />',
4883 + esc_attr($checked),
4884 + esc_attr($disabled)
4856 4885 );
4857 4886 echo '<span class="slider"></span>';
4858 4887 echo '</label>';
4859 4888
4860 4889 echo '<p class="description">' . esc_html__('Enable this option to apply Complianz consent logic to the chatbot (must have Complianz Plugin).', 'mxchat') . '</p>';
4890 +
4891 + // If the feature is not activated, show the Pro feature overlay
4892 + if (!$this->is_activated) {
4893 + echo '<div class="pro-feature-overlay">';
4894 + echo '<a href="https://mxchat.ai/" target="_blank">';
4895 + echo '<img src="' . esc_url(plugin_dir_url(__FILE__) . '../images/pro-only-dark.png') . '" alt="' . esc_attr__('Pro Only', 'mxchat') . '" />';
4896 + echo '</a>';
4897 + echo '</div>';
4898 + }
4899 +
4900 + echo '</div>';
4861 4901 }
4862 4902
4903 +
4863 4904 public function mxchat_link_target_toggle_callback() {
4864 4905 // Load from mxchat_options array
4865 4906 $options = get_option('mxchat_options', []);
4866 4907
@@ -4886,20 +4927,39 @@
4886 4927 // Get chat persistence toggle value with fallback
4887 4928 $chat_persistence_toggle = isset($options['chat_persistence_toggle']) ? $options['chat_persistence_toggle'] : 'off';
4888 4929 $checked = ($chat_persistence_toggle === 'on') ? 'checked' : '';
4889 4930
4931 + // Check if the plugin is activated (paid feature)
4932 + $disabled = $this->is_activated ? '' : 'disabled';
4933 + $class = $this->is_activated ? 'pro-feature-wrapper active' : 'pro-feature-wrapper inactive';
4934 +
4935 + echo '<div class="' . esc_attr($class) . '">';
4936 +
4890 4937 // Output the toggle switch
4891 4938 echo '<label class="toggle-switch">';
4892 4939 echo sprintf(
4893 - '<input type="checkbox" id="chat_persistence_toggle" name="chat_persistence_toggle" value="on" %s />',
4894 - esc_attr($checked)
4940 + '<input type="checkbox" id="chat_persistence_toggle" name="chat_persistence_toggle" value="on" %s %s />',
4941 + esc_attr($checked),
4942 + esc_attr($disabled)
4895 4943 );
4896 4944 echo '<span class="slider"></span>';
4897 4945 echo '</label>';
4898 4946
4899 4947 echo '<p class="description">' . esc_html__('Enable to keep chat history when users navigate tabs or return to the site within 24 hours.', 'mxchat') . '</p>';
4948 +
4949 + // If not activated, show Pro feature overlay
4950 + if (!$this->is_activated) {
4951 + echo '<div class="pro-feature-overlay">';
4952 + echo '<a href="https://mxchat.ai/" target="_blank">';
4953 + echo '<img src="' . esc_url(plugin_dir_url(__FILE__) . '../images/pro-only-dark.png') . '" alt="' . esc_attr__('Pro Only', 'mxchat') . '" />';
4954 + echo '</a>';
4955 + echo '</div>';
4956 + }
4957 +
4958 + echo '</div>';
4900 4959 }
4901 4960
4961 +
4902 4962 public function mxchat_popular_question_1_callback() {
4903 4963 // Load the full plugin options array
4904 4964 $all_options = get_option('mxchat_options', []);
4905 4965
@@ -4924,38 +4984,72 @@
4924 4984
4925 4985 // Retrieve the specific option for popular_question_2
4926 4986 $popular_question_2 = isset($all_options['popular_question_2']) ? $all_options['popular_question_2'] : '';
4927 4987
4988 + // Check if the plugin is activated (paid feature)
4989 + $disabled = $this->is_activated ? '' : 'disabled';
4990 + $class = $this->is_activated ? 'pro-feature-wrapper active' : 'pro-feature-wrapper inactive';
4991 +
4992 + echo '<div class="' . esc_attr($class) . '">';
4993 +
4928 4994 // Render the input field
4929 4995 printf(
4930 - '<input type="text" id="popular_question_2" name="popular_question_2" value="%s" placeholder="%s" class="regular-text" />',
4996 + '<input type="text" id="popular_question_2" name="popular_question_2" value="%s" placeholder="%s" class="regular-text" %s />',
4931 4997 esc_attr($popular_question_2),
4932 - esc_attr__('Enter Popular Question 2', 'mxchat')
4998 + esc_attr__('Enter Popular Question 2', 'mxchat'),
4999 + esc_attr($disabled)
4933 5000 );
4934 5001
4935 5002 // Add a description for the field
4936 5003 echo '<p class="description">' . esc_html__('This will be the second popular question in the chatbot.', 'mxchat') . '</p>';
5004 +
5005 + // If not activated, show Pro feature overlay
5006 + if (!$this->is_activated) {
5007 + echo '<div class="pro-feature-overlay">';
5008 + echo '<a href="https://mxchat.ai/" target="_blank"><img src="' . plugin_dir_url(__FILE__) . '../images/pro-only-dark.png" alt="' . esc_attr__('Pro Only', 'mxchat') . '" /></a>';
5009 + echo '</div>';
5010 + }
5011 +
5012 + echo '</div>';
4937 5013 }
4938 5014
4939 5015
5016 +
4940 5017 public function mxchat_popular_question_3_callback() {
4941 - // Load the full plugin options array
4942 - $all_options = get_option('mxchat_options', []);
5018 + // Load the full plugin options array
5019 + $all_options = get_option('mxchat_options', []);
4943 5020
4944 - // Retrieve the specific option for popular_question_3
4945 - $popular_question_3 = isset($all_options['popular_question_3']) ? $all_options['popular_question_3'] : '';
5021 + // Retrieve the specific option for popular_question_3
5022 + $popular_question_3 = isset($all_options['popular_question_3']) ? $all_options['popular_question_3'] : '';
4946 5023
4947 - // Render the input field
4948 - printf(
4949 - '<input type="text" id="popular_question_3" name="popular_question_3" value="%s" placeholder="%s" class="regular-text" />',
4950 - esc_attr($popular_question_3),
4951 - esc_attr(__('Enter Popular Question 3', 'mxchat'))
4952 - );
5024 + // Check if the plugin is activated (paid feature)
5025 + $disabled = $this->is_activated ? '' : 'disabled';
5026 + $class = $this->is_activated ? 'pro-feature-wrapper active' : 'pro-feature-wrapper inactive';
4953 5027
4954 - // Add a description for the field
4955 - echo '<p class="description">' . esc_html__('This will be the third popular question in the chatbot.', 'mxchat') . '</p>';
5028 + echo '<div class="' . esc_attr($class) . '">';
5029 +
5030 + // Render the input field
5031 + printf(
5032 + '<input type="text" id="popular_question_3" name="popular_question_3" value="%s" placeholder="%s" class="regular-text" %s />',
5033 + esc_attr($popular_question_3),
5034 + esc_attr(__('Enter Popular Question 3', 'mxchat')),
5035 + esc_attr($disabled)
5036 + );
5037 +
5038 + // Add a description for the field
5039 + echo '<p class="description">' . esc_html__('This will be the third popular question in the chatbot.', 'mxchat') . '</p>';
5040 +
5041 + // If not activated, show Pro feature overlay
5042 + if (!$this->is_activated) {
5043 + echo '<div class="pro-feature-overlay">';
5044 + echo '<a href="https://mxchat.ai/" target="_blank"><img src="' . plugin_dir_url(__FILE__) . '../images/pro-only-dark.png" alt="' . esc_attr__('Pro Only', 'mxchat') . '" /></a>';
5045 + echo '</div>';
5046 + }
5047 +
5048 + echo '</div>';
4956 5049 }
4957 5050
5051 +
4958 5052 public function mxchat_additional_popular_questions_callback() {
4959 5053 $options = get_option('mxchat_options', []);
4960 5054 $additional_questions = isset($options['additional_popular_questions'])
4961 5055 ? $options['additional_popular_questions']
@@ -5440,9 +5534,9 @@
5440 5534 public function mxchat_enqueue_admin_assets() {
5441 5535 wp_enqueue_style('wp-color-picker');
5442 5536
5443 5537 // Get the plugin version or file modification time for cache busting
5444 - $plugin_version = '2.0.3'; // Replace this with your plugin's version
5538 + $plugin_version = '2.0.0'; // Replace this with your plugin's version
5445 5539
5446 5540 // File paths
5447 5541 $color_picker_js_path = plugin_dir_path(__FILE__) . '../js/my-color-picker.js';
5448 5542 $embedding_check_js_path = plugin_dir_path(__FILE__) . '../js/embedding-check.js';
@@ -5497,9 +5591,9 @@
5497 5591 'license_nonce' => wp_create_nonce('mxchat_activate_license_nonce'),
5498 5592 'inline_edit_nonce' => wp_create_nonce('mxchat_save_inline_nonce'),
5499 5593 'setting_nonce' => wp_create_nonce('mxchat_save_setting_nonce'),
5500 5594 ));
5501 -
5595 +
5502 5596 // Enqueue the admin CSS
5503 5597 wp_enqueue_style(
5504 5598 'mxchat-admin-css',
5505 5599 plugin_dir_url(__FILE__) . '../css/admin-style.css',
@@ -5505,9 +5599,9 @@
5505 5599 plugin_dir_url(__FILE__) . '../css/admin-style.css',
5506 5600 array(),
5507 5601 $admin_css_version
5508 5602 );
5509 -
5603 +
5510 5604 wp_enqueue_style(
5511 5605 'mxchat-knowledge-css',
5512 5606 plugin_dir_url(__FILE__) . '../css/knowledge-style.css',
5513 5607 array(),
@@ -5512,10 +5606,10 @@
5512 5606 plugin_dir_url(__FILE__) . '../css/knowledge-style.css',
5513 5607 array(),
5514 5608 $knowledge_css_version
5515 5609 );
5516 -
5517 -
5610 +
5611 +
5518 5612 wp_enqueue_style(
5519 5613 'mxchat-intent-css',
5520 5614 plugin_dir_url(__FILE__) . '../css/intent-style.css',
5521 5615 array(),
@@ -5520,9 +5614,9 @@
5520 5614 plugin_dir_url(__FILE__) . '../css/intent-style.css',
5521 5615 array(),
5522 5616 $intent_css_version
5523 5617 );
5524 -
5618 +
5525 5619 // IMPORTANT: Use the same script handle as above for localizing mxchatPromptsAdmin
5526 5620 wp_localize_script( 'mxchat-admin-js', 'mxchatPromptsAdmin', array(
5527 5621 'ajax_url' => admin_url( 'admin-ajax.php' ),
5528 5622 'prompts_setting_nonce' => wp_create_nonce( 'mxchat_prompts_setting_nonce' ),
@@ -5700,8 +5794,9 @@
5700 5794 $new_input['model'] = sanitize_text_field($input['model']);
5701 5795 }
5702 5796 }
5703 5797
5798 + // Sanitize new pro features
5704 5799 if (isset($input['close_button_color'])) {
5705 5800 $new_input['close_button_color'] = sanitize_hex_color($input['close_button_color']);
5706 5801 }
5707 5802
@@ -5913,9 +6008,9 @@
5913 6008
5914 6009
5915 6010 private static function mxchat_extract_main_content($html) {
5916 6011 if (empty($html)) {
5917 - //error_log('mxchat_extract_main_content: Empty HTML content received');
6012 + error_log('mxchat_extract_main_content: Empty HTML content received');
5918 6013 return '';
5919 6014 }
5920 6015
5921 6016 try {
@@ -5920,14 +6015,14 @@
5920 6015
5921 6016 try {
5922 6017 $dom = new DOMDocument;
5923 6018 libxml_use_internal_errors(true); // Suppress HTML parsing errors
5924 -
6019 +
5925 6020 // Simple load of HTML, with @ to suppress warnings
5926 6021 @$dom->loadHTML($html, LIBXML_HTML_NOIMPLIED | LIBXML_HTML_NODEFDTD);
5927 -
6022 +
5928 6023 $xpath = new DOMXPath($dom);
5929 -
6024 +
5930 6025 // Simplified selectors focusing on common content areas
5931 6026 $selectors = [
5932 6027 '//article',
5933 6028 '//*[@id="content"]',
@@ -5933,9 +6028,9 @@
5933 6028 '//*[@id="content"]',
5934 6029 '//*[@class="entry-content"]',
5935 6030 '//main'
5936 6031 ];
5937 -
6032 +
5938 6033 foreach ($selectors as $selector) {
5939 6034 $nodes = $xpath->query($selector);
5940 6035 if ($nodes && $nodes->length > 0) {
5941 6036 $content = '';
@@ -5946,20 +6041,20 @@
5946 6041 return $content;
5947 6042 }
5948 6043 }
5949 6044 }
5950 -
6045 +
5951 6046 // Fallback: Return the entire body content if no specific selector matches
5952 6047 $body = $dom->getElementsByTagName('body');
5953 6048 if ($body->length > 0) {
5954 6049 return $dom->saveHTML($body->item(0));
5955 6050 }
5956 -
6051 +
5957 6052 // Last resort: return the original HTML
5958 6053 return $html;
5959 -
6054 +
5960 6055 } catch (Exception $e) {
5961 - //error_log('mxchat_extract_main_content error: ' . $e->getMessage());
6056 + error_log('mxchat_extract_main_content error: ' . $e->getMessage());
5962 6057 return $html; // Return original HTML if parsing fails
5963 6058 } finally {
5964 6059 libxml_clear_errors();
5965 6060 }