PluginProbe
MxChat – AI Chatbot & Content Generation for WordPress / 2.3.2
MxChat – AI Chatbot & Content Generation for WordPress v2.3.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.3.2, at mxchat-basic.php

388 lines 13.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 * Description: AI chatbot for WordPress with OpenAI, Claude, xAI, DeepSeek, live agent, PDF uploads, WooCommerce, and training on website data.
5 * Version: 2.3.2
6 * Author: MxChat
7 * Author URI: https://mxchat.ai
8 * License: GPLv2 or later
9 * License URI: https://www.gnu.org/licenses/gpl-2.0.html
10 * Text Domain: mxchat
11 * Domain Path: /languages
12 */
13
14 if (!defined('ABSPATH')) {
15 exit; // Exit if accessed directly.
16 }
17
18 // Define plugin version constant for asset versioning
19 define('MXCHAT_VERSION', '2.3.2');
20
21 function mxchat_load_textdomain() {
22 load_plugin_textdomain('mxchat', false, dirname(plugin_basename(__FILE__)) . '/languages');
23 }
24 add_action('plugins_loaded', 'mxchat_load_textdomain');
25
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 );
40
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 function mxchat_activate() {
52 global $wpdb;
53 $charset_collate = $wpdb->get_charset_collate();
54
55 // Chat Transcripts Table
56 $chat_transcripts_table = $wpdb->prefix . 'mxchat_chat_transcripts';
57 $sql_chat_transcripts = "CREATE TABLE $chat_transcripts_table (
58 id MEDIUMINT(9) NOT NULL AUTO_INCREMENT,
59 user_id MEDIUMINT(9) DEFAULT 0,
60 session_id VARCHAR(255) NOT NULL,
61 role VARCHAR(255) NOT NULL,
62 message TEXT NOT NULL,
63 user_email VARCHAR(255) DEFAULT NULL,
64 timestamp TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL,
65 PRIMARY KEY (id)
66 ) $charset_collate;";
67
68 // System Prompt Content Table
69 $system_prompt_table = $wpdb->prefix . 'mxchat_system_prompt_content';
70 $sql_system_prompt = "CREATE TABLE $system_prompt_table (
71 id MEDIUMINT(9) NOT NULL AUTO_INCREMENT,
72 url VARCHAR(255) NOT NULL,
73 article_content LONGTEXT NOT NULL,
74 embedding_vector LONGTEXT,
75 source_url VARCHAR(255) DEFAULT NULL,
76 timestamp TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL,
77 PRIMARY KEY (id)
78 ) $charset_collate;";
79
80 // Intents Table
81 $intents_table = $wpdb->prefix . 'mxchat_intents';
82 $sql_intents_table = "CREATE TABLE $intents_table (
83 id BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT,
84 intent_label VARCHAR(255) NOT NULL,
85 phrases TEXT NOT NULL,
86 embedding_vector LONGTEXT NOT NULL,
87 callback_function VARCHAR(255) NOT NULL,
88 similarity_threshold FLOAT DEFAULT 0.85,
89 PRIMARY KEY (id)
90 ) $charset_collate;";
91
92 require_once ABSPATH . 'wp-admin/includes/upgrade.php';
93
94 // Create or update tables
95 dbDelta($sql_chat_transcripts);
96 dbDelta($sql_system_prompt);
97 dbDelta($sql_intents_table);
98
99 // Ensure additional columns in `mxchat_chat_transcripts`
100 mxchat_add_missing_columns($chat_transcripts_table, 'user_identifier', 'VARCHAR(255)');
101 mxchat_add_missing_columns($chat_transcripts_table, 'user_email', 'VARCHAR(255) DEFAULT NULL');
102
103 // Ensure additional columns in `mxchat_system_prompt_content`
104 mxchat_add_missing_columns($system_prompt_table, 'embedding_vector', 'LONGTEXT');
105 mxchat_add_missing_columns($system_prompt_table, 'source_url', 'VARCHAR(255) DEFAULT NULL');
106
107 // Set default thresholds for existing intents
108 $wpdb->query("UPDATE {$intents_table} SET similarity_threshold = 0.85 WHERE similarity_threshold IS NULL");
109 mxchat_add_missing_columns($intents_table, 'enabled', 'TINYINT(1) NOT NULL DEFAULT 1');
110
111 // SETUP CRON JOB HERE (ONCE ON ACTIVATION)
112 mxchat_setup_cron_jobs();
113
114 // Use the constant instead of hardcoded version
115 update_option('mxchat_plugin_version', MXCHAT_VERSION);
116 }
117
118 /**
119 * Setup cron jobs on plugin activation
120 */
121 function mxchat_setup_cron_jobs() {
122 // Clear any existing cron jobs first
123 wp_clear_scheduled_hook('mxchat_reset_rate_limits');
124
125 // Check if WordPress cron is disabled
126 if (defined('DISABLE_WP_CRON') && DISABLE_WP_CRON) {
127 // Set flag to use fallback system
128 update_option('mxchat_use_fallback_rate_limits', true);
129 update_option('mxchat_next_rate_limit_check', time() + 3600);
130 error_log('MxChat: WordPress cron disabled, using fallback system');
131 return;
132 }
133
134 // Schedule the rate limit reset cron job
135 $result = wp_schedule_event(time() + 300, 'hourly', 'mxchat_reset_rate_limits');
136
137 if ($result === false) {
138 // Fallback if scheduling fails
139 update_option('mxchat_use_fallback_rate_limits', true);
140 update_option('mxchat_next_rate_limit_check', time() + 3600);
141 error_log('MxChat: Failed to schedule cron on activation, using fallback');
142 } else {
143 // Clear fallback flags if cron scheduling succeeded
144 delete_option('mxchat_use_fallback_rate_limits');
145 error_log('MxChat: Successfully scheduled cron on activation');
146 }
147 }
148
149 /**
150 * Clean up on plugin deactivation
151 */
152 function mxchat_deactivate() {
153 // Clear scheduled cron jobs
154 wp_clear_scheduled_hook('mxchat_reset_rate_limits');
155
156 // Clear fallback options
157 delete_option('mxchat_use_fallback_rate_limits');
158 delete_option('mxchat_next_rate_limit_check');
159 delete_option('mxchat_fallback_check_interval');
160
161 error_log('MxChat: Cleaned up cron jobs on deactivation');
162 }
163
164 /**
165 * Check if fallback rate limit cleanup is needed
166 */
167 function mxchat_check_fallback_rate_limits() {
168 $use_fallback = get_option('mxchat_use_fallback_rate_limits', false);
169
170 if (!$use_fallback) {
171 return;
172 }
173
174 $next_check = get_option('mxchat_next_rate_limit_check', 0);
175
176 if (time() >= $next_check) {
177 // Only run reset if the MxChat_Integrator class exists
178 if (class_exists('MxChat_Integrator')) {
179 $integrator = new MxChat_Integrator();
180 if (method_exists($integrator, 'mxchat_reset_rate_limits')) {
181 $integrator->mxchat_reset_rate_limits();
182 update_option('mxchat_next_rate_limit_check', time() + 3600);
183 }
184 }
185 }
186 }
187
188 function mxchat_add_missing_columns($table, $column_name, $column_type) {
189 global $wpdb;
190 $column_exists = $wpdb->get_results($wpdb->prepare("SHOW COLUMNS FROM $table LIKE %s", $column_name));
191 if (empty($column_exists)) {
192 $wpdb->query("ALTER TABLE $table ADD COLUMN $column_name $column_type");
193 }
194 }
195
196 function mxchat_check_for_update() {
197 try {
198 $current_version = get_option('mxchat_plugin_version');
199 $plugin_version = MXCHAT_VERSION;
200
201 if ($current_version !== $plugin_version) {
202 // Run live agent update BEFORE updating the stored version
203 mxchat_handle_live_agent_update();
204
205 // Run existing update processes
206 mxchat_activate();
207 mxchat_migrate_live_agent_status();
208
209 // Add the new cleanup function for version 2.1.8
210 if (version_compare($current_version, '2.1.8', '<')) {
211 $deleted = mxchat_cleanup_orphaned_chat_history();
212 }
213
214 // Update version LAST so the live agent update logic can work
215 update_option('mxchat_plugin_version', $plugin_version);
216 }
217 } catch (Exception $e) {
218 error_log('MxChat update error: ' . $e->getMessage());
219 // Don't update version if there was an error
220 }
221 }
222
223 /**
224 * Clean up orphaned chat history options from the wp_options table
225 * @return int Number of options deleted
226 */
227 function mxchat_cleanup_orphaned_chat_history() {
228 global $wpdb;
229 $count = 0;
230
231 // Get all option keys that match our pattern
232 $history_options = $wpdb->get_results(
233 "SELECT option_name FROM {$wpdb->options}
234 WHERE option_name LIKE 'mxchat_history_%'"
235 );
236
237 if (!empty($history_options)) {
238 foreach ($history_options as $option) {
239 // Extract the session ID from the option name
240 $session_id = str_replace('mxchat_history_', '', $option->option_name);
241
242 // Check if this session still exists in the custom table
243 $table_name = $wpdb->prefix . 'mxchat_chat_transcripts';
244 $exists = $wpdb->get_var(
245 $wpdb->prepare(
246 "SELECT COUNT(*) FROM {$table_name} WHERE session_id = %s",
247 $session_id
248 )
249 );
250
251 // If session doesn't exist in the main table, delete the option
252 if ($exists == 0) {
253 delete_option($option->option_name);
254 // Also delete related metadata
255 delete_option("mxchat_email_{$session_id}");
256 delete_option("mxchat_agent_name_{$session_id}");
257 $count++;
258 }
259 }
260 }
261
262 return $count;
263 }
264
265 function mxchat_migrate_live_agent_status() {
266 $options = get_option('mxchat_options', []);
267
268 // Check if live_agent_status exists
269 if (isset($options['live_agent_status'])) {
270 $current_status = $options['live_agent_status'];
271 $needs_update = false;
272
273 // Convert to new format if needed
274 if ($current_status === 'online') {
275 $options['live_agent_status'] = 'on';
276 $needs_update = true;
277 } else if ($current_status === 'offline') {
278 $options['live_agent_status'] = 'off';
279 $needs_update = true;
280 } else if (!in_array($current_status, ['on', 'off'])) {
281 // Default to off for any unexpected values
282 $options['live_agent_status'] = 'off';
283 $needs_update = true;
284 }
285
286 // Only update if needed
287 if ($needs_update) {
288 update_option('mxchat_options', $options);
289 }
290 } else {
291 // If status doesn't exist, set default to off
292 $options['live_agent_status'] = 'off';
293 update_option('mxchat_options', $options);
294 }
295 }
296
297 function mxchat_handle_live_agent_update() {
298 // Get the CURRENT stored version (before it gets updated)
299 $current_version = get_option('mxchat_plugin_version', '0.0.0');
300 $new_version = '2.2.2';
301
302 // Only run this once for the update to 2.2.2
303 $update_handled = get_option('mxchat_live_agent_update_2_2_2_handled', false);
304
305 // Check if we're upgrading TO 2.2.2 and haven't handled this yet
306 if (version_compare($current_version, $new_version, '<') && !$update_handled) {
307 $options = get_option('mxchat_options', array());
308
309 // Check if live agent was previously enabled
310 if (isset($options['live_agent_status']) && $options['live_agent_status'] === 'on') {
311 // Disable live agent
312 $options['live_agent_status'] = 'off';
313 update_option('mxchat_options', $options);
314
315 // Set flag to show the notification banner
316 update_option('mxchat_show_live_agent_disabled_notice', true);
317 }
318
319 // Mark this update as handled
320 update_option('mxchat_live_agent_update_2_2_2_handled', true);
321 }
322 }
323
324 // Initialize plugin safely
325 function mxchat_init() {
326 // Include all class files first
327 mxchat_include_classes();
328
329 // Run update check
330 mxchat_check_for_update();
331
332 // Add fallback rate limit check
333 add_action('init', 'mxchat_check_fallback_rate_limits', 5);
334
335 // Initialize classes with error handling
336 try {
337 // Initialize admin classes
338 if (is_admin()) {
339 if (class_exists('MxChat_Knowledge_Manager')) {
340 $mxchat_knowledge_manager = new MxChat_Knowledge_Manager();
341
342 if (class_exists('MxChat_Admin')) {
343 $mxchat_admin = new MxChat_Admin($mxchat_knowledge_manager);
344 }
345 }
346 }
347
348 // Initialize public classes
349 if (class_exists('MxChat_Public')) {
350 $mxchat_public = new MxChat_Public();
351 }
352
353 if (class_exists('MxChat_Integrator')) {
354 $mxchat_integrator = new MxChat_Integrator();
355 }
356
357 } catch (Exception $e) {
358 error_log('MxChat initialization error: ' . $e->getMessage());
359
360 // Show admin notice if there's an error
361 if (is_admin()) {
362 add_action('admin_notices', function() use ($e) {
363 echo '<div class="notice notice-error"><p>';
364 echo '<strong>MxChat Error:</strong> Plugin initialization failed. ';
365 echo 'Please check error logs or contact support. Error: ' . esc_html($e->getMessage());
366 echo '</p></div>';
367 });
368 }
369 }
370 }
371
372 // Run initialization on plugins_loaded
373 add_action('plugins_loaded', 'mxchat_init');
374
375 // Register activation hook
376 register_activation_hook(__FILE__, 'mxchat_activate');
377
378 // Add cron schedule
379 add_filter('cron_schedules', function($schedules) {
380 $schedules['one_minute'] = array(
381 'interval' => 60,
382 'display' => 'Every Minute'
383 );
384 return $schedules;
385 });
386
387 // Register deactivation hook
388 register_deactivation_hook(__FILE__, 'mxchat_deactivate');