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

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