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
mxchat-basic / mxchat-basic.php

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

847 lines 30.7 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.2
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 define('MXCHAT_VERSION', '2.5.2');
21
22 function mxchat_load_textdomain() {
23 load_plugin_textdomain('mxchat', false, dirname(plugin_basename(__FILE__)) . '/languages');
24 }
25 add_action('init', 'mxchat_load_textdomain');
26
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 );
42
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() {
57 global $wpdb;
58
59 $table_name = $wpdb->prefix . 'mxchat_url_clicks';
60
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 }
79
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 (
91 id MEDIUMINT(9) NOT NULL AUTO_INCREMENT,
92 user_id MEDIUMINT(9) DEFAULT 0,
93 session_id VARCHAR(255) NOT NULL,
94 role VARCHAR(255) NOT NULL,
95 message TEXT NOT NULL,
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,
101 timestamp TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL,
102 PRIMARY KEY (id),
103 KEY session_id (session_id),
104 KEY user_email (user_email),
105 KEY timestamp (timestamp)
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 }
121
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
404 $system_prompt_table = $wpdb->prefix . 'mxchat_system_prompt_content';
405 $sql_system_prompt = "CREATE TABLE $system_prompt_table (
406 id MEDIUMINT(9) NOT NULL AUTO_INCREMENT,
407 url TEXT NOT NULL,
408 article_content LONGTEXT NOT NULL,
409 embedding_vector LONGTEXT,
410 source_url TEXT DEFAULT NULL,
411 role_restriction VARCHAR(50) DEFAULT 'public',
412 timestamp TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL,
413 PRIMARY KEY (id)
414 ) $charset_collate;";
415
416 // Intents Table - NOW INCLUDES enabled_bots column from the start
417 $intents_table = $wpdb->prefix . 'mxchat_intents';
418 $sql_intents_table = "CREATE TABLE $intents_table (
419 id BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT,
420 intent_label VARCHAR(255) NOT NULL,
421 phrases TEXT NOT NULL,
422 embedding_vector LONGTEXT NOT NULL,
423 callback_function VARCHAR(255) NOT NULL,
424 similarity_threshold FLOAT DEFAULT 0.85,
425 enabled TINYINT(1) NOT NULL DEFAULT 1,
426 enabled_bots LONGTEXT DEFAULT NULL,
427 PRIMARY KEY (id)
428 ) $charset_collate;";
429
430 require_once ABSPATH . 'wp-admin/includes/upgrade.php';
431
432 // Create other tables
433 dbDelta($sql_system_prompt);
434 dbDelta($sql_intents_table);
435
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();
444
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 }
460
461 // Set default thresholds for existing intents
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 }
485
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");
493 }
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 }
522
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() {
568 global $wpdb;
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
636 }
637 }
638
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 }
669
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 }
708 }
709
710 return $count;
711 }
712
713 function mxchat_migrate_live_agent_status() {
714 $options = get_option('mxchat_options', []);
715
716 // Check if live_agent_status exists
717 if (isset($options['live_agent_status'])) {
718 $current_status = $options['live_agent_status'];
719 $needs_update = false;
720
721 // Convert to new format if needed
722 if ($current_status === 'online') {
723 $options['live_agent_status'] = 'on';
724 $needs_update = true;
725 } else if ($current_status === 'offline') {
726 $options['live_agent_status'] = 'off';
727 $needs_update = true;
728 } else if (!in_array($current_status, ['on', 'off'])) {
729 // Default to off for any unexpected values
730 $options['live_agent_status'] = 'off';
731 $needs_update = true;
732 }
733
734 // Only update if needed
735 if ($needs_update) {
736 update_option('mxchat_options', $options);
737 }
738 } else {
739 // If status doesn't exist, set default to off
740 $options['live_agent_status'] = 'off';
741 update_option('mxchat_options', $options);
742 }
743 }
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 }
771
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 }
830
831 // Run initialization on plugins_loaded
832 add_action('plugins_loaded', 'mxchat_init');
833
834 // Register activation hook
835 register_activation_hook(__FILE__, 'mxchat_activate');
836
837 // Add cron schedule
838 add_filter('cron_schedules', function($schedules) {
839 $schedules['one_minute'] = array(
840 'interval' => 60,
841 'display' => 'Every Minute'
842 );
843 return $schedules;
844 });
845
846 // Register deactivation hook
847 register_deactivation_hook(__FILE__, 'mxchat_deactivate');