PluginProbe
MxChat – AI Chatbot & Content Generation for WordPress / 2.5.2
MxChat – AI Chatbot & Content Generation for WordPress v2.5.2
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 +727 -56 2.0.42.5.2 View file →
@@ -1,9 +1,10 @@
1 1 <?php
2 2 /**
3 3 * Plugin Name: MxChat
4 + * Plugin URI: https://mxchat.ai/
4 5 * Description: AI chatbot for WordPress with OpenAI, Claude, xAI, DeepSeek, live agent, PDF uploads, WooCommerce, and training on website data.
5 - * Version: 2.0.4
6 + * Version: 2.5.2
6 7 * Author: MxChat
7 8 * Author URI: https://mxchat.ai
8 9 * License: GPLv2 or later
9 10 * License URI: https://www.gnu.org/licenses/gpl-2.0.html
@@ -14,31 +15,80 @@
14 15 if (!defined('ABSPATH')) {
15 16 exit; // Exit if accessed directly.
16 17 }
17 18
19 +// Define plugin version constant for asset versioning
20 +define('MXCHAT_VERSION', '2.5.2');
18 21
19 22 function mxchat_load_textdomain() {
20 23 load_plugin_textdomain('mxchat', false, dirname(plugin_basename(__FILE__)) . '/languages');
21 24 }
22 -add_action('plugins_loaded', 'mxchat_load_textdomain');
25 +add_action('init', 'mxchat_load_textdomain');
23 26
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/class-mxchat-woocommerce.php';
31 -require_once plugin_dir_path(__FILE__) . 'includes/pdf-parser/alt_autoload.php';
32 -require_once plugin_dir_path(__FILE__) . 'includes/class-mxchat-word-handler.php';
27 +// Include classes with error handling
28 +function mxchat_include_classes() {
29 + $class_files = array(
30 + 'includes/class-mxchat-integrator.php',
31 + 'includes/class-mxchat-admin.php',
32 + 'includes/class-mxchat-public.php',
33 + 'includes/class-mxchat-utils.php',
34 + 'includes/class-mxchat-user.php',
35 + 'includes/class-mxchat-meta-box.php',
36 + 'includes/pdf-parser/alt_autoload.php',
37 + 'includes/class-mxchat-word-handler.php',
38 + 'admin/class-ajax-handler.php',
39 + 'admin/class-pinecone-manager.php',
40 + 'admin/class-knowledge-manager.php'
41 + );
33 42
34 -function mxchat_activate() {
43 + foreach ($class_files as $file) {
44 + $file_path = plugin_dir_path(__FILE__) . $file;
45 + if (file_exists($file_path)) {
46 + require_once $file_path;
47 + } else {
48 + //error_log('MxChat: Missing class file - ' . $file);
49 + }
50 + }
51 +}
52 +
53 +/**
54 + * Create URL click tracking table
55 + */
56 +function mxchat_create_url_clicks_table() {
35 57 global $wpdb;
58 +
59 + $table_name = $wpdb->prefix . 'mxchat_url_clicks';
60 +
36 61 $charset_collate = $wpdb->get_charset_collate();
62 +
63 + $sql = "CREATE TABLE $table_name (
64 + id mediumint(9) NOT NULL AUTO_INCREMENT,
65 + session_id varchar(100) NOT NULL,
66 + clicked_url text NOT NULL,
67 + message_context text,
68 + click_timestamp datetime DEFAULT CURRENT_TIMESTAMP,
69 + user_ip varchar(45),
70 + user_agent text,
71 + PRIMARY KEY (id),
72 + KEY session_id (session_id),
73 + KEY click_timestamp (click_timestamp)
74 + ) $charset_collate;";
75 +
76 + require_once(ABSPATH . 'wp-admin/includes/upgrade.php');
77 + dbDelta($sql);
78 +}
37 79
38 - // Chat Transcripts Table
39 - $chat_transcripts_table = $wpdb->prefix . 'mxchat_chat_transcripts';
40 - $sql_chat_transcripts = "CREATE TABLE $chat_transcripts_table (
80 +/**
81 + * FIXED: Robust table creation and column management
82 + */
83 +function mxchat_create_chat_transcripts_table() {
84 + global $wpdb;
85 +
86 + $table_name = $wpdb->prefix . 'mxchat_chat_transcripts';
87 + $charset_collate = $wpdb->get_charset_collate();
88 +
89 + // Create table with ALL columns including user_name from the start
90 + $sql = "CREATE TABLE $table_name (
41 91 id MEDIUMINT(9) NOT NULL AUTO_INCREMENT,
42 92 user_id MEDIUMINT(9) DEFAULT 0,
43 93 session_id VARCHAR(255) NOT NULL,
44 94 role VARCHAR(255) NOT NULL,
@@ -43,25 +93,328 @@
43 93 session_id VARCHAR(255) NOT NULL,
44 94 role VARCHAR(255) NOT NULL,
45 95 message TEXT NOT NULL,
46 96 user_email VARCHAR(255) DEFAULT NULL,
97 + user_name VARCHAR(100) DEFAULT NULL,
98 + user_identifier VARCHAR(255) DEFAULT NULL,
99 + originating_page_url TEXT DEFAULT NULL,
100 + originating_page_title VARCHAR(500) DEFAULT NULL,
47 101 timestamp TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL,
48 - PRIMARY KEY (id)
102 + PRIMARY KEY (id),
103 + KEY session_id (session_id),
104 + KEY user_email (user_email),
105 + KEY timestamp (timestamp)
49 106 ) $charset_collate;";
107 +
108 + require_once(ABSPATH . 'wp-admin/includes/upgrade.php');
109 + $result = dbDelta($sql);
110 +
111 + // Log the result for debugging
112 + if (empty($result)) {
113 + //error_log("MxChat: dbDelta returned empty result for chat transcripts table");
114 + } else {
115 + //error_log("MxChat: dbDelta result: " . print_r($result, true));
116 + }
117 +
118 + // IMPORTANT: Ensure all columns exist for existing installations
119 + mxchat_ensure_all_columns($table_name);
120 +}
50 121
51 - // System Prompt Content Table
122 +/**
123 + * Ensure all required columns exist (for upgrades)
124 + */
125 +function mxchat_ensure_all_columns($table_name) {
126 + global $wpdb;
127 +
128 + // First check if table exists
129 + $table_exists = $wpdb->get_var("SHOW TABLES LIKE '$table_name'") === $table_name;
130 + if (!$table_exists) {
131 + //error_log("MxChat: Table $table_name does not exist, cannot add columns");
132 + return;
133 + }
134 +
135 + // Define all required columns and their types
136 + $required_columns = [
137 + 'user_identifier' => 'VARCHAR(255) DEFAULT NULL',
138 + 'user_email' => 'VARCHAR(255) DEFAULT NULL',
139 + 'user_name' => 'VARCHAR(100) DEFAULT NULL',
140 + 'originating_page_url' => 'TEXT DEFAULT NULL',
141 + 'originating_page_title' => 'VARCHAR(500) DEFAULT NULL'
142 + ];
143 +
144 + // Get existing columns
145 + $existing_columns = $wpdb->get_results("SHOW COLUMNS FROM $table_name");
146 + if (empty($existing_columns)) {
147 + //error_log("MxChat: Could not get columns for table $table_name");
148 + return;
149 + }
150 +
151 + $existing_column_names = array_column($existing_columns, 'Field');
152 +
153 + // Add missing columns
154 + foreach ($required_columns as $column_name => $column_definition) {
155 + if (!in_array($column_name, $existing_column_names)) {
156 + $alter_sql = "ALTER TABLE $table_name ADD COLUMN $column_name $column_definition";
157 + $result = $wpdb->query($alter_sql);
158 +
159 + if ($result === false) {
160 + //error_log("MxChat: Failed to add column $column_name to $table_name. Error: " . $wpdb->last_error);
161 + } else {
162 + //error_log("MxChat: Successfully added column $column_name to $table_name");
163 + }
164 + }
165 + }
166 +}
167 +
168 +/**
169 + * Add role restriction column to knowledge base table
170 + */
171 +function mxchat_add_role_restriction_column() {
172 + global $wpdb;
173 + $table_name = $wpdb->prefix . 'mxchat_system_prompt_content';
174 +
175 + // Check if table exists first
176 + $table_exists = $wpdb->get_var("SHOW TABLES LIKE '$table_name'") === $table_name;
177 + if (!$table_exists) {
178 + //error_log("MxChat: System prompt content table does not exist, cannot add role_restriction column");
179 + return;
180 + }
181 +
182 + // Check if column already exists
183 + $column_exists = $wpdb->get_results(
184 + $wpdb->prepare(
185 + "SHOW COLUMNS FROM {$table_name} LIKE %s",
186 + 'role_restriction'
187 + )
188 + );
189 +
190 + if (empty($column_exists)) {
191 + $alter_sql = "ALTER TABLE {$table_name} ADD COLUMN role_restriction VARCHAR(50) DEFAULT 'public' AFTER source_url";
192 + $result = $wpdb->query($alter_sql);
193 +
194 + if ($result === false) {
195 + //error_log("MxChat: Failed to add role_restriction column. Error: " . $wpdb->last_error);
196 + } else {
197 + //error_log("MxChat: Successfully added role_restriction column");
198 +
199 + // Set all existing records to 'public' (everyone can access)
200 + $update_result = $wpdb->query(
201 + "UPDATE {$table_name}
202 + SET role_restriction = 'public'
203 + WHERE role_restriction IS NULL OR role_restriction = ''"
204 + );
205 +
206 + if ($update_result !== false) {
207 + //error_log("MxChat: Updated {$update_result} existing records to public access");
208 + }
209 + }
210 + }
211 +}
212 +
213 +/**
214 + * Add enabled_bots column to intents table for multi-bot action filtering
215 + */
216 +function mxchat_add_enabled_bots_column() {
217 + global $wpdb;
218 + $table_name = $wpdb->prefix . 'mxchat_intents';
219 +
220 + // Check if table exists first
221 + $table_exists = $wpdb->get_var("SHOW TABLES LIKE '$table_name'") === $table_name;
222 + if (!$table_exists) {
223 + //error_log("MxChat: Intents table does not exist, cannot add enabled_bots column");
224 + return;
225 + }
226 +
227 + // Check if column already exists
228 + $column_exists = $wpdb->get_results(
229 + $wpdb->prepare(
230 + "SHOW COLUMNS FROM {$table_name} LIKE %s",
231 + 'enabled_bots'
232 + )
233 + );
234 +
235 + if (empty($column_exists)) {
236 + $alter_sql = "ALTER TABLE {$table_name} ADD COLUMN enabled_bots LONGTEXT DEFAULT NULL AFTER enabled";
237 + $result = $wpdb->query($alter_sql);
238 +
239 + if ($result === false) {
240 + //error_log("MxChat: Failed to add enabled_bots column. Error: " . $wpdb->last_error);
241 + } else {
242 + //error_log("MxChat: Successfully added enabled_bots column");
243 +
244 + // Set all existing actions to work with 'default' bot for backward compatibility
245 + $default_bots = json_encode(['default']);
246 + $update_result = $wpdb->query(
247 + $wpdb->prepare(
248 + "UPDATE {$table_name}
249 + SET enabled_bots = %s
250 + WHERE enabled_bots IS NULL OR enabled_bots = ''",
251 + $default_bots
252 + )
253 + );
254 +
255 + if ($update_result !== false) {
256 + //error_log("MxChat: Updated {$update_result} existing actions to work with default bot");
257 + }
258 + }
259 + }
260 +}
261 +
262 +/**
263 + * Create Pinecone role restrictions table
264 + */
265 +function mxchat_create_pinecone_roles_table() {
266 + global $wpdb;
267 +
268 + $table_name = $wpdb->prefix . 'mxchat_pinecone_roles';
269 + $charset_collate = $wpdb->get_charset_collate();
270 +
271 + $sql = "CREATE TABLE $table_name (
272 + id mediumint(9) NOT NULL AUTO_INCREMENT,
273 + vector_id varchar(255) NOT NULL,
274 + source_url text,
275 + role_restriction varchar(50) DEFAULT 'public',
276 + updated_at timestamp DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
277 + PRIMARY KEY (id),
278 + UNIQUE KEY vector_id (vector_id),
279 + KEY role_restriction (role_restriction)
280 + ) $charset_collate;";
281 +
282 + require_once(ABSPATH . 'wp-admin/includes/upgrade.php');
283 + dbDelta($sql);
284 +}
285 +
286 +/**
287 + * 2.5.2: Create queue processing tables for reliable background processing
288 + */
289 +function mxchat_create_queue_tables() {
290 + global $wpdb;
291 + $charset_collate = $wpdb->get_charset_collate();
292 +
293 + // Main queue table
294 + $queue_table = $wpdb->prefix . 'mxchat_processing_queue';
295 + $sql_queue = "CREATE TABLE $queue_table (
296 + id bigint(20) unsigned NOT NULL AUTO_INCREMENT,
297 + queue_id varchar(64) NOT NULL,
298 + item_type varchar(20) NOT NULL,
299 + item_data longtext NOT NULL,
300 + status varchar(20) NOT NULL DEFAULT 'pending',
301 + bot_id varchar(50) NOT NULL DEFAULT 'default',
302 + priority int(11) NOT NULL DEFAULT 0,
303 + attempts int(11) NOT NULL DEFAULT 0,
304 + max_attempts int(11) NOT NULL DEFAULT 3,
305 + error_message text DEFAULT NULL,
306 + created_at datetime NOT NULL,
307 + started_at datetime DEFAULT NULL,
308 + completed_at datetime DEFAULT NULL,
309 + PRIMARY KEY (id),
310 + KEY queue_id (queue_id),
311 + KEY status (status),
312 + KEY item_type (item_type),
313 + KEY priority (priority)
314 + ) $charset_collate;";
315 +
316 + // Queue metadata table
317 + $meta_table = $wpdb->prefix . 'mxchat_queue_meta';
318 + $sql_meta = "CREATE TABLE $meta_table (
319 + id bigint(20) unsigned NOT NULL AUTO_INCREMENT,
320 + queue_id varchar(64) NOT NULL,
321 + meta_key varchar(255) NOT NULL,
322 + meta_value longtext,
323 + PRIMARY KEY (id),
324 + KEY queue_id (queue_id),
325 + KEY meta_key (meta_key)
326 + ) $charset_collate;";
327 +
328 + require_once(ABSPATH . 'wp-admin/includes/upgrade.php');
329 + dbDelta($sql_queue);
330 + dbDelta($sql_meta);
331 +
332 + //error_log("MxChat: Queue tables created/updated successfully");
333 +}
334 +
335 +/**
336 + * 2.5.2: Fix URL column size to support long URLs (especially with UTF-8 encoding)
337 + * This fixes "url, source_url. The supplied values may be too long" errors
338 + */
339 +function mxchat_fix_url_column_size() {
340 + global $wpdb;
341 + $table_name = $wpdb->prefix . 'mxchat_system_prompt_content';
342 +
343 + // Check if table exists
344 + $table_exists = $wpdb->get_var("SHOW TABLES LIKE '$table_name'") === $table_name;
345 + if (!$table_exists) {
346 + return;
347 + }
348 +
349 + // Change url and source_url from VARCHAR to TEXT to handle long URLs
350 + // This is especially important for URLs with UTF-8 encoded characters (Hebrew, Arabic, etc.)
351 + $wpdb->query("ALTER TABLE {$table_name} MODIFY COLUMN url TEXT");
352 + $wpdb->query("ALTER TABLE {$table_name} MODIFY COLUMN source_url TEXT");
353 +
354 + //error_log("MxChat: Successfully updated url and source_url columns to TEXT type for long URL support");
355 +}
356 +
357 +/**
358 + * Migrate deprecated AI models to their replacements
359 + * Version 2.5.1: Migrate Claude 3.5 Sonnet (deprecated) to Claude 3.7 Sonnet
360 + */
361 +function mxchat_migrate_deprecated_models() {
362 + $options = get_option('mxchat_options', array());
363 +
364 + // Check if model is set and is the deprecated Claude 3.5 Sonnet
365 + if (isset($options['model']) && $options['model'] === 'claude-3-5-sonnet-20241022') {
366 + // Update to Claude 3.7 Sonnet (the replacement model)
367 + $options['model'] = 'claude-3-7-sonnet-20250219';
368 + update_option('mxchat_options', $options);
369 +
370 + // Set a flag to show admin notice
371 + update_option('mxchat_model_migrated_notice', true);
372 +
373 + //error_log('MxChat: Migrated deprecated Claude 3.5 Sonnet to Claude 3.7 Sonnet');
374 + }
375 +}
376 +
377 +/**
378 + * Show admin notice after model migration
379 + */
380 +function mxchat_show_migration_notice() {
381 + if (get_option('mxchat_model_migrated_notice')) {
382 + ?>
383 + <div class="notice notice-info is-dismissible">
384 + <p>
385 + <strong><?php esc_html_e('MxChat Model Updated', 'mxchat'); ?></strong><br>
386 + <?php esc_html_e('Your chatbot model has been automatically updated from Claude 3.5 Sonnet to Claude 3.7 Sonnet due to the deprecation of the previous model by Anthropic. Claude 3.7 Sonnet offers improved performance and capabilities.', 'mxchat'); ?>
387 + </p>
388 + </div>
389 + <?php
390 + delete_option('mxchat_model_migrated_notice');
391 + }
392 +}
393 +
394 +function mxchat_activate() {
395 + global $wpdb;
396 + $charset_collate = $wpdb->get_charset_collate();
397 +
398 + //error_log("MxChat: Running activation function");
399 +
400 + // Create chat transcripts table with improved function
401 + mxchat_create_chat_transcripts_table();
402 +
403 + // System Prompt Content Table - UPDATED: Use TEXT for url and source_url columns
52 404 $system_prompt_table = $wpdb->prefix . 'mxchat_system_prompt_content';
53 405 $sql_system_prompt = "CREATE TABLE $system_prompt_table (
54 406 id MEDIUMINT(9) NOT NULL AUTO_INCREMENT,
55 - url VARCHAR(255) NOT NULL,
407 + url TEXT NOT NULL,
56 408 article_content LONGTEXT NOT NULL,
57 409 embedding_vector LONGTEXT,
58 - source_url VARCHAR(255) DEFAULT NULL,
410 + source_url TEXT DEFAULT NULL,
411 + role_restriction VARCHAR(50) DEFAULT 'public',
59 412 timestamp TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL,
60 413 PRIMARY KEY (id)
61 414 ) $charset_collate;";
62 415
63 - // Intents Table
416 + // Intents Table - NOW INCLUDES enabled_bots column from the start
64 417 $intents_table = $wpdb->prefix . 'mxchat_intents';
65 418 $sql_intents_table = "CREATE TABLE $intents_table (
66 419 id BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT,
67 420 intent_label VARCHAR(255) NOT NULL,
@@ -68,51 +421,294 @@
68 421 phrases TEXT NOT NULL,
69 422 embedding_vector LONGTEXT NOT NULL,
70 423 callback_function VARCHAR(255) NOT NULL,
71 424 similarity_threshold FLOAT DEFAULT 0.85,
425 + enabled TINYINT(1) NOT NULL DEFAULT 1,
426 + enabled_bots LONGTEXT DEFAULT NULL,
72 427 PRIMARY KEY (id)
73 428 ) $charset_collate;";
74 429
75 430 require_once ABSPATH . 'wp-admin/includes/upgrade.php';
76 431
77 - // Create or update tables
78 - dbDelta($sql_chat_transcripts);
432 + // Create other tables
79 433 dbDelta($sql_system_prompt);
80 434 dbDelta($sql_intents_table);
81 435
82 - // Ensure additional columns in `mxchat_chat_transcripts`
83 - mxchat_add_missing_columns($chat_transcripts_table, 'user_identifier', 'VARCHAR(255)');
84 - mxchat_add_missing_columns($chat_transcripts_table, 'user_email', 'VARCHAR(255) DEFAULT NULL');
436 + // Create URL click tracking table
437 + mxchat_create_url_clicks_table();
438 +
439 + // Create Pinecone roles table
440 + mxchat_create_pinecone_roles_table();
441 +
442 + // NEW 2.5.2: Create queue processing tables
443 + mxchat_create_queue_tables();
85 444
86 - // Ensure additional columns in `mxchat_system_prompt_content`
87 - mxchat_add_missing_columns($system_prompt_table, 'embedding_vector', 'LONGTEXT');
88 - mxchat_add_missing_columns($system_prompt_table, 'source_url', 'VARCHAR(255) DEFAULT NULL');
445 + // Ensure additional columns in system prompt table
446 + $existing_system_columns = $wpdb->get_results("SHOW COLUMNS FROM $system_prompt_table");
447 + if (!empty($existing_system_columns)) {
448 + $existing_system_column_names = array_column($existing_system_columns, 'Field');
449 +
450 + if (!in_array('embedding_vector', $existing_system_column_names)) {
451 + $wpdb->query("ALTER TABLE $system_prompt_table ADD COLUMN embedding_vector LONGTEXT");
452 + }
453 + if (!in_array('source_url', $existing_system_column_names)) {
454 + $wpdb->query("ALTER TABLE $system_prompt_table ADD COLUMN source_url TEXT DEFAULT NULL");
455 + }
456 + if (!in_array('role_restriction', $existing_system_column_names)) {
457 + $wpdb->query("ALTER TABLE $system_prompt_table ADD COLUMN role_restriction VARCHAR(50) DEFAULT 'public' AFTER source_url");
458 + }
459 + }
89 460
90 461 // Set default thresholds for existing intents
91 462 $wpdb->query("UPDATE {$intents_table} SET similarity_threshold = 0.85 WHERE similarity_threshold IS NULL");
463 +
464 + // Ensure enabled column exists in intents table
465 + $existing_intent_columns = $wpdb->get_results("SHOW COLUMNS FROM $intents_table");
466 + if (!empty($existing_intent_columns)) {
467 + $existing_intent_column_names = array_column($existing_intent_columns, 'Field');
468 +
469 + if (!in_array('enabled', $existing_intent_column_names)) {
470 + $wpdb->query("ALTER TABLE $intents_table ADD COLUMN enabled TINYINT(1) NOT NULL DEFAULT 1");
471 + }
472 +
473 + // Ensure enabled_bots column exists for existing installations
474 + if (!in_array('enabled_bots', $existing_intent_column_names)) {
475 + $wpdb->query("ALTER TABLE $intents_table ADD COLUMN enabled_bots LONGTEXT DEFAULT NULL AFTER enabled");
476 +
477 + // Set existing actions to work with default bot
478 + $default_bots = json_encode(['default']);
479 + $wpdb->query($wpdb->prepare(
480 + "UPDATE {$intents_table} SET enabled_bots = %s WHERE enabled_bots IS NULL",
481 + $default_bots
482 + ));
483 + }
484 + }
92 485
93 - // Update plugin version in the database
94 - update_option('mxchat_plugin_version', '2.0.4');
486 + // Setup cron jobs
487 + mxchat_setup_cron_jobs();
488 +
489 + // Update version
490 + update_option('mxchat_plugin_version', MXCHAT_VERSION);
491 +
492 + //error_log("MxChat: Activation function completed");
95 493 }
96 494
495 +/**
496 + * Setup cron jobs on plugin activation
497 + */
498 +function mxchat_setup_cron_jobs() {
499 + // Clear any existing cron jobs first
500 + wp_clear_scheduled_hook('mxchat_reset_rate_limits');
501 +
502 + // Check if WordPress cron is disabled
503 + if (defined('DISABLE_WP_CRON') && DISABLE_WP_CRON) {
504 + // Set flag to use fallback system
505 + update_option('mxchat_use_fallback_rate_limits', true);
506 + update_option('mxchat_next_rate_limit_check', time() + 3600);
507 + return;
508 + }
509 +
510 + // Schedule the rate limit reset cron job
511 + $result = wp_schedule_event(time() + 300, 'hourly', 'mxchat_reset_rate_limits');
512 +
513 + if ($result === false) {
514 + // Fallback if scheduling fails
515 + update_option('mxchat_use_fallback_rate_limits', true);
516 + update_option('mxchat_next_rate_limit_check', time() + 3600);
517 + } else {
518 + // Clear fallback flags if cron scheduling succeeded
519 + delete_option('mxchat_use_fallback_rate_limits');
520 + }
521 +}
97 522
98 -function mxchat_add_missing_columns($table, $column_name, $column_type) {
523 +/**
524 + * Clean up on plugin deactivation
525 + */
526 +function mxchat_deactivate() {
527 + // Clear scheduled cron jobs
528 + wp_clear_scheduled_hook('mxchat_reset_rate_limits');
529 +
530 + // Clear fallback options
531 + delete_option('mxchat_use_fallback_rate_limits');
532 + delete_option('mxchat_next_rate_limit_check');
533 + delete_option('mxchat_fallback_check_interval');
534 +
535 + // NOTE: We do NOT delete queue tables on deactivation
536 + // This preserves data if user accidentally deactivates the plugin
537 +}
538 +
539 +/**
540 + * Check if fallback rate limit cleanup is needed
541 + */
542 +function mxchat_check_fallback_rate_limits() {
543 + $use_fallback = get_option('mxchat_use_fallback_rate_limits', false);
544 +
545 + if (!$use_fallback) {
546 + return;
547 + }
548 +
549 + $next_check = get_option('mxchat_next_rate_limit_check', 0);
550 +
551 + if (time() >= $next_check) {
552 + // Only run reset if the MxChat_Integrator class exists
553 + if (class_exists('MxChat_Integrator')) {
554 + $integrator = new MxChat_Integrator();
555 + if (method_exists($integrator, 'mxchat_reset_rate_limits')) {
556 + $integrator->mxchat_reset_rate_limits();
557 + update_option('mxchat_next_rate_limit_check', time() + 3600);
558 + }
559 + }
560 + }
561 +}
562 +
563 +/**
564 + * Robust update checking with role restriction migration, model deprecation, and queue tables
565 + * CRITICAL: This runs on EVERY page load to ensure tables exist
566 + */
567 +function mxchat_check_for_update() {
99 568 global $wpdb;
100 - $column_exists = $wpdb->get_results($wpdb->prepare("SHOW COLUMNS FROM $table LIKE %s", $column_name));
101 - if (empty($column_exists)) {
102 - $wpdb->query("ALTER TABLE $table ADD COLUMN $column_name $column_type");
569 +
570 + try {
571 + $current_version = get_option('mxchat_plugin_version', '0.0.0');
572 + $plugin_version = MXCHAT_VERSION;
573 +
574 + // Always ensure critical tables exist (even if version matches)
575 + // This handles manual table deletion or fresh installs
576 + $chat_table = $wpdb->prefix . 'mxchat_chat_transcripts';
577 + $queue_table = $wpdb->prefix . 'mxchat_processing_queue';
578 +
579 + $chat_exists = $wpdb->get_var("SHOW TABLES LIKE '$chat_table'") === $chat_table;
580 + $queue_exists = $wpdb->get_var("SHOW TABLES LIKE '$queue_table'") === $queue_table;
581 +
582 + if (!$chat_exists || !$queue_exists) {
583 + //error_log("MxChat: Critical tables missing, running activation");
584 + mxchat_activate();
585 + }
586 +
587 + // Version-specific migrations
588 + if ($current_version !== $plugin_version) {
589 + //error_log("MxChat: Version change detected: $current_version -> $plugin_version");
590 +
591 + // Run live agent update BEFORE updating the stored version
592 + mxchat_handle_live_agent_update();
593 +
594 + // Run role restriction migration for 2.4.1
595 + if (version_compare($current_version, '2.4.1', '<')) {
596 + mxchat_add_role_restriction_column();
597 + }
598 +
599 + // Run enabled_bots column migration for 2.4.4
600 + if (version_compare($current_version, '2.4.4', '<')) {
601 + mxchat_add_enabled_bots_column();
602 + }
603 +
604 + // Run model migration for 2.5.1 (Claude deprecation)
605 + if (version_compare($current_version, '2.5.1', '<')) {
606 + mxchat_migrate_deprecated_models();
607 + }
608 +
609 + // 2.5.2: Ensure queue tables exist and fix URL column sizes for all users upgrading to 2.5.2
610 + if (version_compare($current_version, '2.5.2', '<')) {
611 + mxchat_create_queue_tables();
612 + mxchat_fix_url_column_size(); // NEW: Fix URL column size for long URLs
613 + //error_log("MxChat: Queue tables created and URL columns updated for upgrade to 2.5.2");
614 + }
615 +
616 + // Run full activation to ensure everything is up to date
617 + mxchat_activate();
618 +
619 + // Run migration functions
620 + mxchat_migrate_live_agent_status();
621 +
622 + // Add the cleanup function for version 2.1.8
623 + if (version_compare($current_version, '2.1.8', '<')) {
624 + $deleted = mxchat_cleanup_orphaned_chat_history();
625 + }
626 +
627 + // Update version LAST
628 + update_option('mxchat_plugin_version', $plugin_version);
629 +
630 + //error_log("MxChat: Updated from version $current_version to $plugin_version");
631 + }
632 +
633 + } catch (Exception $e) {
634 + //error_log('MxChat update error: ' . $e->getMessage());
635 + // Don't update version if there was an error
103 636 }
104 637 }
105 638
106 -function mxchat_check_for_update() {
107 - $current_version = get_option('mxchat_plugin_version');
108 - $plugin_version = '2.0.4'; // Update with your latest version
639 +/**
640 + * Ensure tables exist on every admin load for fresh installations
641 + * This is a safety net for cases where activation hook doesn't fire
642 + */
643 +function mxchat_ensure_tables_exist() {
644 + global $wpdb;
645 +
646 + // Only run for admin users to avoid performance impact
647 + if (!current_user_can('administrator')) {
648 + return;
649 + }
650 +
651 + // Check if we've already verified tables in this session
652 + static $tables_checked = false;
653 + if ($tables_checked) {
654 + return;
655 + }
656 + $tables_checked = true;
657 +
658 + $table_name = $wpdb->prefix . 'mxchat_chat_transcripts';
659 + $queue_table = $wpdb->prefix . 'mxchat_processing_queue';
660 +
661 + $chat_exists = $wpdb->get_var("SHOW TABLES LIKE '$table_name'") === $table_name;
662 + $queue_exists = $wpdb->get_var("SHOW TABLES LIKE '$queue_table'") === $queue_table;
663 +
664 + if (!$chat_exists || !$queue_exists) {
665 + //error_log("MxChat: Tables missing on admin load, running activation");
666 + mxchat_activate();
667 + }
668 +}
109 669
110 - if ($current_version !== $plugin_version) {
111 - mxchat_activate(); // Run the activation script to apply schema changes
112 - mxchat_migrate_live_agent_status(); // Add migration for live agent status
113 - update_option('mxchat_plugin_version', $plugin_version); // Update the version
670 +/**
671 + * Clean up orphaned chat history options from the wp_options table
672 + * @return int Number of options deleted
673 + */
674 +function mxchat_cleanup_orphaned_chat_history() {
675 + global $wpdb;
676 + $count = 0;
677 +
678 + // Get all option keys that match our pattern
679 + $history_options = $wpdb->get_results(
680 + "SELECT option_name FROM {$wpdb->options}
681 + WHERE option_name LIKE 'mxchat_history_%'"
682 + );
683 +
684 + if (!empty($history_options)) {
685 + foreach ($history_options as $option) {
686 + // Extract the session ID from the option name
687 + $session_id = str_replace('mxchat_history_', '', $option->option_name);
688 +
689 + // Check if this session still exists in the custom table
690 + $table_name = $wpdb->prefix . 'mxchat_chat_transcripts';
691 + $exists = $wpdb->get_var(
692 + $wpdb->prepare(
693 + "SELECT COUNT(*) FROM {$table_name} WHERE session_id = %s",
694 + $session_id
695 + )
696 + );
697 +
698 + // If session doesn't exist in the main table, delete the option
699 + if ($exists == 0) {
700 + delete_option($option->option_name);
701 + // Also delete related metadata
702 + delete_option("mxchat_email_{$session_id}");
703 + delete_option("mxchat_name_{$session_id}");
704 + delete_option("mxchat_agent_name_{$session_id}");
705 + $count++;
706 + }
707 + }
114 708 }
709 +
710 + return $count;
115 711 }
116 712
117 713 function mxchat_migrate_live_agent_status() {
118 714 $options = get_option('mxchat_options', []);
@@ -145,16 +741,101 @@
145 741 update_option('mxchat_options', $options);
146 742 }
147 743 }
148 744
745 +function mxchat_handle_live_agent_update() {
746 + // Get the CURRENT stored version (before it gets updated)
747 + $current_version = get_option('mxchat_plugin_version', '0.0.0');
748 + $new_version = '2.2.2';
749 +
750 + // Only run this once for the update to 2.2.2
751 + $update_handled = get_option('mxchat_live_agent_update_2_2_2_handled', false);
752 +
753 + // Check if we're upgrading TO 2.2.2 and haven't handled this yet
754 + if (version_compare($current_version, $new_version, '<') && !$update_handled) {
755 + $options = get_option('mxchat_options', array());
756 +
757 + // Check if live agent was previously enabled
758 + if (isset($options['live_agent_status']) && $options['live_agent_status'] === 'on') {
759 + // Disable live agent
760 + $options['live_agent_status'] = 'off';
761 + update_option('mxchat_options', $options);
762 +
763 + // Set flag to show the notification banner
764 + update_option('mxchat_show_live_agent_disabled_notice', true);
765 + }
766 +
767 + // Mark this update as handled
768 + update_option('mxchat_live_agent_update_2_2_2_handled', true);
769 + }
770 +}
149 771
150 -// Run the update check function on every request
151 -add_action('plugins_loaded', 'mxchat_check_for_update');
772 +// Initialize plugin safely
773 +function mxchat_init() {
774 + // Include all class files first
775 + mxchat_include_classes();
776 +
777 + // Run update check (this also ensures tables exist)
778 + mxchat_check_for_update();
779 +
780 + // CRITICAL: Ensure tables exist on admin pages (safety net)
781 + add_action('admin_init', 'mxchat_ensure_tables_exist', 1);
782 +
783 + // Add fallback rate limit check
784 + add_action('init', 'mxchat_check_fallback_rate_limits', 5);
785 +
786 + // Add migration notice hook
787 + add_action('admin_notices', 'mxchat_show_migration_notice');
788 +
789 + // Initialize classes with error handling
790 + try {
791 + // Initialize admin classes
792 + if (is_admin()) {
793 + if (class_exists('MxChat_Knowledge_Manager')) {
794 + $mxchat_knowledge_manager = new MxChat_Knowledge_Manager();
795 +
796 + if (class_exists('MxChat_Admin')) {
797 + $mxchat_admin = new MxChat_Admin($mxchat_knowledge_manager);
798 + }
799 + }
800 +
801 + // Initialize meta box class
802 + if (class_exists('MxChat_Meta_Box')) {
803 + new MxChat_Meta_Box();
804 + }
805 + }
806 +
807 + // Initialize public classes
808 + if (class_exists('MxChat_Public')) {
809 + $mxchat_public = new MxChat_Public();
810 + }
811 +
812 + if (class_exists('MxChat_Integrator')) {
813 + $mxchat_integrator = new MxChat_Integrator();
814 + }
815 +
816 + } catch (Exception $e) {
817 + //error_log('MxChat initialization error: ' . $e->getMessage());
818 +
819 + // Show admin notice if there's an error
820 + if (is_admin()) {
821 + add_action('admin_notices', function() use ($e) {
822 + echo '<div class="notice notice-error"><p>';
823 + echo '<strong>MxChat Error:</strong> Plugin initialization failed. ';
824 + echo 'Please check error logs or contact support. Error: ' . esc_html($e->getMessage());
825 + echo '</p></div>';
826 + });
827 + }
828 + }
829 +}
152 830
831 +// Run initialization on plugins_loaded
832 +add_action('plugins_loaded', 'mxchat_init');
833 +
153 834 // Register activation hook
154 835 register_activation_hook(__FILE__, 'mxchat_activate');
155 836
156 -
837 +// Add cron schedule
157 838 add_filter('cron_schedules', function($schedules) {
158 839 $schedules['one_minute'] = array(
159 840 'interval' => 60,
160 841 'display' => 'Every Minute'
@@ -161,16 +842,6 @@
161 842 );
162 843 return $schedules;
163 844 });
164 845
165 -add_action('init', function() {
166 - add_action('mxchat_process_pdf_pages', array('MxChat_Admin', 'process_pdf_pages_cron'), 10, 5);
167 - add_action('mxchat_process_sitemap_urls', array('MxChat_Admin', 'process_sitemap_urls_cron'), 10, 5);
168 -});
169 -
170 -
171 -// Instantiate classes
172 -if (is_admin()) {
173 - $mxchat_admin = new MxChat_Admin();
174 -}
175 -$mxchat_public = new MxChat_Public();
176 -$mxchat_integrator = new MxChat_Integrator();
846 +// Register deactivation hook
847 +register_deactivation_hook(__FILE__, 'mxchat_deactivate');