PluginProbe
MxChat – AI Chatbot & Content Generation for WordPress / 2.3.8
MxChat – AI Chatbot & Content Generation for WordPress v2.3.8
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 +423 -50 2.0.62.3.8 View file →
@@ -1,9 +1,9 @@
1 1 <?php
2 2 /**
3 3 * Plugin Name: MxChat
4 4 * Description: AI chatbot for WordPress with OpenAI, Claude, xAI, DeepSeek, live agent, PDF uploads, WooCommerce, and training on website data.
5 - * Version: 2.0.6
5 + * Version: 2.3.8
6 6 * Author: MxChat
7 7 * Author URI: https://mxchat.ai
8 8 * License: GPLv2 or later
9 9 * License URI: https://www.gnu.org/licenses/gpl-2.0.html
@@ -14,8 +14,10 @@
14 14 if (!defined('ABSPATH')) {
15 15 exit; // Exit if accessed directly.
16 16 }
17 17
18 +// Define plugin version constant for asset versioning
19 +define('MXCHAT_VERSION', '2.3.8');
18 20
19 21 function mxchat_load_textdomain() {
20 22 load_plugin_textdomain('mxchat', false, dirname(plugin_basename(__FILE__)) . '/languages');
21 23 }
@@ -20,24 +22,71 @@
20 22 load_plugin_textdomain('mxchat', false, dirname(plugin_basename(__FILE__)) . '/languages');
21 23 }
22 24 add_action('plugins_loaded', 'mxchat_load_textdomain');
23 25
24 -// Include classes
25 -require_once plugin_dir_path(__FILE__) . 'includes/class-mxchat-integrator.php';
26 -require_once plugin_dir_path(__FILE__) . 'includes/class-mxchat-admin.php';
27 -require_once plugin_dir_path(__FILE__) . 'includes/class-mxchat-public.php';
28 -require_once plugin_dir_path(__FILE__) . 'includes/class-mxchat-utils.php';
29 -require_once plugin_dir_path(__FILE__) . 'includes/class-mxchat-user.php';
30 -require_once plugin_dir_path(__FILE__) . 'includes/pdf-parser/alt_autoload.php';
31 -require_once plugin_dir_path(__FILE__) . 'includes/class-mxchat-word-handler.php';
26 +// Include classes with error handling
27 +function mxchat_include_classes() {
28 + $class_files = array(
29 + 'includes/class-mxchat-integrator.php',
30 + 'includes/class-mxchat-admin.php',
31 + 'includes/class-mxchat-public.php',
32 + 'includes/class-mxchat-utils.php',
33 + 'includes/class-mxchat-user.php',
34 + 'includes/pdf-parser/alt_autoload.php',
35 + 'includes/class-mxchat-word-handler.php',
36 + 'admin/class-ajax-handler.php',
37 + 'admin/class-pinecone-manager.php',
38 + 'admin/class-knowledge-manager.php'
39 + );
32 40
33 -function mxchat_activate() {
41 + foreach ($class_files as $file) {
42 + $file_path = plugin_dir_path(__FILE__) . $file;
43 + if (file_exists($file_path)) {
44 + require_once $file_path;
45 + } else {
46 + //error_log('MxChat: Missing class file - ' . $file);
47 + }
48 + }
49 +}
50 +
51 +/**
52 + * Create URL click tracking table
53 + */
54 +function mxchat_create_url_clicks_table() {
34 55 global $wpdb;
56 +
57 + $table_name = $wpdb->prefix . 'mxchat_url_clicks';
58 +
35 59 $charset_collate = $wpdb->get_charset_collate();
60 +
61 + $sql = "CREATE TABLE $table_name (
62 + id mediumint(9) NOT NULL AUTO_INCREMENT,
63 + session_id varchar(100) NOT NULL,
64 + clicked_url text NOT NULL,
65 + message_context text,
66 + click_timestamp datetime DEFAULT CURRENT_TIMESTAMP,
67 + user_ip varchar(45),
68 + user_agent text,
69 + PRIMARY KEY (id),
70 + KEY session_id (session_id),
71 + KEY click_timestamp (click_timestamp)
72 + ) $charset_collate;";
73 +
74 + require_once(ABSPATH . 'wp-admin/includes/upgrade.php');
75 + dbDelta($sql);
76 +}
36 77
37 - // Chat Transcripts Table
38 - $chat_transcripts_table = $wpdb->prefix . 'mxchat_chat_transcripts';
39 - $sql_chat_transcripts = "CREATE TABLE $chat_transcripts_table (
78 +/**
79 + * FIXED: Robust table creation and column management
80 + */
81 +function mxchat_create_chat_transcripts_table() {
82 + global $wpdb;
83 +
84 + $table_name = $wpdb->prefix . 'mxchat_chat_transcripts';
85 + $charset_collate = $wpdb->get_charset_collate();
86 +
87 + // Create table with ALL columns including user_name from the start
88 + $sql = "CREATE TABLE $table_name (
40 89 id MEDIUMINT(9) NOT NULL AUTO_INCREMENT,
41 90 user_id MEDIUMINT(9) DEFAULT 0,
42 91 session_id VARCHAR(255) NOT NULL,
43 92 role VARCHAR(255) NOT NULL,
@@ -42,12 +91,88 @@
42 91 session_id VARCHAR(255) NOT NULL,
43 92 role VARCHAR(255) NOT NULL,
44 93 message TEXT NOT NULL,
45 94 user_email VARCHAR(255) DEFAULT NULL,
95 + user_name VARCHAR(100) DEFAULT NULL,
96 + user_identifier VARCHAR(255) DEFAULT NULL,
97 + originating_page_url TEXT DEFAULT NULL,
98 + originating_page_title VARCHAR(500) DEFAULT NULL,
46 99 timestamp TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL,
47 - PRIMARY KEY (id)
100 + PRIMARY KEY (id),
101 + KEY session_id (session_id),
102 + KEY user_email (user_email),
103 + KEY timestamp (timestamp)
48 104 ) $charset_collate;";
105 +
106 + require_once(ABSPATH . 'wp-admin/includes/upgrade.php');
107 + $result = dbDelta($sql);
108 +
109 + // Log the result for debugging
110 + if (empty($result)) {
111 + //error_log("MxChat: dbDelta returned empty result for chat transcripts table");
112 + } else {
113 + //error_log("MxChat: dbDelta result: " . print_r($result, true));
114 + }
115 +
116 + // IMPORTANT: Ensure all columns exist for existing installations
117 + mxchat_ensure_all_columns($table_name);
118 +}
49 119
120 +/**
121 + * IMPROVED: Ensure all required columns exist (for upgrades)
122 + */
123 +function mxchat_ensure_all_columns($table_name) {
124 + global $wpdb;
125 +
126 + // First check if table exists
127 + $table_exists = $wpdb->get_var("SHOW TABLES LIKE '$table_name'") === $table_name;
128 + if (!$table_exists) {
129 + //error_log("MxChat: Table $table_name does not exist, cannot add columns");
130 + return;
131 + }
132 +
133 + // Define all required columns and their types
134 + $required_columns = [
135 + 'user_identifier' => 'VARCHAR(255) DEFAULT NULL',
136 + 'user_email' => 'VARCHAR(255) DEFAULT NULL',
137 + 'user_name' => 'VARCHAR(100) DEFAULT NULL',
138 + 'originating_page_url' => 'TEXT DEFAULT NULL',
139 + 'originating_page_title' => 'VARCHAR(500) DEFAULT NULL'
140 + ];
141 +
142 + // Get existing columns
143 + $existing_columns = $wpdb->get_results("SHOW COLUMNS FROM $table_name");
144 + if (empty($existing_columns)) {
145 + //error_log("MxChat: Could not get columns for table $table_name");
146 + return;
147 + }
148 +
149 + $existing_column_names = array_column($existing_columns, 'Field');
150 +
151 + // Add missing columns
152 + foreach ($required_columns as $column_name => $column_definition) {
153 + if (!in_array($column_name, $existing_column_names)) {
154 + $alter_sql = "ALTER TABLE $table_name ADD COLUMN $column_name $column_definition";
155 + $result = $wpdb->query($alter_sql);
156 +
157 + if ($result === false) {
158 + //error_log("MxChat: Failed to add column $column_name to $table_name. Error: " . $wpdb->last_error);
159 + } else {
160 + //error_log("MxChat: Successfully added column $column_name to $table_name");
161 + }
162 + }
163 + }
164 +}
165 +
166 +function mxchat_activate() {
167 + global $wpdb;
168 + $charset_collate = $wpdb->get_charset_collate();
169 +
170 + //error_log("MxChat: Running activation function");
171 +
172 + // Create chat transcripts table with improved function
173 + mxchat_create_chat_transcripts_table();
174 +
50 175 // System Prompt Content Table
51 176 $system_prompt_table = $wpdb->prefix . 'mxchat_system_prompt_content';
52 177 $sql_system_prompt = "CREATE TABLE $system_prompt_table (
53 178 id MEDIUMINT(9) NOT NULL AUTO_INCREMENT,
@@ -67,51 +192,232 @@
67 192 phrases TEXT NOT NULL,
68 193 embedding_vector LONGTEXT NOT NULL,
69 194 callback_function VARCHAR(255) NOT NULL,
70 195 similarity_threshold FLOAT DEFAULT 0.85,
196 + enabled TINYINT(1) NOT NULL DEFAULT 1,
71 197 PRIMARY KEY (id)
72 198 ) $charset_collate;";
73 199
74 200 require_once ABSPATH . 'wp-admin/includes/upgrade.php';
75 201
76 - // Create or update tables
77 - dbDelta($sql_chat_transcripts);
202 + // Create other tables
78 203 dbDelta($sql_system_prompt);
79 204 dbDelta($sql_intents_table);
80 205
81 - // Ensure additional columns in `mxchat_chat_transcripts`
82 - mxchat_add_missing_columns($chat_transcripts_table, 'user_identifier', 'VARCHAR(255)');
83 - mxchat_add_missing_columns($chat_transcripts_table, 'user_email', 'VARCHAR(255) DEFAULT NULL');
206 + // Create URL click tracking table
207 + mxchat_create_url_clicks_table();
84 208
85 - // Ensure additional columns in `mxchat_system_prompt_content`
86 - mxchat_add_missing_columns($system_prompt_table, 'embedding_vector', 'LONGTEXT');
87 - mxchat_add_missing_columns($system_prompt_table, 'source_url', 'VARCHAR(255) DEFAULT NULL');
209 + // Ensure additional columns in system prompt table
210 + $existing_system_columns = $wpdb->get_results("SHOW COLUMNS FROM $system_prompt_table");
211 + if (!empty($existing_system_columns)) {
212 + $existing_system_column_names = array_column($existing_system_columns, 'Field');
213 +
214 + if (!in_array('embedding_vector', $existing_system_column_names)) {
215 + $wpdb->query("ALTER TABLE $system_prompt_table ADD COLUMN embedding_vector LONGTEXT");
216 + }
217 + if (!in_array('source_url', $existing_system_column_names)) {
218 + $wpdb->query("ALTER TABLE $system_prompt_table ADD COLUMN source_url VARCHAR(255) DEFAULT NULL");
219 + }
220 + }
88 221
89 222 // Set default thresholds for existing intents
90 223 $wpdb->query("UPDATE {$intents_table} SET similarity_threshold = 0.85 WHERE similarity_threshold IS NULL");
224 +
225 + // Ensure enabled column exists in intents table
226 + $existing_intent_columns = $wpdb->get_results("SHOW COLUMNS FROM $intents_table");
227 + if (!empty($existing_intent_columns)) {
228 + $existing_intent_column_names = array_column($existing_intent_columns, 'Field');
229 +
230 + if (!in_array('enabled', $existing_intent_column_names)) {
231 + $wpdb->query("ALTER TABLE $intents_table ADD COLUMN enabled TINYINT(1) NOT NULL DEFAULT 1");
232 + }
233 + }
91 234
92 - // Update plugin version in the database
93 - update_option('mxchat_plugin_version', '2.0.6');
235 + // Setup cron jobs
236 + mxchat_setup_cron_jobs();
237 +
238 + // Update version
239 + update_option('mxchat_plugin_version', MXCHAT_VERSION);
240 +
241 + //error_log("MxChat: Activation function completed");
94 242 }
95 243
244 +/**
245 + * Setup cron jobs on plugin activation
246 + */
247 +function mxchat_setup_cron_jobs() {
248 + // Clear any existing cron jobs first
249 + wp_clear_scheduled_hook('mxchat_reset_rate_limits');
250 +
251 + // Check if WordPress cron is disabled
252 + if (defined('DISABLE_WP_CRON') && DISABLE_WP_CRON) {
253 + // Set flag to use fallback system
254 + update_option('mxchat_use_fallback_rate_limits', true);
255 + update_option('mxchat_next_rate_limit_check', time() + 3600);
256 + return;
257 + }
258 +
259 + // Schedule the rate limit reset cron job
260 + $result = wp_schedule_event(time() + 300, 'hourly', 'mxchat_reset_rate_limits');
261 +
262 + if ($result === false) {
263 + // Fallback if scheduling fails
264 + update_option('mxchat_use_fallback_rate_limits', true);
265 + update_option('mxchat_next_rate_limit_check', time() + 3600);
266 + } else {
267 + // Clear fallback flags if cron scheduling succeeded
268 + delete_option('mxchat_use_fallback_rate_limits');
269 + }
270 +}
96 271
97 -function mxchat_add_missing_columns($table, $column_name, $column_type) {
272 +/**
273 + * Clean up on plugin deactivation
274 + */
275 +function mxchat_deactivate() {
276 + // Clear scheduled cron jobs
277 + wp_clear_scheduled_hook('mxchat_reset_rate_limits');
278 +
279 + // Clear fallback options
280 + delete_option('mxchat_use_fallback_rate_limits');
281 + delete_option('mxchat_next_rate_limit_check');
282 + delete_option('mxchat_fallback_check_interval');
283 +}
284 +
285 +/**
286 + * Check if fallback rate limit cleanup is needed
287 + */
288 +function mxchat_check_fallback_rate_limits() {
289 + $use_fallback = get_option('mxchat_use_fallback_rate_limits', false);
290 +
291 + if (!$use_fallback) {
292 + return;
293 + }
294 +
295 + $next_check = get_option('mxchat_next_rate_limit_check', 0);
296 +
297 + if (time() >= $next_check) {
298 + // Only run reset if the MxChat_Integrator class exists
299 + if (class_exists('MxChat_Integrator')) {
300 + $integrator = new MxChat_Integrator();
301 + if (method_exists($integrator, 'mxchat_reset_rate_limits')) {
302 + $integrator->mxchat_reset_rate_limits();
303 + update_option('mxchat_next_rate_limit_check', time() + 3600);
304 + }
305 + }
306 + }
307 +}
308 +
309 +/**
310 + * FIXED: Robust update checking with proper version handling
311 + */
312 +function mxchat_check_for_update() {
313 + global $wpdb; // CRITICAL: Declare this at the top
314 +
315 + try {
316 + $current_version = get_option('mxchat_plugin_version', '0.0.0');
317 + $plugin_version = MXCHAT_VERSION;
318 +
319 + // Always run activation to ensure tables exist (safe for existing installations)
320 + if ($current_version !== $plugin_version) {
321 + //error_log("MxChat: Version change detected: $current_version -> $plugin_version");
322 +
323 + // Run live agent update BEFORE updating the stored version
324 + mxchat_handle_live_agent_update();
325 +
326 + // Run activation (this will create/update all tables and columns)
327 + mxchat_activate();
328 +
329 + // Run migration functions
330 + mxchat_migrate_live_agent_status();
331 +
332 + // Add the cleanup function for version 2.1.8
333 + if (version_compare($current_version, '2.1.8', '<')) {
334 + $deleted = mxchat_cleanup_orphaned_chat_history();
335 + }
336 +
337 + // Update version LAST
338 + update_option('mxchat_plugin_version', $plugin_version);
339 +
340 + //error_log("MxChat: Updated from version $current_version to $plugin_version");
341 + }
342 +
343 + // CRITICAL: Always ensure tables exist, even if version matches
344 + // This handles cases where tables were manually deleted
345 + $table_name = $wpdb->prefix . 'mxchat_chat_transcripts';
346 + $table_exists = $wpdb->get_var("SHOW TABLES LIKE '$table_name'") === $table_name;
347 +
348 + if (!$table_exists) {
349 + //error_log("MxChat: Chat transcripts table missing, recreating...");
350 + mxchat_activate(); // Run full activation instead of just table creation
351 + }
352 +
353 + } catch (Exception $e) {
354 + //error_log('MxChat update error: ' . $e->getMessage());
355 + // Don't update version if there was an error
356 + }
357 +}
358 +
359 +/**
360 + * CRITICAL: Ensure tables exist on every load for fresh installations
361 + */
362 +function mxchat_ensure_tables_exist() {
98 363 global $wpdb;
99 - $column_exists = $wpdb->get_results($wpdb->prepare("SHOW COLUMNS FROM $table LIKE %s", $column_name));
100 - if (empty($column_exists)) {
101 - $wpdb->query("ALTER TABLE $table ADD COLUMN $column_name $column_type");
364 +
365 + // Only run for admin users to avoid performance impact
366 + if (!current_user_can('administrator')) {
367 + return;
102 368 }
369 +
370 + $table_name = $wpdb->prefix . 'mxchat_chat_transcripts';
371 + $table_exists = $wpdb->get_var("SHOW TABLES LIKE '$table_name'") === $table_name;
372 +
373 + if (!$table_exists) {
374 + //error_log("MxChat: Tables missing on admin load, running activation");
375 + mxchat_activate();
376 + }
103 377 }
104 378
105 -function mxchat_check_for_update() {
106 - $current_version = get_option('mxchat_plugin_version');
107 - $plugin_version = '2.0.6'; // Update with your latest version
379 +/**
380 + * Clean up orphaned chat history options from the wp_options table
381 + * @return int Number of options deleted
382 + */
383 +function mxchat_cleanup_orphaned_chat_history() {
384 + global $wpdb;
385 + $count = 0;
108 386
109 - if ($current_version !== $plugin_version) {
110 - mxchat_activate(); // Run the activation script to apply schema changes
111 - mxchat_migrate_live_agent_status(); // Add migration for live agent status
112 - update_option('mxchat_plugin_version', $plugin_version); // Update the version
387 + // Get all option keys that match our pattern
388 + $history_options = $wpdb->get_results(
389 + "SELECT option_name FROM {$wpdb->options}
390 + WHERE option_name LIKE 'mxchat_history_%'"
391 + );
392 +
393 + if (!empty($history_options)) {
394 + foreach ($history_options as $option) {
395 + // Extract the session ID from the option name
396 + $session_id = str_replace('mxchat_history_', '', $option->option_name);
397 +
398 + // Check if this session still exists in the custom table
399 + $table_name = $wpdb->prefix . 'mxchat_chat_transcripts';
400 + $exists = $wpdb->get_var(
401 + $wpdb->prepare(
402 + "SELECT COUNT(*) FROM {$table_name} WHERE session_id = %s",
403 + $session_id
404 + )
405 + );
406 +
407 + // If session doesn't exist in the main table, delete the option
408 + if ($exists == 0) {
409 + delete_option($option->option_name);
410 + // Also delete related metadata
411 + delete_option("mxchat_email_{$session_id}");
412 + delete_option("mxchat_name_{$session_id}");
413 + delete_option("mxchat_agent_name_{$session_id}");
414 + $count++;
415 + }
416 + }
113 417 }
418 +
419 + return $count;
114 420 }
115 421
116 422 function mxchat_migrate_live_agent_status() {
117 423 $options = get_option('mxchat_options', []);
@@ -144,16 +450,93 @@
144 450 update_option('mxchat_options', $options);
145 451 }
146 452 }
147 453
454 +function mxchat_handle_live_agent_update() {
455 + // Get the CURRENT stored version (before it gets updated)
456 + $current_version = get_option('mxchat_plugin_version', '0.0.0');
457 + $new_version = '2.2.2';
458 +
459 + // Only run this once for the update to 2.2.2
460 + $update_handled = get_option('mxchat_live_agent_update_2_2_2_handled', false);
461 +
462 + // Check if we're upgrading TO 2.2.2 and haven't handled this yet
463 + if (version_compare($current_version, $new_version, '<') && !$update_handled) {
464 + $options = get_option('mxchat_options', array());
465 +
466 + // Check if live agent was previously enabled
467 + if (isset($options['live_agent_status']) && $options['live_agent_status'] === 'on') {
468 + // Disable live agent
469 + $options['live_agent_status'] = 'off';
470 + update_option('mxchat_options', $options);
471 +
472 + // Set flag to show the notification banner
473 + update_option('mxchat_show_live_agent_disabled_notice', true);
474 + }
475 +
476 + // Mark this update as handled
477 + update_option('mxchat_live_agent_update_2_2_2_handled', true);
478 + }
479 +}
148 480
149 -// Run the update check function on every request
150 -add_action('plugins_loaded', 'mxchat_check_for_update');
481 +// Initialize plugin safely
482 +function mxchat_init() {
483 + // Include all class files first
484 + mxchat_include_classes();
485 +
486 + // Run update check
487 + mxchat_check_for_update();
488 +
489 + // CRITICAL: Ensure tables exist (for fresh installations that don't trigger activation hook)
490 + add_action('admin_init', 'mxchat_ensure_tables_exist', 1);
491 +
492 + // Add fallback rate limit check
493 + add_action('init', 'mxchat_check_fallback_rate_limits', 5);
494 +
495 + // Initialize classes with error handling
496 + try {
497 + // Initialize admin classes
498 + if (is_admin()) {
499 + if (class_exists('MxChat_Knowledge_Manager')) {
500 + $mxchat_knowledge_manager = new MxChat_Knowledge_Manager();
501 +
502 + if (class_exists('MxChat_Admin')) {
503 + $mxchat_admin = new MxChat_Admin($mxchat_knowledge_manager);
504 + }
505 + }
506 + }
507 +
508 + // Initialize public classes
509 + if (class_exists('MxChat_Public')) {
510 + $mxchat_public = new MxChat_Public();
511 + }
512 +
513 + if (class_exists('MxChat_Integrator')) {
514 + $mxchat_integrator = new MxChat_Integrator();
515 + }
516 +
517 + } catch (Exception $e) {
518 + //error_log('MxChat initialization error: ' . $e->getMessage());
519 +
520 + // Show admin notice if there's an error
521 + if (is_admin()) {
522 + add_action('admin_notices', function() use ($e) {
523 + echo '<div class="notice notice-error"><p>';
524 + echo '<strong>MxChat Error:</strong> Plugin initialization failed. ';
525 + echo 'Please check error logs or contact support. Error: ' . esc_html($e->getMessage());
526 + echo '</p></div>';
527 + });
528 + }
529 + }
530 +}
151 531
532 +// Run initialization on plugins_loaded
533 +add_action('plugins_loaded', 'mxchat_init');
534 +
152 535 // Register activation hook
153 536 register_activation_hook(__FILE__, 'mxchat_activate');
154 537
155 -
538 +// Add cron schedule
156 539 add_filter('cron_schedules', function($schedules) {
157 540 $schedules['one_minute'] = array(
158 541 'interval' => 60,
159 542 'display' => 'Every Minute'
@@ -160,16 +543,6 @@
160 543 );
161 544 return $schedules;
162 545 });
163 546
164 -add_action('init', function() {
165 - add_action('mxchat_process_pdf_pages', array('MxChat_Admin', 'process_pdf_pages_cron'), 10, 5);
166 - add_action('mxchat_process_sitemap_urls', array('MxChat_Admin', 'process_sitemap_urls_cron'), 10, 5);
167 -});
168 -
169 -
170 -// Instantiate classes
171 -if (is_admin()) {
172 - $mxchat_admin = new MxChat_Admin();
173 -}
174 -$mxchat_public = new MxChat_Public();
175 -$mxchat_integrator = new MxChat_Integrator();
547 +// Register deactivation hook
548 +register_deactivation_hook(__FILE__, 'mxchat_deactivate');