PluginProbe
MxChat – AI Chatbot & Content Generation for WordPress / 3.1.5
MxChat – AI Chatbot & Content Generation for WordPress v3.1.5
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 | mxchat-basic.php +10 -340 3.2.123.1.5 View file →
@@ -2,9 +2,9 @@
2 2 /**
3 3 * Plugin Name: MxChat
4 4 * Plugin URI: https://mxchat.ai/
5 5 * Description: AI chatbot for WordPress with OpenAI, Claude, xAI, DeepSeek, live agent, PDF uploads, WooCommerce, and training on website data.
6 - * Version: 3.2.12
6 + * Version: 3.1.5
7 7 * Author: MxChat
8 8 * Author URI: https://mxchat.ai
9 9 * License: GPLv2 or later
10 10 * License URI: https://www.gnu.org/licenses/gpl-2.0.html
@@ -46,84 +46,8 @@
46 46 }
47 47 add_action('init', 'mxchat_load_textdomain');
48 48
49 49 /**
50 - * One-time migration: gemini-3-pro-preview was shut down by Google on March 9, 2026.
51 - * Existing installs with the dead ID get auto-remapped to gemini-3.1-pro-preview
52 - * (Google's official migration target) the first time admin_init fires after update.
53 - */
54 -add_action('admin_init', function () {
55 - if (get_option('mxchat_gemini_3_remap_done')) {
56 - return;
57 - }
58 - $opts = get_option('mxchat_options');
59 - if (is_array($opts) && isset($opts['model']) && $opts['model'] === 'gemini-3-pro-preview') {
60 - $opts['model'] = 'gemini-3.1-pro-preview';
61 - update_option('mxchat_options', $opts);
62 - }
63 - if (is_array($opts) && isset($opts['content_model']) && $opts['content_model'] === 'gemini-3-pro-preview') {
64 - $opts['content_model'] = 'gemini-3.1-pro-preview';
65 - update_option('mxchat_options', $opts);
66 - }
67 - update_option('mxchat_gemini_3_remap_done', 1);
68 -});
69 -
70 -/**
71 - * One-time migration: the Grok 2 family was retired by xAI (grok-2, grok-2-1212,
72 - * grok-2-latest, grok-2-vision-1212 all return 400 "Model not found"). Existing
73 - * installs with the dead ID get auto-remapped to grok-4-1-fast-non-reasoning
74 - * (modern, fast, broadly available) the first time admin_init fires after update.
75 - */
76 -add_action('admin_init', function () {
77 - if (get_option('mxchat_grok_2_remap_done')) {
78 - return;
79 - }
80 - $opts = get_option('mxchat_options');
81 - if (is_array($opts) && isset($opts['model']) && $opts['model'] === 'grok-2') {
82 - $opts['model'] = 'grok-4-1-fast-non-reasoning';
83 - update_option('mxchat_options', $opts);
84 - }
85 - if (is_array($opts) && isset($opts['content_model']) && $opts['content_model'] === 'grok-2') {
86 - $opts['content_model'] = 'grok-4-1-fast-non-reasoning';
87 - update_option('mxchat_options', $opts);
88 - }
89 - update_option('mxchat_grok_2_remap_done', 1);
90 -});
91 -
92 -/**
93 - * One-time migration: Anthropic retired the Claude 4 (2025-05-14) snapshots on
94 - * June 15, 2026 — claude-opus-4-20250514 and claude-sonnet-4-20250514 now return
95 - * an API error. Existing installs with a dead ID get auto-remapped to the current
96 - * equivalents Anthropic recommends (Opus 4.8 / Sonnet 4.6) the first time admin_init
97 - * fires after update. Mirrors the gemini-3-pro-preview / grok-2 rescues above.
98 - */
99 -add_action('admin_init', function () {
100 - if (get_option('mxchat_claude_4_retire_remap_done')) {
101 - return;
102 - }
103 - $map = array(
104 - 'claude-opus-4-20250514' => 'claude-opus-4-8',
105 - 'claude-sonnet-4-20250514' => 'claude-sonnet-4-6',
106 - );
107 - $opts = get_option('mxchat_options');
108 - if (is_array($opts)) {
109 - $changed = false;
110 - if (isset($opts['model']) && isset($map[$opts['model']])) {
111 - $opts['model'] = $map[$opts['model']];
112 - $changed = true;
113 - }
114 - if (isset($opts['content_model']) && isset($map[$opts['content_model']])) {
115 - $opts['content_model'] = $map[$opts['content_model']];
116 - $changed = true;
117 - }
118 - if ($changed) {
119 - update_option('mxchat_options', $opts);
120 - }
121 - }
122 - update_option('mxchat_claude_4_retire_remap_done', 1);
123 -});
124 -
125 -/**
126 50 * Exclude MxChat assets from caching plugin optimizations
127 51 *
128 52 * This prevents issues with WP Rocket, LiteSpeed Cache, Autoptimize, WP Super Cache,
129 53 * W3 Total Cache, SG Optimizer, and similar plugins that may break the chatbot by
@@ -326,66 +250,11 @@
326 250 $rejected[] = 'wp-admin/admin-ajax.php';
327 251 return $rejected;
328 252 });
329 253
330 -// ── Page-cache bypass for chat AJAX (companion to the 3.2.6 nonce-race hotfix)
331 -// Each cache plugin gets its own filter export so that visitors hitting an
332 -// edge-cached page never receive cached chat-AJAX responses. The chat send /
333 -// stream send / file upload all POST to /wp-admin/admin-ajax.php with
334 -// `action=mxchat_*`. Without these exports, a cache plugin can stale a response
335 -// and break the per-session nonce flow on the first message.
336 -
337 -// WP Rocket — `rocket_cache_reject_uri` takes a flat array of regex strings.
338 -add_filter('rocket_cache_reject_uri', function($uris) {
339 - if (!is_array($uris)) $uris = array();
340 - $uris[] = '/wp-admin/admin-ajax\.php\?action=mxchat_.*';
341 - return $uris;
342 -});
343 -
344 -// LiteSpeed Cache — `litespeed_cache_no_cache_for_request` short-circuits
345 -// caching when the request matches our chat-AJAX pattern.
346 -add_filter('litespeed_cache_no_cache_for_request', function($no_cache) {
347 - if ($no_cache) return $no_cache;
348 - if (!empty($_SERVER['REQUEST_URI']) &&
349 - strpos($_SERVER['REQUEST_URI'], '/wp-admin/admin-ajax.php') !== false &&
350 - !empty($_REQUEST['action']) &&
351 - strpos((string) $_REQUEST['action'], 'mxchat_') === 0) {
352 - return true;
353 - }
354 - return $no_cache;
355 -});
356 -
357 -// W3 Total Cache — `w3tc_pgcache_request_skip_uri` flips page-cache off when
358 -// the URI matches.
359 -add_filter('w3tc_pgcache_request_skip_uri', function($skip) {
360 - if ($skip) return $skip;
361 - if (!empty($_SERVER['REQUEST_URI']) &&
362 - strpos($_SERVER['REQUEST_URI'], '/wp-admin/admin-ajax.php') !== false &&
363 - !empty($_REQUEST['action']) &&
364 - strpos((string) $_REQUEST['action'], 'mxchat_') === 0) {
365 - return true;
366 - }
367 - return $skip;
368 -});
369 -
370 -// FlyingPress — `flying_press_cacheable` takes a boolean and is run per
371 -// request. Same pattern as LiteSpeed / W3TC.
372 -add_filter('flying_press_cacheable', function($cacheable) {
373 - if (!$cacheable) return $cacheable;
374 - if (!empty($_SERVER['REQUEST_URI']) &&
375 - strpos($_SERVER['REQUEST_URI'], '/wp-admin/admin-ajax.php') !== false &&
376 - !empty($_REQUEST['action']) &&
377 - strpos((string) $_REQUEST['action'], 'mxchat_') === 0) {
378 - return false;
379 - }
380 - return $cacheable;
381 -});
382 -
383 254 // Include classes with error handling
384 255 function mxchat_include_classes() {
385 256 $class_files = array(
386 - 'includes/class-mxchat-model-catalog.php',
387 - 'includes/class-mxchat-tool-registry.php',
388 257 'includes/class-mxchat-integrator.php',
389 258 'includes/class-mxchat-admin.php',
390 259 'includes/class-mxchat-public.php',
391 260 'includes/class-mxchat-utils.php',
@@ -393,10 +262,8 @@
393 262 'includes/class-mxchat-meta-box.php',
394 263 'includes/class-mxchat-chunker.php',
395 264 'includes/class-mxchat-word-handler.php',
396 265 'includes/class-mxchat-content-generator.php',
397 - 'includes/class-mxchat-cache-purge.php',
398 - 'includes/class-rest-api.php',
399 266 'admin/class-ajax-handler.php',
400 267 'admin/class-pinecone-manager.php',
401 268 'admin/class-knowledge-manager.php'
402 269 );
@@ -408,31 +275,8 @@
408 275 } else {
409 276 //error_log('MxChat: Missing class file - ' . $file);
410 277 }
411 278 }
412 -
413 - // Register the native function-calling admin-post save handler (a41dee).
414 - if (class_exists('MxChat_Tool_Registry')) {
415 - MxChat_Tool_Registry::init();
416 - }
417 -
418 - // Admin pages that aren't classes (procedural include).
419 - if (is_admin()) {
420 - $admin_api_page = plugin_dir_path(__FILE__) . 'includes/admin-api-page.php';
421 - if (file_exists($admin_api_page)) {
422 - require_once $admin_api_page;
423 - }
424 - // f7c7d4 renamed this file admin-dashboard-page.php → admin-onboarding-page.php.
425 - // The require MUST live here (admin bootstrap) and not just inside
426 - // mxchat_add_plugin_page() on the admin_menu hook — admin_menu does NOT
427 - // fire on admin-ajax.php requests, so the wizard's AJAX handlers
428 - // (plan-905439: mxchat_onboarding_kb_status / save_step / mark_step /
429 - // auto_graduate + the f7c7d4 dismiss handler) would never register.
430 - $admin_onboarding_page = plugin_dir_path(__FILE__) . 'includes/admin-onboarding-page.php';
431 - if (file_exists($admin_onboarding_page)) {
432 - require_once $admin_onboarding_page;
433 - }
434 - }
435 279 }
436 280
437 281 /**
438 282 * Lazy-load the PDF parser library only when needed.
@@ -764,33 +608,8 @@
764 608 update_option('mxchat_content_type_migration_version', '2.5.6');
765 609 }
766 610
767 611 /**
768 - * 3.2.4: Backfill the active embedding model option for installs that already
769 - * have KB content but no stamped model. The mismatch warning compares this
770 - * against the user's currently selected model — no per-row column needed.
771 - */
772 -function mxchat_backfill_active_embedding_model() {
773 - global $wpdb;
774 -
775 - if (get_option('mxchat_active_embedding_model', '') !== '') {
776 - return;
777 - }
778 -
779 - $kb_table = $wpdb->prefix . 'mxchat_system_prompt_content';
780 - if ($wpdb->get_var("SHOW TABLES LIKE '{$kb_table}'") !== $kb_table) {
781 - return;
782 - }
783 -
784 - $kb_count = (int) $wpdb->get_var("SELECT COUNT(*) FROM {$kb_table}");
785 - if ($kb_count > 0) {
786 - $options = get_option('mxchat_options', array());
787 - $current_model = $options['embedding_model'] ?? 'text-embedding-ada-002';
788 - update_option('mxchat_active_embedding_model', $current_model, false);
789 - }
790 -}
791 -
792 -/**
793 612 * 2.5.2: Create queue processing tables for reliable background processing
794 613 */
795 614 function mxchat_create_queue_tables() {
796 615 global $wpdb;
@@ -862,34 +681,8 @@
862 681 dbDelta($sql);
863 682 }
864 683
865 684 /**
866 - * Create per-session satisfaction ratings table (v3.2.6)
867 - * Stores one 👍/👎 rating + optional feedback per chat session.
868 - */
869 -function mxchat_create_session_ratings_table() {
870 - global $wpdb;
871 - $charset_collate = $wpdb->get_charset_collate();
872 -
873 - $table_name = $wpdb->prefix . 'mxchat_session_ratings';
874 - $sql = "CREATE TABLE $table_name (
875 - id bigint(20) unsigned NOT NULL AUTO_INCREMENT,
876 - session_id varchar(255) NOT NULL,
877 - bot_id varchar(50) NOT NULL DEFAULT 'default',
878 - rating_value tinyint(1) NOT NULL,
879 - rating_feedback text DEFAULT NULL,
880 - created_at datetime NOT NULL,
881 - PRIMARY KEY (id),
882 - UNIQUE KEY session_id (session_id),
883 - KEY bot_id (bot_id),
884 - KEY created_at (created_at)
885 - ) $charset_collate;";
886 -
887 - require_once(ABSPATH . 'wp-admin/includes/upgrade.php');
888 - dbDelta($sql);
889 -}
890 -
891 -/**
892 685 * 2.5.2: Fix URL column size to support long URLs (especially with UTF-8 encoding)
893 686 * This fixes "url, source_url. The supplied values may be too long" errors
894 687 */
895 688 function mxchat_fix_url_column_size() {
@@ -948,9 +741,9 @@
948 741 if (in_array($current_model, $deprecated_claude_models, true)) {
949 742 $options['model'] = 'claude-opus-4-6';
950 743 $migrated = true;
951 744 $migration_message = sprintf(
952 - 'Your chatbot model has been automatically updated from %s to Claude Opus 4.6 due to Anthropic deprecating older Claude models.',
745 + __('Your chatbot model has been automatically updated from %s to Claude Opus 4.6 due to Anthropic deprecating older Claude models.', 'mxchat'),
953 746 $current_model
954 747 );
955 748 }
956 749
@@ -957,9 +750,9 @@
957 750 // Migrate deprecated Claude Haiku 3.5 to Claude Haiku 4.5
958 751 if ($current_model === 'claude-3-5-haiku-20241022') {
959 752 $options['model'] = 'claude-haiku-4-5-20251001';
960 753 $migrated = true;
961 - $migration_message = 'Your chatbot model has been automatically updated from Claude Haiku 3.5 to Claude Haiku 4.5 due to Anthropic deprecating the older model.';
754 + $migration_message = __('Your chatbot model has been automatically updated from Claude Haiku 3.5 to Claude Haiku 4.5 due to Anthropic deprecating the older model.', 'mxchat');
962 755 }
963 756
964 757 // Migrate deprecated GPT-4 series and GPT-3.5 Turbo to GPT-5.1 Chat Latest
965 758 if (in_array($current_model, array('gpt-4o', 'gpt-4.1-2025-04-14', 'gpt-4-turbo', 'gpt-4', 'gpt-3.5-turbo'), true)) {
@@ -965,9 +758,9 @@
965 758 if (in_array($current_model, array('gpt-4o', 'gpt-4.1-2025-04-14', 'gpt-4-turbo', 'gpt-4', 'gpt-3.5-turbo'), true)) {
966 759 $options['model'] = 'gpt-5.1-chat-latest';
967 760 $migrated = true;
968 761 $migration_message = sprintf(
969 - 'Your chatbot model has been automatically updated from %s to GPT-5.1 Chat Latest due to OpenAI deprecating older models.',
762 + __('Your chatbot model has been automatically updated from %s to GPT-5.1 Chat Latest due to OpenAI deprecating older models.', 'mxchat'),
970 763 $current_model
971 764 );
972 765 }
973 766
@@ -975,9 +768,9 @@
975 768 if (in_array($current_model, array('gpt-4o-mini', 'gpt-4.1-mini'), true)) {
976 769 $options['model'] = 'gpt-5-mini';
977 770 $migrated = true;
978 771 $migration_message = sprintf(
979 - 'Your chatbot model has been automatically updated from %s to GPT-5 Mini due to OpenAI deprecating GPT-4 series models.',
772 + __('Your chatbot model has been automatically updated from %s to GPT-5 Mini due to OpenAI deprecating GPT-4 series models.', 'mxchat'),
980 773 $current_model
981 774 );
982 775 }
983 776
@@ -1044,26 +837,13 @@
1044 837 enabled_bots LONGTEXT DEFAULT NULL,
1045 838 PRIMARY KEY (id)
1046 839 ) $charset_collate;";
1047 840
1048 - // Individual Intent Phrases Table - each phrase gets its own embedding vector
1049 - $intent_phrases_table = $wpdb->prefix . 'mxchat_intent_phrases';
1050 - $sql_intent_phrases_table = "CREATE TABLE $intent_phrases_table (
1051 - id BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT,
1052 - intent_id BIGINT(20) UNSIGNED NOT NULL,
1053 - phrase TEXT NOT NULL,
1054 - embedding_vector LONGTEXT NOT NULL,
1055 - created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL,
1056 - PRIMARY KEY (id),
1057 - KEY intent_id (intent_id)
1058 - ) $charset_collate;";
1059 -
1060 841 require_once ABSPATH . 'wp-admin/includes/upgrade.php';
1061 842
1062 843 // Create other tables
1063 844 dbDelta($sql_system_prompt);
1064 845 dbDelta($sql_intents_table);
1065 - dbDelta($sql_intent_phrases_table);
1066 846
1067 847 // Create URL click tracking table
1068 848 mxchat_create_url_clicks_table();
1069 849
@@ -1075,11 +855,8 @@
1075 855
1076 856 // Create transcript translations table
1077 857 mxchat_create_translations_table();
1078 858
1079 - // Create per-session satisfaction ratings table (v3.2.6)
1080 - mxchat_create_session_ratings_table();
1081 -
1082 859 // Ensure additional columns in system prompt table
1083 860 $existing_system_columns = $wpdb->get_results("SHOW COLUMNS FROM $system_prompt_table");
1084 861 if (!empty($existing_system_columns)) {
1085 862 $existing_system_column_names = array_column($existing_system_columns, 'Field');
@@ -1122,11 +899,8 @@
1122 899
1123 900 // Run migration for existing installations
1124 901 mxchat_migrate_pinecone_roles_add_bot_id();
1125 902
1126 - // 3.2.4: Backfill active embedding model option (replaces 3.2.3 column-based tracking)
1127 - mxchat_backfill_active_embedding_model();
1128 -
1129 903 // Setup cron jobs
1130 904 mxchat_setup_cron_jobs();
1131 905
1132 906 // Update version
@@ -1161,14 +935,13 @@
1161 935 // Clear fallback flags if cron scheduling succeeded
1162 936 delete_option('mxchat_use_fallback_rate_limits');
1163 937 }
1164 938
1165 - // Schedule transcript cleanup if configured (bucket dropdown OR custom retention-days > 0)
939 + // Schedule transcript cleanup if configured
1166 940 $transcript_options = get_option('mxchat_transcripts_options', array());
1167 941 $cleanup_interval = isset($transcript_options['mxchat_auto_delete_transcripts']) ? $transcript_options['mxchat_auto_delete_transcripts'] : 'never';
1168 - $custom_retention = isset($transcript_options['mxchat_retention_days']) ? (int) $transcript_options['mxchat_retention_days'] : 0;
1169 -
1170 - if ($cleanup_interval !== 'never' || $custom_retention > 0) {
942 +
943 + if ($cleanup_interval !== 'never') {
1171 944 // Check if not already scheduled
1172 945 if (!wp_next_scheduled('mxchat_cleanup_old_transcripts')) {
1173 946 // Schedule to run daily at 3 AM
1174 947 $next_run = strtotime('tomorrow 3:00 AM');
@@ -1296,20 +1069,8 @@
1296 1069 if (version_compare($current_version, '3.1.2', '<')) {
1297 1070 mxchat_migrate_transcripts_charset();
1298 1071 }
1299 1072
1300 - // 3.1.7: Clean up stale shared session email/name entries
1301 - if (version_compare($current_version, '3.1.7', '<')) {
1302 - delete_option('mxchat_email_null');
1303 - delete_option('mxchat_name_null');
1304 - }
1305 -
1306 - // 3.2.4: Backfill active embedding model option for the warning UI
1307 - // (replaces the per-row column tracking from 3.2.3, which was reverted)
1308 - if (version_compare($current_version, '3.2.4', '<')) {
1309 - mxchat_backfill_active_embedding_model();
1310 - }
1311 -
1312 1073 // Run full activation to ensure everything is up to date
1313 1074 mxchat_activate();
1314 1075
1315 1076 // Run migration functions
@@ -1480,9 +1241,9 @@
1480 1241 // Check if we're upgrading TO 3.0.1 and haven't handled this yet
1481 1242 if (version_compare($current_version, $target_version, '<') && !$update_handled) {
1482 1243 // Check if Pro is activated - only show to Pro users
1483 1244 $license_status = get_option('mxchat_license_status', 'inactive');
1484 - $is_pro = ($license_status === 'active');
1245 + $is_pro = ($license_status === 'active' || $license_status === esc_html__('active', 'mxchat'));
1485 1246
1486 1247 if ($is_pro) {
1487 1248 // Set flag to show the theme migration notification banner
1488 1249 update_option('mxchat_show_theme_migration_notice', true);
@@ -1534,23 +1295,8 @@
1534 1295 if (class_exists('MxChat_Content_Generator')) {
1535 1296 new MxChat_Content_Generator();
1536 1297 }
1537 1298
1538 - // Initialize cache purge globally — settings writes can happen on any
1539 - // request type (admin screens, admin-ajax autosave, wp-cli), and the
1540 - // deferred-purge cron event fires on front-end requests.
1541 - if (class_exists('MxChat_Cache_Purge')) {
1542 - MxChat_Cache_Purge::init();
1543 - }
1544 -
1545 - // Initialize REST API globally — endpoints must be registered on
1546 - // every request (admin and frontend) so they're reachable via /wp-json/.
1547 - // Endpoints are auth-gated and locked until the site owner generates
1548 - // a token in MxChat → API Access.
1549 - if (class_exists('MxChat_Rest_Api')) {
1550 - new MxChat_Rest_Api();
1551 - }
1552 -
1553 1299 // Initialize public classes
1554 1300 if (class_exists('MxChat_Public')) {
1555 1301 $mxchat_public = new MxChat_Public();
1556 1302 }
@@ -1595,25 +1341,11 @@
1595 1341
1596 1342 mxchat_migrate_pinecone_roles_add_bot_id();
1597 1343 mxchat_migrate_add_content_type_column();
1598 1344 mxchat_migrate_add_translations_table();
1599 - mxchat_migrate_add_session_ratings_table();
1600 1345 }
1601 1346
1602 1347 /**
1603 - * Migration: Create per-session satisfaction ratings table (v3.2.6)
1604 - * For users upgrading from versions before 3.2.6
1605 - */
1606 -function mxchat_migrate_add_session_ratings_table() {
1607 - $migration_key = 'mxchat_session_ratings_table_created';
1608 - if (get_option($migration_key)) {
1609 - return;
1610 - }
1611 - mxchat_create_session_ratings_table();
1612 - update_option($migration_key, '3.2.6');
1613 -}
1614 -
1615 -/**
1616 1348 * Migration: Create transcript translations table (v3.0.4)
1617 1349 * For users upgrading from versions before 3.0.4
1618 1350 */
1619 1351 function mxchat_migrate_add_translations_table() {
@@ -1656,67 +1388,5 @@
1656 1388 return $schedules;
1657 1389 });
1658 1390
1659 1391 // Register deactivation hook
1660 -register_deactivation_hook(__FILE__, 'mxchat_deactivate');
1661 -
1662 -/**
1663 - * Per-session satisfaction rating: AJAX save handler (v3.2.6).
1664 - * Records one 👍/👎 + optional feedback per chat session. The UNIQUE KEY on
1665 - * session_id makes this naturally idempotent — only the first rating per
1666 - * session is stored; duplicate POSTs are silent no-ops.
1667 - */
1668 -function mxchat_save_session_rating() {
1669 - global $wpdb;
1670 -
1671 - $session_id = isset($_POST['session_id']) ? sanitize_text_field(wp_unslash($_POST['session_id'])) : '';
1672 - $bot_id = isset($_POST['bot_id']) ? sanitize_text_field(wp_unslash($_POST['bot_id'])) : 'default';
1673 - $rating_raw = isset($_POST['rating']) ? (int) $_POST['rating'] : 0;
1674 - $feedback = isset($_POST['feedback']) ? sanitize_textarea_field(wp_unslash($_POST['feedback'])) : '';
1675 -
1676 - if ($session_id === '' || ($rating_raw !== 1 && $rating_raw !== -1)) {
1677 - wp_send_json_error(array('message' => 'invalid_input'), 400);
1678 - }
1679 -
1680 - if (strlen($feedback) > 1000) {
1681 - $feedback = substr($feedback, 0, 1000);
1682 - }
1683 -
1684 - $table_name = $wpdb->prefix . 'mxchat_session_ratings';
1685 - $existing = $wpdb->get_var($wpdb->prepare(
1686 - "SELECT id FROM $table_name WHERE session_id = %s LIMIT 1",
1687 - $session_id
1688 - ));
1689 -
1690 - if ($existing) {
1691 - if ($feedback !== '') {
1692 - $wpdb->update(
1693 - $table_name,
1694 - array('rating_feedback' => $feedback),
1695 - array('id' => (int) $existing),
1696 - array('%s'),
1697 - array('%d')
1698 - );
1699 - }
1700 - wp_send_json_success(array('updated' => true));
1701 - }
1702 -
1703 - $inserted = $wpdb->insert(
1704 - $table_name,
1705 - array(
1706 - 'session_id' => $session_id,
1707 - 'bot_id' => $bot_id !== '' ? $bot_id : 'default',
1708 - 'rating_value' => $rating_raw,
1709 - 'rating_feedback' => $feedback !== '' ? $feedback : null,
1710 - 'created_at' => current_time('mysql'),
1711 - ),
1712 - array('%s', '%s', '%d', '%s', '%s')
1713 - );
1714 -
1715 - if ($inserted === false) {
1716 - wp_send_json_error(array('message' => 'db_insert_failed'), 500);
1717 - }
1718 -
1719 - wp_send_json_success(array('saved' => true));
1720 -}
1721 -add_action('wp_ajax_mxchat_save_rating', 'mxchat_save_session_rating');
1722 -add_action('wp_ajax_nopriv_mxchat_save_rating', 'mxchat_save_session_rating');
1392 +register_deactivation_hook(__FILE__, 'mxchat_deactivate');