PluginProbe
MxChat – AI Chatbot & Content Generation for WordPress / 3.0.5
MxChat – AI Chatbot & Content Generation for WordPress v3.0.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
← All changes | admin/class-ajax-handler.php +52 -289 3.2.73.0.5 View file →
@@ -40,90 +40,10 @@
40 40 add_action('wp_ajax_mxchat_update_intent_threshold', array($this, 'mxchat_update_intent_threshold'));
41 41
42 42 add_action('wp_ajax_mxchat_save_selected_bot', array($this, 'mxchat_save_selected_bot'));
43 43 add_action('wp_ajax_mxchat_check_api_keys', array($this, 'mxchat_check_api_keys'));
44 -
45 - // Debug & Optimization AJAX
46 - add_action('wp_ajax_mxchat_toggle_debug_mode', array($this, 'mxchat_toggle_debug_mode_callback'));
47 - add_action('wp_ajax_mxchat_get_debug_log', array($this, 'mxchat_get_debug_log_callback'));
48 - add_action('wp_ajax_mxchat_clear_debug_log', array($this, 'mxchat_clear_debug_log_callback'));
49 - add_action('wp_ajax_mxchat_export_settings', array($this, 'mxchat_export_settings_callback'));
50 - add_action('wp_ajax_mxchat_reset_all_settings', array($this, 'mxchat_reset_all_settings_callback'));
51 -
52 - // Custom (OpenAI-compatible) Provider connection test
53 - add_action('wp_ajax_mxchat_test_custom_provider', array($this, 'mxchat_test_custom_provider_callback'));
54 44 }
55 45
56 -/**
57 - * Test connection to a Custom (OpenAI-compatible) provider by hitting its /models endpoint
58 - * with whichever auth scheme the user configured. Reports model count or a clean error.
59 - */
60 -public function mxchat_test_custom_provider_callback() {
61 - check_ajax_referer('mxchat_test_custom_provider');
62 - if (!current_user_can('manage_options')) {
63 - wp_send_json_error(array('message' => esc_html__('Unauthorized', 'mxchat')));
64 - }
65 -
66 - $options = get_option('mxchat_options', array());
67 - $base_url = isset($options['custom_provider_base_url']) ? trim((string) $options['custom_provider_base_url']) : '';
68 - $api_key = isset($options['custom_provider_api_key']) ? trim((string) $options['custom_provider_api_key']) : '';
69 - $auth = isset($options['custom_provider_auth_scheme']) ? $options['custom_provider_auth_scheme'] : 'bearer';
70 - $api_version = isset($options['custom_provider_api_version']) ? trim((string) $options['custom_provider_api_version']) : '';
71 -
72 - if (empty($base_url)) {
73 - wp_send_json_error(array('message' => esc_html__('Base URL is empty. Save it first.', 'mxchat')));
74 - }
75 -
76 - $url = rtrim($base_url, '/') . '/models';
77 - if (!empty($api_version)) {
78 - $url = add_query_arg('api-version', $api_version, $url);
79 - }
80 -
81 - $headers = array('Content-Type' => 'application/json');
82 - if (!empty($api_key)) {
83 - if ($auth === 'api-key') {
84 - $headers['api-key'] = $api_key;
85 - } else {
86 - $headers['Authorization'] = 'Bearer ' . $api_key;
87 - }
88 - }
89 -
90 - $response = wp_remote_get($url, array(
91 - 'headers' => $headers,
92 - 'timeout' => 10,
93 - ));
94 -
95 - if (is_wp_error($response)) {
96 - wp_send_json_error(array('message' => sprintf(esc_html__('Network error: %s', 'mxchat'), esc_html($response->get_error_message()))));
97 - }
98 -
99 - $code = (int) wp_remote_retrieve_response_code($response);
100 - if ($code === 401 || $code === 403) {
101 - wp_send_json_error(array('message' => sprintf(esc_html__('Auth rejected (HTTP %d). Check API key and auth scheme.', 'mxchat'), $code)));
102 - }
103 - if ($code === 404) {
104 - wp_send_json_error(array('message' => esc_html__('Endpoint not found (HTTP 404). Check the Base URL.', 'mxchat')));
105 - }
106 - if ($code < 200 || $code >= 300) {
107 - wp_send_json_error(array('message' => sprintf(esc_html__('Upstream returned HTTP %d.', 'mxchat'), $code)));
108 - }
109 -
110 - $body = json_decode(wp_remote_retrieve_body($response), true);
111 - $count = 0;
112 - if (is_array($body)) {
113 - if (isset($body['data']) && is_array($body['data'])) {
114 - $count = count($body['data']);
115 - } elseif (isset($body['models']) && is_array($body['models'])) {
116 - $count = count($body['models']);
117 - }
118 - }
119 -
120 - wp_send_json_success(array(
121 - 'message' => sprintf(esc_html__('Connection OK — %d model(s) reported.', 'mxchat'), $count),
122 - 'count' => $count,
123 - ));
124 -}
125 -
126 46 // ========================================
127 47 // SETTINGS AJAX HANDLERS
128 48 // ========================================
129 49
@@ -152,17 +72,10 @@
152 72 // Load the full options array
153 73 $options = get_option('mxchat_options', []);
154 74 //error_log('MXChat Save: Current options array: ' . print_r($options, true));
155 75
156 - // Extract field name from mxchat_options[field_name] format if present
157 - // But preserve the full name for special cases like rate_limits that need the full path
158 - $field_name = $name;
159 - if (preg_match('/^mxchat_options\[([^\[\]]+)\]$/', $name, $matches)) {
160 - $field_name = $matches[1];
161 - }
162 -
163 76 // Handle special cases
164 - switch ($field_name) {
77 + switch ($name) {
165 78 case 'model':
166 79 //error_log('MXChat Save: Processing model selection');
167 80 //error_log('MXChat Save: Model value received: ' . $value);
168 81 //error_log('MXChat Save: Value type: ' . gettype($value));
@@ -174,15 +87,21 @@
174 87 //error_log('MXChat Save: Setting model to openrouter');
175 88 $options['model'] = 'openrouter';
176 89 } else {
177 90 //error_log('MXChat Save: Checking against whitelist');
178 - // Catalog refactor (plan-d14e89): canonical allowlist lives in
179 - // includes/class-mxchat-model-catalog.php. A new chat model
180 - // added there is automatically accepted by autosave.
181 - if (!class_exists('MxChat_Model_Catalog')) {
182 - require_once plugin_dir_path(dirname(__FILE__)) . 'includes/class-mxchat-model-catalog.php';
183 - }
184 - $allowed_models = MxChat_Model_Catalog::chat_model_ids();
91 + $allowed_models = array(
92 + 'gemini-3-pro-preview', 'gemini-3-flash-preview', 'gemini-2.5-pro', 'gemini-2.5-flash', 'gemini-2.5-flash-lite',
93 + 'gemini-2.0-flash', 'gemini-2.0-flash-lite', 'gemini-1.5-pro', 'gemini-1.5-flash',
94 + 'grok-4-0709', 'grok-4-1-fast-reasoning', 'grok-4-1-fast-non-reasoning', 'grok-3-beta', 'grok-3-fast-beta', 'grok-3-mini-beta',
95 + 'grok-3-mini-fast-beta', 'grok-2',
96 + 'deepseek-chat',
97 + 'claude-sonnet-4-5-20250929', 'claude-opus-4-1-20250805', 'claude-haiku-4-5-20251001',
98 + 'claude-opus-4-20250514', 'claude-sonnet-4-20250514', 'claude-3-7-sonnet-20250219',
99 + 'claude-3-5-sonnet-20241022', 'claude-3-opus-20240229', 'claude-3-sonnet-20240229',
100 + 'claude-3-haiku-20240307',
101 + 'gpt-5.2', 'gpt-5.1-2025-11-13', 'gpt-5', 'gpt-5-mini', 'gpt-5-nano', 'gpt-4.1-2025-04-14',
102 + 'gpt-4o', 'gpt-4o-mini', 'gpt-4-turbo', 'gpt-4', 'gpt-3.5-turbo',
103 + );
185 104
186 105 //error_log('MXChat Save: in_array result: ' . (in_array($value, $allowed_models) ? 'YES' : 'NO'));
187 106
188 107 if (in_array($value, $allowed_models)) {
@@ -221,9 +140,9 @@
221 140 case 'additional_popular_questions':
222 141 //error_log('MXChat Save: Processing additional_popular_questions');
223 142 $questions = json_decode($value, true); // No need for stripslashes here
224 143 if (is_array($questions)) {
225 - $options[$field_name] = $questions;
144 + $options[$name] = $questions;
226 145 // Also update old option for backwards compatibility
227 146 update_option('additional_popular_questions', $questions);
228 147 //error_log('MXChat Save: Saved ' . count($questions) . ' additional questions');
229 148 } else {
@@ -232,59 +151,60 @@
232 151 break;
233 152 case 'email_blocker_header_content':
234 153 //error_log('MXChat Save: Processing email_blocker_header_content');
235 154 // Allow HTML content but sanitize it safely
236 - $options[$field_name] = wp_kses_post($value);
155 + $options[$name] = wp_kses_post($value);
237 156 break;
238 157 case 'email_blocker_button_text':
239 158 //error_log('MXChat Save: Processing email_blocker_button_text');
240 - $options[$field_name] = sanitize_text_field($value);
159 + $options[$name] = sanitize_text_field($value);
241 160 break;
242 161 case 'name_field_placeholder':
243 162 //error_log('MXChat Save: Processing name_field_placeholder');
244 - $options[$field_name] = sanitize_text_field($value);
163 + $options[$name] = sanitize_text_field($value);
245 164 break;
246 165 case 'similarity_threshold':
247 166 //error_log('MXChat Save: Processing similarity_threshold');
248 - // Validate and save - enforce min 20, max 85
249 - $threshold = intval($value);
250 - if ($threshold < 20) $threshold = 20;
251 - if ($threshold > 85) $threshold = 85;
252 - $options[$field_name] = $threshold;
167 + // Save to the options array
168 + $options[$name] = $value;
253 169 break;
254 - case 'rag_sources_limit':
255 - //error_log('MXChat Save: Processing rag_sources_limit');
256 - // Validate and save - enforce min 3, max 10, default 6
257 - $rag_limit = intval($value);
258 - if ($rag_limit < 3) $rag_limit = 3;
259 - if ($rag_limit > 10) $rag_limit = 10;
260 - $options[$field_name] = $rag_limit;
170 + case 'user_message_bg_color':
171 + case 'user_message_font_color':
172 + case 'bot_message_bg_color':
173 + case 'bot_message_font_color':
174 + case 'top_bar_bg_color':
175 + case 'send_button_font_color':
176 + case 'chatbot_background_color':
177 + case 'icon_color':
178 + case 'chat_input_font_color':
179 + case 'live_agent_message_bg_color':
180 + case 'live_agent_message_font_color':
181 + case 'mode_indicator_bg_color':
182 + case 'mode_indicator_font_color':
183 + case 'toolbar_icon_color':
184 + case 'quick_questions_toggle_color':
185 + //error_log('MXChat Save: Processing color value: ' . $name);
186 + // Store color values directly
187 + $options[$name] = $value;
261 188 break;
262 - case 'rag_chunks_limit':
263 - // Validate and save - enforce min 8, max 20, default 15
264 - $chunks_limit = intval($value);
265 - if ($chunks_limit < 8) $chunks_limit = 8;
266 - if ($chunks_limit > 20) $chunks_limit = 20;
267 - $options[$field_name] = $chunks_limit;
268 - break;
269 189 case 'live_agent_status':
270 190 //error_log('MXChat Save: Processing live_agent_status');
271 191 // Set the new value
272 - $options[$field_name] = ($value === 'on') ? 'on' : 'off';
192 + $options[$name] = ($value === 'on') ? 'on' : 'off';
273 193 break;
274 194 case 'enable_web_search':
275 195 //error_log('MXChat Save: Processing enable_web_search');
276 - $options[$field_name] = ($value === 'on') ? 'on' : 'off';
196 + $options[$name] = ($value === 'on') ? 'on' : 'off';
277 197 break;
278 198 case 'enable_woocommerce_integration':
279 199 //error_log('MXChat Save: Processing enable_woocommerce_integration');
280 200 // Handle values that used to be 1/0
281 - $options[$field_name] = ($value === 'on' || $value === '1') ? 'on' : 'off';
201 + $options[$name] = ($value === 'on' || $value === '1') ? 'on' : 'off';
282 202 break;
283 203 case 'post_type_visibility_mode':
284 204 // Validate mode value
285 205 $allowed_modes = array('all', 'include', 'exclude');
286 - $options[$field_name] = in_array($value, $allowed_modes) ? $value : 'all';
206 + $options[$name] = in_array($value, $allowed_modes) ? $value : 'all';
287 207 break;
288 208 case 'post_type_visibility_list':
289 209 // Handle JSON array of post types
290 210 $post_types = json_decode($value, true);
@@ -289,22 +209,13 @@
289 209 // Handle JSON array of post types
290 210 $post_types = json_decode($value, true);
291 211 if (is_array($post_types)) {
292 212 // Sanitize each post type slug
293 - $options[$field_name] = array_map('sanitize_key', $post_types);
213 + $options[$name] = array_map('sanitize_key', $post_types);
294 214 } else {
295 - $options[$field_name] = array();
215 + $options[$name] = array();
296 216 }
297 217 break;
298 - case 'script_loading_strategy':
299 - // Validate script loading strategy value
300 - $allowed_strategies = array('default', 'defer', 'delay_1s', 'delay_3s', 'delay_5s', 'on_interaction');
301 - $options[$field_name] = in_array($value, $allowed_strategies) ? $value : 'default';
302 - break;
303 - case 'auto_retry_on_transient_error':
304 - // Boolean toggle — accept 1/0/on/off, default to '1' if any truthy value.
305 - $options[$field_name] = ($value === '1' || $value === 'on' || $value === 1 || $value === true) ? '1' : '0';
306 - break;
307 218 default:
308 219 // Handle transcripts options
309 220 if (strpos($name, 'mxchat_transcripts_options') !== false) {
310 221 // Extract field name from mxchat_transcripts_options[field_name]
@@ -430,10 +341,10 @@
430 341 } else {
431 342 //error_log('MXChat Save: Failed to parse role_rate_limits pattern: ' . $name);
432 343 }
433 344 }
434 - // Handle toggles - check both extracted field_name and original name for toggle detection
435 - else if (strpos($field_name, 'toggle') !== false || in_array($field_name, [
345 + // Handle toggles
346 + else if (strpos($name, 'toggle') !== false || in_array($name, [
436 347 'chat_persistence_toggle',
437 348 'privacy_toggle',
438 349 'complianz_toggle',
439 350 'chat_toolbar_toggle',
@@ -443,17 +354,16 @@
443 354 'contextual_awareness_toggle',
444 355 'citation_links_toggle',
445 356 'enable_email_block',
446 357 'enable_name_field',
447 - 'custom_provider_for_embeddings',
448 - 'custom_provider_for_images'
358 + 'show_frontend_debugger'
449 359 ])) {
450 - //error_log('MXChat Save: Processing toggle: ' . $field_name);
451 - $options[$field_name] = ($value === 'on') ? 'on' : 'off';
360 + //error_log('MXChat Save: Processing toggle: ' . $name);
361 + $options[$name] = ($value === 'on') ? 'on' : 'off';
452 362 } else {
453 - //error_log('MXChat Save: Processing standard field: ' . $field_name);
454 - // Store all other values directly using the extracted field name
455 - $options[$field_name] = $value;
363 + //error_log('MXChat Save: Processing standard field: ' . $name);
364 + // Store all other values directly
365 + $options[$name] = $value;
456 366 }
457 367 break;
458 368 }
459 369
@@ -461,20 +371,8 @@
461 371 $updated = update_option('mxchat_options', $options);
462 372 //error_log('MXChat Save: Update result: ' . ($updated ? 'success' : 'unchanged') . ' for field: ' . $name);
463 373 //error_log('MXChat Save: Updated options array: ' . print_r($options, true));
464 374
465 - // Log the save action if debug mode is enabled
466 - if ( class_exists( 'MxChat_Admin' ) ) {
467 - MxChat_Admin::mxchat_log_debug(
468 - 'settings_save',
469 - sprintf( 'Field saved: %s', $field_name ),
470 - array(
471 - 'field' => $field_name,
472 - 'updated' => $updated,
473 - )
474 - );
475 - }
476 -
477 375 // Always return success even if WordPress says nothing changed
478 376 // (which happens when the value is the same as before)
479 377 wp_send_json_success(['message' => esc_html__('Setting saved', 'mxchat')]);
480 378 }
@@ -1208,143 +1106,8 @@
1208 1106 'voyage' => !empty($options['voyage_api_key'])
1209 1107 );
1210 1108
1211 1109 wp_send_json_success($api_key_status);
1212 - }
1213 -
1214 - // ========================================
1215 - // DEBUG & OPTIMIZATION AJAX HANDLERS
1216 - // ========================================
1217 -
1218 - /**
1219 - * Toggle debug mode on/off
1220 - */
1221 - public function mxchat_toggle_debug_mode_callback() {
1222 - // Verify nonce
1223 - if ( ! check_ajax_referer( 'mxchat_save_setting_nonce', '_ajax_nonce', false ) ) {
1224 - wp_send_json_error( array( 'message' => esc_html__( 'Security check failed', 'mxchat' ) ) );
1225 - }
1226 -
1227 - // Check permissions
1228 - if ( ! current_user_can( 'manage_options' ) ) {
1229 - wp_send_json_error( array( 'message' => esc_html__( 'Unauthorized', 'mxchat' ) ) );
1230 - }
1231 -
1232 - $enabled = isset( $_POST['enabled'] ) && $_POST['enabled'] === 'on';
1233 -
1234 - $options = get_option( 'mxchat_options', array() );
1235 -
1236 - if ( $enabled ) {
1237 - $options['debug_mode'] = 'on';
1238 - update_option( 'mxchat_options', $options );
1239 - MxChat_Admin::mxchat_log_debug( 'debug_mode', 'Debug mode enabled' );
1240 - } else {
1241 - // Log before disabling
1242 - MxChat_Admin::mxchat_log_debug( 'debug_mode', 'Debug mode disabled' );
1243 - $options['debug_mode'] = 'off';
1244 - update_option( 'mxchat_options', $options );
1245 - }
1246 -
1247 - wp_send_json_success( array(
1248 - 'message' => $enabled ? esc_html__( 'Debug mode enabled', 'mxchat' ) : esc_html__( 'Debug mode disabled', 'mxchat' ),
1249 - 'enabled' => $enabled,
1250 - ) );
1251 - }
1252 -
1253 - /**
1254 - * Get the debug log entries
1255 - */
1256 - public function mxchat_get_debug_log_callback() {
1257 - // Verify nonce
1258 - if ( ! check_ajax_referer( 'mxchat_save_setting_nonce', '_ajax_nonce', false ) ) {
1259 - wp_send_json_error( array( 'message' => esc_html__( 'Security check failed', 'mxchat' ) ) );
1260 - }
1261 -
1262 - // Check permissions
1263 - if ( ! current_user_can( 'manage_options' ) ) {
1264 - wp_send_json_error( array( 'message' => esc_html__( 'Unauthorized', 'mxchat' ) ) );
1265 - }
1266 -
1267 - $log = MxChat_Admin::mxchat_get_debug_log();
1268 -
1269 - wp_send_json_success( array(
1270 - 'log' => $log,
1271 - 'count' => count( $log ),
1272 - ) );
1273 - }
1274 -
1275 - /**
1276 - * Clear the debug log
1277 - */
1278 - public function mxchat_clear_debug_log_callback() {
1279 - // Verify nonce
1280 - if ( ! check_ajax_referer( 'mxchat_save_setting_nonce', '_ajax_nonce', false ) ) {
1281 - wp_send_json_error( array( 'message' => esc_html__( 'Security check failed', 'mxchat' ) ) );
1282 - }
1283 -
1284 - // Check permissions
1285 - if ( ! current_user_can( 'manage_options' ) ) {
1286 - wp_send_json_error( array( 'message' => esc_html__( 'Unauthorized', 'mxchat' ) ) );
1287 - }
1288 -
1289 - MxChat_Admin::mxchat_clear_debug_log();
1290 -
1291 - // Log that the log was cleared (this will be the first entry in the new log)
1292 - MxChat_Admin::mxchat_log_debug( 'debug_log', 'Debug log cleared by user' );
1293 -
1294 - wp_send_json_success( array( 'message' => esc_html__( 'Debug log cleared', 'mxchat' ) ) );
1295 - }
1296 -
1297 - /**
1298 - * Export settings as JSON
1299 - */
1300 - public function mxchat_export_settings_callback() {
1301 - // Verify nonce
1302 - if ( ! check_ajax_referer( 'mxchat_save_setting_nonce', '_ajax_nonce', false ) ) {
1303 - wp_send_json_error( array( 'message' => esc_html__( 'Security check failed', 'mxchat' ) ) );
1304 - }
1305 -
1306 - // Check permissions
1307 - if ( ! current_user_can( 'manage_options' ) ) {
1308 - wp_send_json_error( array( 'message' => esc_html__( 'Unauthorized', 'mxchat' ) ) );
1309 - }
1310 -
1311 - $export = MxChat_Admin::mxchat_export_settings();
1312 -
1313 - // Log the export
1314 - MxChat_Admin::mxchat_log_debug( 'settings_export', 'Settings exported by user' );
1315 -
1316 - wp_send_json_success( array(
1317 - 'settings' => $export,
1318 - 'filename' => 'mxchat-settings-' . gmdate( 'Y-m-d-His' ) . '.json',
1319 - ) );
1320 - }
1321 -
1322 - /**
1323 - * Reset all settings to defaults
1324 - */
1325 - public function mxchat_reset_all_settings_callback() {
1326 - // Verify nonce
1327 - if ( ! check_ajax_referer( 'mxchat_save_setting_nonce', '_ajax_nonce', false ) ) {
1328 - wp_send_json_error( array( 'message' => esc_html__( 'Security check failed', 'mxchat' ) ) );
1329 - }
1330 -
1331 - // Check permissions
1332 - if ( ! current_user_can( 'manage_options' ) ) {
1333 - wp_send_json_error( array( 'message' => esc_html__( 'Unauthorized', 'mxchat' ) ) );
1334 - }
1335 -
1336 - // Require confirmation code
1337 - $confirmation = isset( $_POST['confirmation'] ) ? sanitize_text_field( wp_unslash( $_POST['confirmation'] ) ) : '';
1338 -
1339 - if ( strtoupper( $confirmation ) !== 'RESET' ) {
1340 - wp_send_json_error( array( 'message' => esc_html__( 'Invalid confirmation code. Please type RESET to confirm.', 'mxchat' ) ) );
1341 - }
1342 -
1343 - // Perform the reset
1344 - MxChat_Admin::mxchat_reset_all_settings();
1345 -
1346 - wp_send_json_success( array( 'message' => esc_html__( 'All settings have been reset to defaults. The page will reload.', 'mxchat' ) ) );
1347 1110 }
1348 1111
1349 1112 }
1350 1113