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 -239 3.2.63.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.6
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
@@ -250,61 +250,8 @@
250 250 $rejected[] = 'wp-admin/admin-ajax.php';
251 251 return $rejected;
252 252 });
253 253
254 -// ── Page-cache bypass for chat AJAX (companion to the 3.2.6 nonce-race hotfix)
255 -// Each cache plugin gets its own filter export so that visitors hitting an
256 -// edge-cached page never receive cached chat-AJAX responses. The chat send /
257 -// stream send / file upload all POST to /wp-admin/admin-ajax.php with
258 -// `action=mxchat_*`. Without these exports, a cache plugin can stale a response
259 -// and break the per-session nonce flow on the first message.
260 -
261 -// WP Rocket — `rocket_cache_reject_uri` takes a flat array of regex strings.
262 -add_filter('rocket_cache_reject_uri', function($uris) {
263 - if (!is_array($uris)) $uris = array();
264 - $uris[] = '/wp-admin/admin-ajax\.php\?action=mxchat_.*';
265 - return $uris;
266 -});
267 -
268 -// LiteSpeed Cache — `litespeed_cache_no_cache_for_request` short-circuits
269 -// caching when the request matches our chat-AJAX pattern.
270 -add_filter('litespeed_cache_no_cache_for_request', function($no_cache) {
271 - if ($no_cache) return $no_cache;
272 - if (!empty($_SERVER['REQUEST_URI']) &&
273 - strpos($_SERVER['REQUEST_URI'], '/wp-admin/admin-ajax.php') !== false &&
274 - !empty($_REQUEST['action']) &&
275 - strpos((string) $_REQUEST['action'], 'mxchat_') === 0) {
276 - return true;
277 - }
278 - return $no_cache;
279 -});
280 -
281 -// W3 Total Cache — `w3tc_pgcache_request_skip_uri` flips page-cache off when
282 -// the URI matches.
283 -add_filter('w3tc_pgcache_request_skip_uri', function($skip) {
284 - if ($skip) return $skip;
285 - if (!empty($_SERVER['REQUEST_URI']) &&
286 - strpos($_SERVER['REQUEST_URI'], '/wp-admin/admin-ajax.php') !== false &&
287 - !empty($_REQUEST['action']) &&
288 - strpos((string) $_REQUEST['action'], 'mxchat_') === 0) {
289 - return true;
290 - }
291 - return $skip;
292 -});
293 -
294 -// FlyingPress — `flying_press_cacheable` takes a boolean and is run per
295 -// request. Same pattern as LiteSpeed / W3TC.
296 -add_filter('flying_press_cacheable', function($cacheable) {
297 - if (!$cacheable) return $cacheable;
298 - if (!empty($_SERVER['REQUEST_URI']) &&
299 - strpos($_SERVER['REQUEST_URI'], '/wp-admin/admin-ajax.php') !== false &&
300 - !empty($_REQUEST['action']) &&
301 - strpos((string) $_REQUEST['action'], 'mxchat_') === 0) {
302 - return false;
303 - }
304 - return $cacheable;
305 -});
306 -
307 254 // Include classes with error handling
308 255 function mxchat_include_classes() {
309 256 $class_files = array(
310 257 'includes/class-mxchat-integrator.php',
@@ -315,9 +262,8 @@
315 262 'includes/class-mxchat-meta-box.php',
316 263 'includes/class-mxchat-chunker.php',
317 264 'includes/class-mxchat-word-handler.php',
318 265 'includes/class-mxchat-content-generator.php',
319 - 'includes/class-rest-api.php',
320 266 'admin/class-ajax-handler.php',
321 267 'admin/class-pinecone-manager.php',
322 268 'admin/class-knowledge-manager.php'
323 269 );
@@ -329,16 +275,8 @@
329 275 } else {
330 276 //error_log('MxChat: Missing class file - ' . $file);
331 277 }
332 278 }
333 -
334 - // Admin pages that aren't classes (procedural include).
335 - if (is_admin()) {
336 - $admin_api_page = plugin_dir_path(__FILE__) . 'includes/admin-api-page.php';
337 - if (file_exists($admin_api_page)) {
338 - require_once $admin_api_page;
339 - }
340 - }
341 279 }
342 280
343 281 /**
344 282 * Lazy-load the PDF parser library only when needed.
@@ -670,33 +608,8 @@
670 608 update_option('mxchat_content_type_migration_version', '2.5.6');
671 609 }
672 610
673 611 /**
674 - * 3.2.4: Backfill the active embedding model option for installs that already
675 - * have KB content but no stamped model. The mismatch warning compares this
676 - * against the user's currently selected model — no per-row column needed.
677 - */
678 -function mxchat_backfill_active_embedding_model() {
679 - global $wpdb;
680 -
681 - if (get_option('mxchat_active_embedding_model', '') !== '') {
682 - return;
683 - }
684 -
685 - $kb_table = $wpdb->prefix . 'mxchat_system_prompt_content';
686 - if ($wpdb->get_var("SHOW TABLES LIKE '{$kb_table}'") !== $kb_table) {
687 - return;
688 - }
689 -
690 - $kb_count = (int) $wpdb->get_var("SELECT COUNT(*) FROM {$kb_table}");
691 - if ($kb_count > 0) {
692 - $options = get_option('mxchat_options', array());
693 - $current_model = $options['embedding_model'] ?? 'text-embedding-ada-002';
694 - update_option('mxchat_active_embedding_model', $current_model, false);
695 - }
696 -}
697 -
698 -/**
699 612 * 2.5.2: Create queue processing tables for reliable background processing
700 613 */
701 614 function mxchat_create_queue_tables() {
702 615 global $wpdb;
@@ -768,34 +681,8 @@
768 681 dbDelta($sql);
769 682 }
770 683
771 684 /**
772 - * Create per-session satisfaction ratings table (v3.2.6)
773 - * Stores one 👍/👎 rating + optional feedback per chat session.
774 - */
775 -function mxchat_create_session_ratings_table() {
776 - global $wpdb;
777 - $charset_collate = $wpdb->get_charset_collate();
778 -
779 - $table_name = $wpdb->prefix . 'mxchat_session_ratings';
780 - $sql = "CREATE TABLE $table_name (
781 - id bigint(20) unsigned NOT NULL AUTO_INCREMENT,
782 - session_id varchar(255) NOT NULL,
783 - bot_id varchar(50) NOT NULL DEFAULT 'default',
784 - rating_value tinyint(1) NOT NULL,
785 - rating_feedback text DEFAULT NULL,
786 - created_at datetime NOT NULL,
787 - PRIMARY KEY (id),
788 - UNIQUE KEY session_id (session_id),
789 - KEY bot_id (bot_id),
790 - KEY created_at (created_at)
791 - ) $charset_collate;";
792 -
793 - require_once(ABSPATH . 'wp-admin/includes/upgrade.php');
794 - dbDelta($sql);
795 -}
796 -
797 -/**
798 685 * 2.5.2: Fix URL column size to support long URLs (especially with UTF-8 encoding)
799 686 * This fixes "url, source_url. The supplied values may be too long" errors
800 687 */
801 688 function mxchat_fix_url_column_size() {
@@ -854,9 +741,9 @@
854 741 if (in_array($current_model, $deprecated_claude_models, true)) {
855 742 $options['model'] = 'claude-opus-4-6';
856 743 $migrated = true;
857 744 $migration_message = sprintf(
858 - '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'),
859 746 $current_model
860 747 );
861 748 }
862 749
@@ -863,9 +750,9 @@
863 750 // Migrate deprecated Claude Haiku 3.5 to Claude Haiku 4.5
864 751 if ($current_model === 'claude-3-5-haiku-20241022') {
865 752 $options['model'] = 'claude-haiku-4-5-20251001';
866 753 $migrated = true;
867 - $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');
868 755 }
869 756
870 757 // Migrate deprecated GPT-4 series and GPT-3.5 Turbo to GPT-5.1 Chat Latest
871 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)) {
@@ -871,9 +758,9 @@
871 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)) {
872 759 $options['model'] = 'gpt-5.1-chat-latest';
873 760 $migrated = true;
874 761 $migration_message = sprintf(
875 - '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'),
876 763 $current_model
877 764 );
878 765 }
879 766
@@ -881,9 +768,9 @@
881 768 if (in_array($current_model, array('gpt-4o-mini', 'gpt-4.1-mini'), true)) {
882 769 $options['model'] = 'gpt-5-mini';
883 770 $migrated = true;
884 771 $migration_message = sprintf(
885 - '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'),
886 773 $current_model
887 774 );
888 775 }
889 776
@@ -950,26 +837,13 @@
950 837 enabled_bots LONGTEXT DEFAULT NULL,
951 838 PRIMARY KEY (id)
952 839 ) $charset_collate;";
953 840
954 - // Individual Intent Phrases Table - each phrase gets its own embedding vector
955 - $intent_phrases_table = $wpdb->prefix . 'mxchat_intent_phrases';
956 - $sql_intent_phrases_table = "CREATE TABLE $intent_phrases_table (
957 - id BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT,
958 - intent_id BIGINT(20) UNSIGNED NOT NULL,
959 - phrase TEXT NOT NULL,
960 - embedding_vector LONGTEXT NOT NULL,
961 - created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL,
962 - PRIMARY KEY (id),
963 - KEY intent_id (intent_id)
964 - ) $charset_collate;";
965 -
966 841 require_once ABSPATH . 'wp-admin/includes/upgrade.php';
967 842
968 843 // Create other tables
969 844 dbDelta($sql_system_prompt);
970 845 dbDelta($sql_intents_table);
971 - dbDelta($sql_intent_phrases_table);
972 846
973 847 // Create URL click tracking table
974 848 mxchat_create_url_clicks_table();
975 849
@@ -981,11 +855,8 @@
981 855
982 856 // Create transcript translations table
983 857 mxchat_create_translations_table();
984 858
985 - // Create per-session satisfaction ratings table (v3.2.6)
986 - mxchat_create_session_ratings_table();
987 -
988 859 // Ensure additional columns in system prompt table
989 860 $existing_system_columns = $wpdb->get_results("SHOW COLUMNS FROM $system_prompt_table");
990 861 if (!empty($existing_system_columns)) {
991 862 $existing_system_column_names = array_column($existing_system_columns, 'Field');
@@ -1028,11 +899,8 @@
1028 899
1029 900 // Run migration for existing installations
1030 901 mxchat_migrate_pinecone_roles_add_bot_id();
1031 902
1032 - // 3.2.4: Backfill active embedding model option (replaces 3.2.3 column-based tracking)
1033 - mxchat_backfill_active_embedding_model();
1034 -
1035 903 // Setup cron jobs
1036 904 mxchat_setup_cron_jobs();
1037 905
1038 906 // Update version
@@ -1067,14 +935,13 @@
1067 935 // Clear fallback flags if cron scheduling succeeded
1068 936 delete_option('mxchat_use_fallback_rate_limits');
1069 937 }
1070 938
1071 - // Schedule transcript cleanup if configured (bucket dropdown OR custom retention-days > 0)
939 + // Schedule transcript cleanup if configured
1072 940 $transcript_options = get_option('mxchat_transcripts_options', array());
1073 941 $cleanup_interval = isset($transcript_options['mxchat_auto_delete_transcripts']) ? $transcript_options['mxchat_auto_delete_transcripts'] : 'never';
1074 - $custom_retention = isset($transcript_options['mxchat_retention_days']) ? (int) $transcript_options['mxchat_retention_days'] : 0;
1075 -
1076 - if ($cleanup_interval !== 'never' || $custom_retention > 0) {
942 +
943 + if ($cleanup_interval !== 'never') {
1077 944 // Check if not already scheduled
1078 945 if (!wp_next_scheduled('mxchat_cleanup_old_transcripts')) {
1079 946 // Schedule to run daily at 3 AM
1080 947 $next_run = strtotime('tomorrow 3:00 AM');
@@ -1202,20 +1069,8 @@
1202 1069 if (version_compare($current_version, '3.1.2', '<')) {
1203 1070 mxchat_migrate_transcripts_charset();
1204 1071 }
1205 1072
1206 - // 3.1.7: Clean up stale shared session email/name entries
1207 - if (version_compare($current_version, '3.1.7', '<')) {
1208 - delete_option('mxchat_email_null');
1209 - delete_option('mxchat_name_null');
1210 - }
1211 -
1212 - // 3.2.4: Backfill active embedding model option for the warning UI
1213 - // (replaces the per-row column tracking from 3.2.3, which was reverted)
1214 - if (version_compare($current_version, '3.2.4', '<')) {
1215 - mxchat_backfill_active_embedding_model();
1216 - }
1217 -
1218 1073 // Run full activation to ensure everything is up to date
1219 1074 mxchat_activate();
1220 1075
1221 1076 // Run migration functions
@@ -1386,9 +1241,9 @@
1386 1241 // Check if we're upgrading TO 3.0.1 and haven't handled this yet
1387 1242 if (version_compare($current_version, $target_version, '<') && !$update_handled) {
1388 1243 // Check if Pro is activated - only show to Pro users
1389 1244 $license_status = get_option('mxchat_license_status', 'inactive');
1390 - $is_pro = ($license_status === 'active');
1245 + $is_pro = ($license_status === 'active' || $license_status === esc_html__('active', 'mxchat'));
1391 1246
1392 1247 if ($is_pro) {
1393 1248 // Set flag to show the theme migration notification banner
1394 1249 update_option('mxchat_show_theme_migration_notice', true);
@@ -1440,16 +1295,8 @@
1440 1295 if (class_exists('MxChat_Content_Generator')) {
1441 1296 new MxChat_Content_Generator();
1442 1297 }
1443 1298
1444 - // Initialize REST API globally — endpoints must be registered on
1445 - // every request (admin and frontend) so they're reachable via /wp-json/.
1446 - // Endpoints are auth-gated and locked until the site owner generates
1447 - // a token in MxChat → API Access.
1448 - if (class_exists('MxChat_Rest_Api')) {
1449 - new MxChat_Rest_Api();
1450 - }
1451 -
1452 1299 // Initialize public classes
1453 1300 if (class_exists('MxChat_Public')) {
1454 1301 $mxchat_public = new MxChat_Public();
1455 1302 }
@@ -1494,25 +1341,11 @@
1494 1341
1495 1342 mxchat_migrate_pinecone_roles_add_bot_id();
1496 1343 mxchat_migrate_add_content_type_column();
1497 1344 mxchat_migrate_add_translations_table();
1498 - mxchat_migrate_add_session_ratings_table();
1499 1345 }
1500 1346
1501 1347 /**
1502 - * Migration: Create per-session satisfaction ratings table (v3.2.6)
1503 - * For users upgrading from versions before 3.2.6
1504 - */
1505 -function mxchat_migrate_add_session_ratings_table() {
1506 - $migration_key = 'mxchat_session_ratings_table_created';
1507 - if (get_option($migration_key)) {
1508 - return;
1509 - }
1510 - mxchat_create_session_ratings_table();
1511 - update_option($migration_key, '3.2.6');
1512 -}
1513 -
1514 -/**
1515 1348 * Migration: Create transcript translations table (v3.0.4)
1516 1349 * For users upgrading from versions before 3.0.4
1517 1350 */
1518 1351 function mxchat_migrate_add_translations_table() {
@@ -1555,67 +1388,5 @@
1555 1388 return $schedules;
1556 1389 });
1557 1390
1558 1391 // Register deactivation hook
1559 -register_deactivation_hook(__FILE__, 'mxchat_deactivate');
1560 -
1561 -/**
1562 - * Per-session satisfaction rating: AJAX save handler (v3.2.6).
1563 - * Records one 👍/👎 + optional feedback per chat session. The UNIQUE KEY on
1564 - * session_id makes this naturally idempotent — only the first rating per
1565 - * session is stored; duplicate POSTs are silent no-ops.
1566 - */
1567 -function mxchat_save_session_rating() {
1568 - global $wpdb;
1569 -
1570 - $session_id = isset($_POST['session_id']) ? sanitize_text_field(wp_unslash($_POST['session_id'])) : '';
1571 - $bot_id = isset($_POST['bot_id']) ? sanitize_text_field(wp_unslash($_POST['bot_id'])) : 'default';
1572 - $rating_raw = isset($_POST['rating']) ? (int) $_POST['rating'] : 0;
1573 - $feedback = isset($_POST['feedback']) ? sanitize_textarea_field(wp_unslash($_POST['feedback'])) : '';
1574 -
1575 - if ($session_id === '' || ($rating_raw !== 1 && $rating_raw !== -1)) {
1576 - wp_send_json_error(array('message' => 'invalid_input'), 400);
1577 - }
1578 -
1579 - if (strlen($feedback) > 1000) {
1580 - $feedback = substr($feedback, 0, 1000);
1581 - }
1582 -
1583 - $table_name = $wpdb->prefix . 'mxchat_session_ratings';
1584 - $existing = $wpdb->get_var($wpdb->prepare(
1585 - "SELECT id FROM $table_name WHERE session_id = %s LIMIT 1",
1586 - $session_id
1587 - ));
1588 -
1589 - if ($existing) {
1590 - if ($feedback !== '') {
1591 - $wpdb->update(
1592 - $table_name,
1593 - array('rating_feedback' => $feedback),
1594 - array('id' => (int) $existing),
1595 - array('%s'),
1596 - array('%d')
1597 - );
1598 - }
1599 - wp_send_json_success(array('updated' => true));
1600 - }
1601 -
1602 - $inserted = $wpdb->insert(
1603 - $table_name,
1604 - array(
1605 - 'session_id' => $session_id,
1606 - 'bot_id' => $bot_id !== '' ? $bot_id : 'default',
1607 - 'rating_value' => $rating_raw,
1608 - 'rating_feedback' => $feedback !== '' ? $feedback : null,
1609 - 'created_at' => current_time('mysql'),
1610 - ),
1611 - array('%s', '%s', '%d', '%s', '%s')
1612 - );
1613 -
1614 - if ($inserted === false) {
1615 - wp_send_json_error(array('message' => 'db_insert_failed'), 500);
1616 - }
1617 -
1618 - wp_send_json_success(array('saved' => true));
1619 -}
1620 -add_action('wp_ajax_mxchat_save_rating', 'mxchat_save_session_rating');
1621 -add_action('wp_ajax_nopriv_mxchat_save_rating', 'mxchat_save_session_rating');
1392 +register_deactivation_hook(__FILE__, 'mxchat_deactivate');