PluginProbe
MxChat – AI Chatbot & Content Generation for WordPress / 2.5.5
MxChat – AI Chatbot & Content Generation for WordPress v2.5.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
mxchat-basic / mxchat-basic.php

mxchat-basic.php in MxChat – AI Chatbot & Content Generation for WordPress 2.5.5, at mxchat-basic.php

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