PluginProbe
MxChat – AI Chatbot & Content Generation for WordPress / 2.3.0
MxChat – AI Chatbot & Content Generation for WordPress v2.3.0
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 / admin / class-ajax-handler.php

class-ajax-handler.php in MxChat – AI Chatbot & Content Generation for WordPress 2.3.0, at admin/class-ajax-handler.php

671 lines 28.5 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * File: admin/class-ajax-handler.php
4 *
5 * Handles all AJAX requests for MxChat admin functionality
6 */
7
8 if (!defined('ABSPATH')) {
9 exit; // Exit if accessed directly
10 }
11
12 class MxChat_Ajax_Handler {
13
14 private $pinecone_manager = null;
15
16 /**
17 * Constructor - Register all AJAX hooks
18 */
19 public function __construct() {
20 $this->mxchat_init_ajax_hooks();
21 }
22
23
24 /**
25 * Register all AJAX action hooks
26 */
27 private function mxchat_init_ajax_hooks() {
28 // Settings AJAX
29 add_action('wp_ajax_mxchat_save_setting', array($this, 'mxchat_save_setting_callback'));
30 add_action('wp_ajax_mxchat_save_prompts_setting', array($this, 'mxchat_save_prompts_setting_callback'));
31 add_action('wp_ajax_migrate_pinecone_settings', array($this, 'ajax_migrate_pinecone_settings'));
32
33 // License AJAX
34 add_action('wp_ajax_mxchat_activate_license', array($this, 'mxchat_handle_activate_license'));
35 add_action('wp_ajax_mxchat_check_license', array($this, 'mxchat_check_license_status'));
36
37 // Actions & Intents AJAX
38 add_action('wp_ajax_mxchat_toggle_action', array($this, 'mxchat_toggle_action'));
39 add_action('wp_ajax_mxchat_update_intent_threshold', array($this, 'mxchat_update_intent_threshold'));
40 }
41
42 // ========================================
43 // SETTINGS AJAX HANDLERS
44 // ========================================
45
46 /**
47 * Validates and saves chat settings via AJAX request
48 */
49 public function mxchat_save_setting_callback() {
50 check_ajax_referer('mxchat_save_setting_nonce');
51 if (!current_user_can('manage_options')) {
52 ('MXChat Save: Unauthorized access attempt');
53 wp_send_json_error(['message' => esc_html__('Unauthorized', 'mxchat')]);
54 }
55
56 $name = isset($_POST['name']) ? $_POST['name'] : '';
57 // Strip slashes from the value before saving
58 $value = isset($_POST['value']) ? stripslashes($_POST['value']) : '';
59
60 //error_log('MXChat Save: Processing field name: ' . $name);
61 //error_log('MXChat Save: Field value: ' . $value);
62
63 if (empty($name)) {
64 //error_log('MXChat Save: Empty field name detected');
65 wp_send_json_error(['message' => esc_html__('Invalid field name', 'mxchat')]);
66 }
67
68 // Load the full options array
69 $options = get_option('mxchat_options', []);
70 //error_log('MXChat Save: Current options array: ' . print_r($options, true));
71
72 // Handle special cases
73 switch ($name) {
74 case 'additional_popular_questions':
75 //error_log('MXChat Save: Processing additional_popular_questions');
76 $questions = json_decode($value, true); // No need for stripslashes here
77 if (is_array($questions)) {
78 $options[$name] = $questions;
79 // Also update old option for backwards compatibility
80 update_option('additional_popular_questions', $questions);
81 //error_log('MXChat Save: Saved ' . count($questions) . ' additional questions');
82 } else {
83 //error_log('MXChat Save: Failed to decode questions JSON');
84 }
85 break;
86 case 'email_blocker_header_content':
87 //error_log('MXChat Save: Processing email_blocker_header_content');
88 // Allow HTML content but sanitize it safely
89 $options[$name] = wp_kses_post($value);
90 break;
91 case 'similarity_threshold':
92 //error_log('MXChat Save: Processing similarity_threshold');
93 // Save to the options array
94 $options[$name] = $value;
95 break;
96 case 'user_message_bg_color':
97 case 'user_message_font_color':
98 case 'bot_message_bg_color':
99 case 'bot_message_font_color':
100 case 'top_bar_bg_color':
101 case 'send_button_font_color':
102 case 'chatbot_background_color':
103 case 'icon_color':
104 case 'chat_input_font_color':
105 case 'live_agent_message_bg_color':
106 case 'live_agent_message_font_color':
107 case 'mode_indicator_bg_color':
108 case 'mode_indicator_font_color':
109 case 'toolbar_icon_color':
110 case 'quick_questions_toggle_color':
111 //error_log('MXChat Save: Processing color value: ' . $name);
112 // Store color values directly
113 $options[$name] = $value;
114 break;
115 case 'live_agent_status':
116 //error_log('MXChat Save: Processing live_agent_status');
117 // Set the new value
118 $options[$name] = ($value === 'on') ? 'on' : 'off';
119 break;
120 case 'enable_woocommerce_integration':
121 //error_log('MXChat Save: Processing enable_woocommerce_integration');
122 // Handle values that used to be 1/0
123 $options[$name] = ($value === 'on' || $value === '1') ? 'on' : 'off';
124 break;
125 default:
126 // First check for rate limits settings
127 if (strpos($name, 'mxchat_options[rate_limits]') !== false) {
128 //error_log('MXChat Save: Detected rate_limits field: ' . $name);
129
130 // Extract role ID and setting from the name
131 preg_match('/\[rate_limits\]\[(.*?)\]\[(.*?)\]/', $name, $matches);
132 //error_log('MXChat Save: Regex matches: ' . print_r($matches, true));
133
134 if (isset($matches[1]) && isset($matches[2])) {
135 $role_id = $matches[1];
136 $setting_key = $matches[2]; // limit, timeframe, or message
137
138 //error_log('MXChat Save: Role ID = ' . $role_id . ', Setting Key = ' . $setting_key);
139
140 // Initialize rate_limits if it doesn't exist
141 if (!isset($options['rate_limits'])) {
142 // //error_log('MXChat Save: Initializing rate_limits array');
143 $options['rate_limits'] = [];
144 }
145
146 // Initialize role settings if it doesn't exist
147 if (!isset($options['rate_limits'][$role_id])) {
148 //error_log('MXChat Save: Initializing rate_limits for role: ' . $role_id);
149 $options['rate_limits'][$role_id] = [
150 'limit' => ($role_id === 'logged_out') ? '10' : '100',
151 'timeframe' => 'daily',
152 'message' => 'Rate limit exceeded. Please try again later.'
153 ];
154 }
155
156 // Update the specific setting
157 $options['rate_limits'][$role_id][$setting_key] = $value;
158 //error_log('MXChat Save: Updated rate_limits[' . $role_id . '][' . $setting_key . '] = ' . $value);
159 } else {
160 //error_log('MXChat Save: Failed to parse rate_limits pattern: ' . $name);
161 }
162 }
163 // Then check for role rate limits (old format)
164 else if (strpos($name, 'mxchat_options[role_rate_limits]') !== false) {
165 //error_log('MXChat Save: Processing role_rate_limits field: ' . $name);
166 // Extract role ID from the name
167 preg_match('/\[role_rate_limits\]\[(.*?)\]/', $name, $matches);
168 //error_log('MXChat Save: Regex matches: ' . print_r($matches, true));
169
170 if (isset($matches[1])) {
171 $role_id = $matches[1];
172 // Initialize role_rate_limits if it doesn't exist
173 if (!isset($options['role_rate_limits'])) {
174 //error_log('MXChat Save: Initializing role_rate_limits array');
175 $options['role_rate_limits'] = [];
176 }
177 // Update the specific role's rate limit
178 $options['role_rate_limits'][$role_id] = sanitize_text_field($value);
179 //error_log('MXChat Save: Updated role_rate_limits[' . $role_id . '] = ' . $value);
180 } else {
181 //error_log('MXChat Save: Failed to parse role_rate_limits pattern: ' . $name);
182 }
183 }
184 // Handle toggles
185 else if (strpos($name, 'toggle') !== false || in_array($name, [
186 'chat_persistence_toggle',
187 'privacy_toggle',
188 'complianz_toggle',
189 'chat_toolbar_toggle',
190 'show_pdf_upload_button',
191 'show_word_upload_button',
192 'enable_streaming_toggle',
193 'contextual_awareness_toggle' // Add this line
194 ])) {
195 //error_log('MXChat Save: Processing toggle: ' . $name);
196 $options[$name] = ($value === 'on') ? 'on' : 'off';
197 } else {
198 //error_log('MXChat Save: Processing standard field: ' . $name);
199 // Store all other values directly
200 $options[$name] = $value;
201 }
202 break;
203 }
204
205 // Save all updates to the options array
206 $updated = update_option('mxchat_options', $options);
207 //error_log('MXChat Save: Update result: ' . ($updated ? 'success' : 'unchanged') . ' for field: ' . $name);
208 //error_log('MXChat Save: Updated options array: ' . print_r($options, true));
209
210 // Always return success even if WordPress says nothing changed
211 // (which happens when the value is the same as before)
212 wp_send_json_success(['message' => esc_html__('Setting saved', 'mxchat')]);
213 }
214
215
216 /**
217 * Handles AJAX request for saving chat settings
218 */
219 public function mxchat_save_prompts_setting_callback() {
220 check_ajax_referer('mxchat_prompts_setting_nonce');
221
222 if (!current_user_can('manage_options')) {
223 wp_send_json_error(['message' => esc_html__('Unauthorized', 'mxchat')]);
224 }
225
226 $name = isset($_POST['name']) ? $_POST['name'] : '';
227 $value = isset($_POST['value']) ? stripslashes($_POST['value']) : '';
228
229 //error_log('[MXCHAT-PROMPTS] Saving setting: ' . $name . ' = ' . $value);
230
231 if (empty($name)) {
232 wp_send_json_error(['message' => esc_html__('Invalid field name', 'mxchat')]);
233 }
234
235 // Handle Pinecone settings - BYPASS WORDPRESS SANITIZATION
236 if (strpos($name, 'mxchat_pinecone_addon_options') !== false) {
237 //error_log('[MXCHAT-PROMPTS] Processing Pinecone setting: ' . $name);
238
239 // Extract the field name
240 if (preg_match('/mxchat_pinecone_addon_options\[([^\]]+)\]/', $name, $matches)) {
241 $field_name = $matches[1];
242 //error_log('[MXCHAT-PROMPTS] Extracted field name: ' . $field_name);
243
244 // Get current options directly from database - NO WordPress filters
245 global $wpdb;
246 $current_options_raw = $wpdb->get_var(
247 $wpdb->prepare(
248 "SELECT option_value FROM {$wpdb->options} WHERE option_name = %s",
249 'mxchat_pinecone_addon_options'
250 )
251 );
252
253 // FIX: Handle the case where the option doesn't exist yet
254 if ($current_options_raw === null) {
255 // Option doesn't exist, create it with default values
256 $current_options = array(
257 'mxchat_use_pinecone' => '0',
258 'mxchat_pinecone_api_key' => '',
259 'mxchat_pinecone_host' => '',
260 'mxchat_pinecone_index' => '',
261 'mxchat_pinecone_environment' => ''
262 );
263 //error_log('[MXCHAT-PROMPTS] Option does not exist, creating with defaults');
264 } else {
265 // Unserialize the raw data
266 $current_options = maybe_unserialize($current_options_raw);
267 if (!is_array($current_options)) {
268 // Fallback to defaults if unserialization fails
269 $current_options = array(
270 'mxchat_use_pinecone' => '0',
271 'mxchat_pinecone_api_key' => '',
272 'mxchat_pinecone_host' => '',
273 'mxchat_pinecone_index' => '',
274 'mxchat_pinecone_environment' => ''
275 );
276 //error_log('[MXCHAT-PROMPTS] Failed to unserialize, using defaults');
277 }
278 }
279
280 //error_log('[MXCHAT-PROMPTS] Current options from DB: ' . print_r($current_options, true));
281
282 // Update the specific field with proper sanitization
283 switch ($field_name) {
284 case 'mxchat_use_pinecone':
285 $new_value = ($value === '1') ? '1' : '0';
286 break;
287 case 'mxchat_pinecone_api_key':
288 case 'mxchat_pinecone_host':
289 case 'mxchat_pinecone_index':
290 case 'mxchat_pinecone_environment':
291 $new_value = sanitize_text_field($value);
292 if ($field_name === 'mxchat_pinecone_host') {
293 $new_value = str_replace(['https://', 'http://'], '', $new_value);
294 }
295 break;
296 default:
297 wp_send_json_error(['message' => esc_html__('Unknown Pinecone field', 'mxchat')]);
298 }
299
300 $current_options[$field_name] = $new_value;
301 //error_log('[MXCHAT-PROMPTS] New value for ' . $field_name . ': "' . $new_value . '"');
302 //error_log('[MXCHAT-PROMPTS] Updated options: ' . print_r($current_options, true));
303
304 // Save directly to database to bypass WordPress sanitization
305 $serialized_options = maybe_serialize($current_options);
306
307 // FIX: Use INSERT ... ON DUPLICATE KEY UPDATE or separate INSERT/UPDATE logic
308 $option_exists = $wpdb->get_var(
309 $wpdb->prepare(
310 "SELECT COUNT(*) FROM {$wpdb->options} WHERE option_name = %s",
311 'mxchat_pinecone_addon_options'
312 )
313 );
314
315 if ($option_exists > 0) {
316 // Update existing option
317 $save_result = $wpdb->update(
318 $wpdb->options,
319 array('option_value' => $serialized_options),
320 array('option_name' => 'mxchat_pinecone_addon_options'),
321 array('%s'),
322 array('%s')
323 );
324 //error_log('[MXCHAT-PROMPTS] Updated existing option, result: ' . ($save_result !== false ? 'SUCCESS' : 'FAILED'));
325 } else {
326 // Insert new option
327 $save_result = $wpdb->insert(
328 $wpdb->options,
329 array(
330 'option_name' => 'mxchat_pinecone_addon_options',
331 'option_value' => $serialized_options,
332 'autoload' => 'yes'
333 ),
334 array('%s', '%s', '%s')
335 );
336 //error_log('[MXCHAT-PROMPTS] Inserted new option, result: ' . ($save_result !== false ? 'SUCCESS' : 'FAILED'));
337 }
338
339 // Clear any WordPress option cache to ensure get_option() returns fresh data
340 wp_cache_delete('mxchat_pinecone_addon_options', 'options');
341
342 // IMPROVED VERIFICATION - Check if the database operation succeeded
343 if ($save_result !== false) {
344 // Double-check by reading fresh from database
345 $verification_raw = $wpdb->get_var(
346 $wpdb->prepare(
347 "SELECT option_value FROM {$wpdb->options} WHERE option_name = %s",
348 'mxchat_pinecone_addon_options'
349 )
350 );
351 $verification_options = maybe_unserialize($verification_raw);
352 $verified_value = isset($verification_options[$field_name]) ? $verification_options[$field_name] : 'NOT_FOUND';
353
354 //error_log('[MXCHAT-PROMPTS] Final verification - Expected: "' . $new_value . '", Got: "' . $verified_value . '"');
355
356 // Use loose comparison (==) instead of strict (===) to avoid type issues
357 if ($verified_value == $new_value || $save_result > 0) {
358 wp_send_json_success(['message' => esc_html__('Pinecone setting saved', 'mxchat')]);
359 } else {
360 // Still return success if the DB operation worked, even if verification is quirky
361 //error_log('[MXCHAT-PROMPTS] Verification mismatch but DB operation succeeded');
362 wp_send_json_success(['message' => esc_html__('Pinecone setting saved (DB success)', 'mxchat')]);
363 }
364 } else {
365 wp_send_json_error(['message' => esc_html__('Database save failed', 'mxchat')]);
366 }
367 } else {
368 wp_send_json_error(['message' => esc_html__('Invalid field name format', 'mxchat')]);
369 }
370
371 return; // Exit here for Pinecone settings
372 }
373 // Handle auto-sync settings (existing functionality)
374 if (strpos($name, 'mxchat_auto_sync_') === 0) {
375 $value = ($value === 'on' || $value === '1') ? '1' : '0';
376 $updated = update_option($name, $value);
377
378 if ($updated || get_option($name) === $value) {
379 wp_send_json_success(['message' => esc_html__('Auto-sync setting saved', 'mxchat')]);
380 } else {
381 wp_send_json_error(['message' => esc_html__('No changes detected', 'mxchat')]);
382 }
383 }
384
385 // Handle other prompts options
386 $options = get_option('mxchat_prompts_options', []);
387 $options[$name] = $value;
388 $updated = update_option('mxchat_prompts_options', $options);
389
390 if ($updated) {
391 wp_send_json_success(['message' => esc_html__('Setting saved', 'mxchat')]);
392 } else {
393 wp_send_json_error(['message' => esc_html__('No changes detected', 'mxchat')]);
394 }
395 }
396
397
398 /**
399 * Handles AJAX request for Pinecone settings migration
400 */
401 public function ajax_migrate_pinecone_settings() {
402 // Verify nonce
403 if (!wp_verify_nonce($_POST['_ajax_nonce'] ?? '', 'mxchat_save_setting_nonce')) {
404 wp_send_json_error('Invalid nonce');
405 }
406
407 // Check permissions
408 if (!current_user_can('manage_options')) {
409 wp_send_json_error('Unauthorized access');
410 }
411
412 // Check if old Pinecone addon options exist
413 $old_options = get_option('mxchat_pinecone_addon_options', array());
414
415 if (empty($old_options)) {
416 wp_send_json_success(array('migrated' => false, 'message' => 'No old settings found'));
417 }
418
419 // Get current core plugin options
420 $current_options = get_option('mxchat_pinecone_addon_options', array());
421
422 // Only migrate if core options are empty or if explicitly requested
423 $should_migrate = empty($current_options) ||
424 (empty($current_options['mxchat_pinecone_api_key']) && !empty($old_options['mxchat_pinecone_api_key']));
425
426 if ($should_migrate) {
427 // Migrate settings with proper sanitization
428 $migrated_options = array(
429 'mxchat_use_pinecone' => $old_options['mxchat_use_pinecone'] ?? '0',
430 'mxchat_pinecone_api_key' => sanitize_text_field($old_options['mxchat_pinecone_api_key'] ?? ''),
431 'mxchat_pinecone_host' => sanitize_text_field($old_options['mxchat_pinecone_host'] ?? ''),
432 'mxchat_pinecone_index' => sanitize_text_field($old_options['mxchat_pinecone_index'] ?? ''),
433 'mxchat_pinecone_environment' => sanitize_text_field($old_options['mxchat_pinecone_environment'] ?? '')
434 );
435
436 update_option('mxchat_pinecone_addon_options', $migrated_options);
437
438 wp_send_json_success(array(
439 'migrated' => true,
440 'message' => 'Settings migrated successfully from Pinecone add-on'
441 ));
442 } else {
443 wp_send_json_success(array(
444 'migrated' => false,
445 'message' => 'Settings already exist in core plugin'
446 ));
447 }
448 }
449
450
451
452 // ========================================
453 // LICENSE AJAX HANDLERS
454 // ========================================
455
456 /**
457 * Validates and activates chat license via AJAX
458 */
459 public function mxchat_handle_activate_license() {
460 // Check nonce
461 if (!check_ajax_referer('mxchat_activate_license_nonce', 'security', false)) {
462 wp_send_json_error(esc_html__('Invalid security token', 'mxchat'));
463 return;
464 }
465
466 // Verify user capabilities
467 if (!current_user_can('manage_options')) {
468 wp_send_json_error(esc_html__('Unauthorized access', 'mxchat'));
469 return;
470 }
471
472 $license_key = isset($_POST['mxchat_activation_key']) ? sanitize_text_field($_POST['mxchat_activation_key']) : '';
473 $customer_email = isset($_POST['mxchat_pro_email']) ? sanitize_email($_POST['mxchat_pro_email']) : '';
474
475 if (empty($license_key) || empty($customer_email)) {
476 wp_send_json_error(esc_html__('Email or License Key is missing', 'mxchat'));
477 return;
478 }
479
480 $product_id = 'MxChatPRO';
481
482 // **CHANGED TO HTTPS**
483 $response = wp_remote_get(
484 add_query_arg(
485 array(
486 'wc-api' => 'software-api',
487 'request' => 'activation',
488 'email' => $customer_email,
489 'license_key' => $license_key,
490 'product_id' => $product_id
491 ),
492 'https://mxchat.ai/' // **CHANGED FROM HTTP TO HTTPS**
493 ),
494 array(
495 'timeout' => 60, // 60 seconds timeout
496 'sslverify' => true // **CHANGED TO TRUE FOR HTTPS**
497 )
498 );
499
500 if (is_wp_error($response)) {
501 $error_message = $response->get_error_message();
502 //error_log('MxChat License Activation Error: ' . $error_message);
503 wp_send_json_error(esc_html__('Activation failed due to a server error: ', 'mxchat') . $error_message);
504 return;
505 }
506
507 $response_code = wp_remote_retrieve_response_code($response);
508 $body = wp_remote_retrieve_body($response);
509
510 // Log response for debugging
511 //error_log('MxChat License Response Code: ' . $response_code);
512 //error_log('MxChat License Response Body: ' . $body);
513
514 if ($response_code !== 200) {
515 wp_send_json_error(esc_html__('Server returned error code: ', 'mxchat') . $response_code);
516 return;
517 }
518
519 $data = json_decode($body);
520
521 if ($data && isset($data->activated) && $data->activated) {
522 update_option('mxchat_license_status', 'active');
523 update_option('mxchat_pro_email', $customer_email);
524 update_option('mxchat_activation_key', $license_key);
525 delete_option('mxchat_license_error'); // Clear any previous errors
526 wp_send_json_success(array('message' => esc_html__('License activated successfully', 'mxchat')));
527 } else {
528 $error_message = isset($data->error) ? $data->error : esc_html__('Activation failed', 'mxchat');
529 update_option('mxchat_license_status', 'inactive');
530 update_option('mxchat_license_error', $error_message);
531 wp_send_json_error($error_message);
532 }
533 }
534
535
536 /**
537 * Validates license via AJAX with email and key
538 */
539 public function mxchat_check_license_status() {
540 // Verify nonce
541 check_ajax_referer($this->mxchat_get_nonce_action(), 'security');
542
543 $email = sanitize_email($_POST['email']);
544 $key = sanitize_text_field($_POST['key']);
545
546 // Check if this license is actually active in your system
547 $is_active = (get_option('mxchat_license_status') === 'active' &&
548 get_option('mxchat_pro_email') === $email &&
549 get_option('mxchat_activation_key') === $key);
550
551 wp_send_json(array(
552 'is_active' => $is_active
553 ));
554 }
555
556
557 // ========================================
558 // ACTIONS & INTENTS AJAX HANDLERS
559 // ========================================
560
561 /**
562 * Validates nonce and returns JSON error on failure
563 */
564 public function mxchat_toggle_action() {
565 // Check nonce
566 if (!isset($_POST['nonce']) || !wp_verify_nonce($_POST['nonce'], 'mxchat_actions_nonce')) {
567 wp_send_json_error(array('message' => 'Security check failed'));
568 return;
569 }
570
571 // Check permissions
572 if (!current_user_can('manage_options')) {
573 wp_send_json_error(array('message' => 'Permission denied'));
574 return;
575 }
576
577 // Validate params
578 $intent_id = isset($_POST['intent_id']) ? intval($_POST['intent_id']) : 0;
579 $enabled = isset($_POST['enabled']) ? (bool)$_POST['enabled'] : false;
580
581 if (!$intent_id) {
582 wp_send_json_error(array('message' => 'Invalid action ID'));
583 return;
584 }
585
586 // Update the intent/action status in the database
587 global $wpdb;
588 $table_name = $wpdb->prefix . 'mxchat_intents';
589
590 // Using the 'enabled' field - add this field if it doesn't exist
591 $result = $wpdb->update(
592 $table_name,
593 array('enabled' => $enabled ? 1 : 0),
594 array('id' => $intent_id),
595 array('%d'),
596 array('%d')
597 );
598
599 if ($result === false) {
600 wp_send_json_error(array('message' => 'Database error'));
601 return;
602 }
603
604 wp_send_json_success();
605 }
606
607
608 /**
609 * Validates permissions for AJAX request handling
610 */
611 public function mxchat_update_intent_threshold() {
612 // Check permissions
613 if (!current_user_can('manage_options')) {
614 if (wp_doing_ajax()) {
615 wp_send_json_error(array('message' => 'Unauthorized user'));
616 return;
617 }
618 wp_die(esc_html__('Unauthorized user', 'mxchat'));
619 }
620
621 // Verify nonce
622 check_admin_referer('mxchat_update_intent_threshold_nonce');
623
624 // Process the update if we have valid data
625 if (isset($_POST['intent_id'], $_POST['intent_threshold'])) {
626 global $wpdb;
627 $table_name = $wpdb->prefix . 'mxchat_intents';
628 $intent_id = intval($_POST['intent_id']);
629 $threshold_percentage = max(70, min(95, intval($_POST['intent_threshold'])));
630 $similarity_threshold = $threshold_percentage / 100;
631
632 $result = $wpdb->update(
633 $table_name,
634 ['similarity_threshold' => $similarity_threshold],
635 ['id' => $intent_id],
636 ['%f'],
637 ['%d']
638 );
639
640 // Handle AJAX requests
641 if (wp_doing_ajax()) {
642 if ($result === false) {
643 wp_send_json_error(array('message' => 'Failed to update threshold'));
644 } else {
645 wp_send_json_success(array('threshold' => $threshold_percentage));
646 }
647 return;
648 }
649 }
650
651 // Redirect for regular form submissions
652 wp_safe_redirect(admin_url('admin.php?page=mxchat-actions&updated=true'));
653 exit;
654 }
655
656 // ========================================
657 // HELPER METHODS
658 // ========================================
659
660 /**
661 * Returns a specific nonce action string
662 */
663 private function mxchat_get_nonce_action() {
664 return 'mxchat_license_nonce';
665 }
666
667 }
668
669 // Initialize the AJAX handler
670 new MxChat_Ajax_Handler();
671