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

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