Changeset 3343848
- Timestamp:
- 08/13/2025 01:28:41 AM (6 months ago)
- Location:
- mxchat-basic
- Files:
-
- 96 added
- 12 edited
-
tags/2.3.8 (added)
-
tags/2.3.8/admin (added)
-
tags/2.3.8/admin/class-ajax-handler.php (added)
-
tags/2.3.8/admin/class-knowledge-manager.php (added)
-
tags/2.3.8/admin/class-pinecone-manager.php (added)
-
tags/2.3.8/css (added)
-
tags/2.3.8/css/admin-add-ons.css (added)
-
tags/2.3.8/css/admin-style.css (added)
-
tags/2.3.8/css/chat-style.css (added)
-
tags/2.3.8/css/chat-transcripts.css (added)
-
tags/2.3.8/css/content-selector.css (added)
-
tags/2.3.8/css/intent-style.css (added)
-
tags/2.3.8/css/knowledge-style.css (added)
-
tags/2.3.8/css/test-panel.css (added)
-
tags/2.3.8/images (added)
-
tags/2.3.8/images/Icon-01.svg (added)
-
tags/2.3.8/images/Icon-02.svg (added)
-
tags/2.3.8/images/Icon-03.svg (added)
-
tags/2.3.8/images/Icon-04.svg (added)
-
tags/2.3.8/images/pro-only-dark.png (added)
-
tags/2.3.8/includes (added)
-
tags/2.3.8/includes/class-mxchat-addons.php (added)
-
tags/2.3.8/includes/class-mxchat-admin.php (added)
-
tags/2.3.8/includes/class-mxchat-integrator.php (added)
-
tags/2.3.8/includes/class-mxchat-public.php (added)
-
tags/2.3.8/includes/class-mxchat-user.php (added)
-
tags/2.3.8/includes/class-mxchat-utils.php (added)
-
tags/2.3.8/includes/class-mxchat-word-handler.php (added)
-
tags/2.3.8/includes/pdf-parser (added)
-
tags/2.3.8/includes/pdf-parser/alt_autoload.php (added)
-
tags/2.3.8/includes/pdf-parser/src (added)
-
tags/2.3.8/includes/pdf-parser/src/Smalot (added)
-
tags/2.3.8/includes/pdf-parser/src/Smalot/PdfParser (added)
-
tags/2.3.8/includes/pdf-parser/src/Smalot/PdfParser/Config.php (added)
-
tags/2.3.8/includes/pdf-parser/src/Smalot/PdfParser/Document.php (added)
-
tags/2.3.8/includes/pdf-parser/src/Smalot/PdfParser/Element (added)
-
tags/2.3.8/includes/pdf-parser/src/Smalot/PdfParser/Element.php (added)
-
tags/2.3.8/includes/pdf-parser/src/Smalot/PdfParser/Element/ElementArray.php (added)
-
tags/2.3.8/includes/pdf-parser/src/Smalot/PdfParser/Element/ElementBoolean.php (added)
-
tags/2.3.8/includes/pdf-parser/src/Smalot/PdfParser/Element/ElementDate.php (added)
-
tags/2.3.8/includes/pdf-parser/src/Smalot/PdfParser/Element/ElementHexa.php (added)
-
tags/2.3.8/includes/pdf-parser/src/Smalot/PdfParser/Element/ElementMissing.php (added)
-
tags/2.3.8/includes/pdf-parser/src/Smalot/PdfParser/Element/ElementName.php (added)
-
tags/2.3.8/includes/pdf-parser/src/Smalot/PdfParser/Element/ElementNull.php (added)
-
tags/2.3.8/includes/pdf-parser/src/Smalot/PdfParser/Element/ElementNumeric.php (added)
-
tags/2.3.8/includes/pdf-parser/src/Smalot/PdfParser/Element/ElementString.php (added)
-
tags/2.3.8/includes/pdf-parser/src/Smalot/PdfParser/Element/ElementStruct.php (added)
-
tags/2.3.8/includes/pdf-parser/src/Smalot/PdfParser/Element/ElementXRef.php (added)
-
tags/2.3.8/includes/pdf-parser/src/Smalot/PdfParser/Encoding (added)
-
tags/2.3.8/includes/pdf-parser/src/Smalot/PdfParser/Encoding.php (added)
-
tags/2.3.8/includes/pdf-parser/src/Smalot/PdfParser/Encoding/AbstractEncoding.php (added)
-
tags/2.3.8/includes/pdf-parser/src/Smalot/PdfParser/Encoding/EncodingLocator.php (added)
-
tags/2.3.8/includes/pdf-parser/src/Smalot/PdfParser/Encoding/ISOLatin1Encoding.php (added)
-
tags/2.3.8/includes/pdf-parser/src/Smalot/PdfParser/Encoding/ISOLatin9Encoding.php (added)
-
tags/2.3.8/includes/pdf-parser/src/Smalot/PdfParser/Encoding/MacRomanEncoding.php (added)
-
tags/2.3.8/includes/pdf-parser/src/Smalot/PdfParser/Encoding/PDFDocEncoding.php (added)
-
tags/2.3.8/includes/pdf-parser/src/Smalot/PdfParser/Encoding/PostScriptGlyphs.php (added)
-
tags/2.3.8/includes/pdf-parser/src/Smalot/PdfParser/Encoding/StandardEncoding.php (added)
-
tags/2.3.8/includes/pdf-parser/src/Smalot/PdfParser/Encoding/WinAnsiEncoding.php (added)
-
tags/2.3.8/includes/pdf-parser/src/Smalot/PdfParser/Exception (added)
-
tags/2.3.8/includes/pdf-parser/src/Smalot/PdfParser/Exception/EmptyPdfException.php (added)
-
tags/2.3.8/includes/pdf-parser/src/Smalot/PdfParser/Exception/EncodingNotFoundException.php (added)
-
tags/2.3.8/includes/pdf-parser/src/Smalot/PdfParser/Exception/MissingPdfHeaderException.php (added)
-
tags/2.3.8/includes/pdf-parser/src/Smalot/PdfParser/Exception/NotImplementedException.php (added)
-
tags/2.3.8/includes/pdf-parser/src/Smalot/PdfParser/Font (added)
-
tags/2.3.8/includes/pdf-parser/src/Smalot/PdfParser/Font.php (added)
-
tags/2.3.8/includes/pdf-parser/src/Smalot/PdfParser/Font/FontCIDFontType0.php (added)
-
tags/2.3.8/includes/pdf-parser/src/Smalot/PdfParser/Font/FontCIDFontType2.php (added)
-
tags/2.3.8/includes/pdf-parser/src/Smalot/PdfParser/Font/FontTrueType.php (added)
-
tags/2.3.8/includes/pdf-parser/src/Smalot/PdfParser/Font/FontType0.php (added)
-
tags/2.3.8/includes/pdf-parser/src/Smalot/PdfParser/Font/FontType1.php (added)
-
tags/2.3.8/includes/pdf-parser/src/Smalot/PdfParser/Font/FontType3.php (added)
-
tags/2.3.8/includes/pdf-parser/src/Smalot/PdfParser/Header.php (added)
-
tags/2.3.8/includes/pdf-parser/src/Smalot/PdfParser/PDFObject.php (added)
-
tags/2.3.8/includes/pdf-parser/src/Smalot/PdfParser/Page.php (added)
-
tags/2.3.8/includes/pdf-parser/src/Smalot/PdfParser/Pages.php (added)
-
tags/2.3.8/includes/pdf-parser/src/Smalot/PdfParser/Parser.php (added)
-
tags/2.3.8/includes/pdf-parser/src/Smalot/PdfParser/RawData (added)
-
tags/2.3.8/includes/pdf-parser/src/Smalot/PdfParser/RawData/FilterHelper.php (added)
-
tags/2.3.8/includes/pdf-parser/src/Smalot/PdfParser/RawData/RawDataParser.php (added)
-
tags/2.3.8/includes/pdf-parser/src/Smalot/PdfParser/XObject (added)
-
tags/2.3.8/includes/pdf-parser/src/Smalot/PdfParser/XObject/Form.php (added)
-
tags/2.3.8/includes/pdf-parser/src/Smalot/PdfParser/XObject/Image.php (added)
-
tags/2.3.8/js (added)
-
tags/2.3.8/js/activation-script.js (added)
-
tags/2.3.8/js/chat-script.js (added)
-
tags/2.3.8/js/content-selector.js (added)
-
tags/2.3.8/js/knowledge-processing.js (added)
-
tags/2.3.8/js/mxchat-admin.js (added)
-
tags/2.3.8/js/mxchat-test-streaming.js (added)
-
tags/2.3.8/js/mxchat_transcripts.js (added)
-
tags/2.3.8/js/test-panel.js (added)
-
tags/2.3.8/languages (added)
-
tags/2.3.8/languages/mxchat.pot (added)
-
tags/2.3.8/mxchat-basic.php (added)
-
tags/2.3.8/readme.txt (added)
-
trunk/admin/class-ajax-handler.php (modified) (1 diff)
-
trunk/admin/class-knowledge-manager.php (modified) (1 diff)
-
trunk/css/admin-style.css (modified) (1 diff)
-
trunk/css/chat-style.css (modified) (2 diffs)
-
trunk/includes/class-mxchat-addons.php (modified) (1 diff)
-
trunk/includes/class-mxchat-admin.php (modified) (112 diffs)
-
trunk/includes/class-mxchat-integrator.php (modified) (12 diffs)
-
trunk/includes/class-mxchat-public.php (modified) (3 diffs)
-
trunk/js/chat-script.js (modified) (9 diffs)
-
trunk/js/mxchat-admin.js (modified) (1 diff)
-
trunk/mxchat-basic.php (modified) (13 diffs)
-
trunk/readme.txt (modified) (4 diffs)
Legend:
- Unmodified
- Added
- Removed
-
mxchat-basic/trunk/admin/class-ajax-handler.php
r3335923 r3343848 45 45 // ======================================== 46 46 47 /** 48 * Validates and saves chat settings via AJAX request 49 */ 50 public function mxchat_save_setting_callback() { 51 check_ajax_referer('mxchat_save_setting_nonce'); 52 if (!current_user_can('manage_options')) { 53 ('MXChat Save: Unauthorized access attempt'); 54 wp_send_json_error(['message' => esc_html__('Unauthorized', 'mxchat')]); 55 } 56 57 $name = isset($_POST['name']) ? $_POST['name'] : ''; 58 // Strip slashes from the value before saving 59 $value = isset($_POST['value']) ? stripslashes($_POST['value']) : ''; 60 61 //error_log('MXChat Save: Processing field name: ' . $name); 62 //error_log('MXChat Save: Field value: ' . $value); 63 64 if (empty($name)) { 65 //error_log('MXChat Save: Empty field name detected'); 66 wp_send_json_error(['message' => esc_html__('Invalid field name', 'mxchat')]); 67 } 68 69 // Load the full options array 70 $options = get_option('mxchat_options', []); 71 //error_log('MXChat Save: Current options array: ' . print_r($options, true)); 72 73 // Handle special cases 74 switch ($name) { 75 case 'additional_popular_questions': 76 //error_log('MXChat Save: Processing additional_popular_questions'); 77 $questions = json_decode($value, true); // No need for stripslashes here 78 if (is_array($questions)) { 79 $options[$name] = $questions; 80 // Also update old option for backwards compatibility 81 update_option('additional_popular_questions', $questions); 82 //error_log('MXChat Save: Saved ' . count($questions) . ' additional questions'); 83 } else { 84 //error_log('MXChat Save: Failed to decode questions JSON'); 85 } 86 break; 87 case 'email_blocker_header_content': 88 //error_log('MXChat Save: Processing email_blocker_header_content'); 89 // Allow HTML content but sanitize it safely 90 $options[$name] = wp_kses_post($value); 91 break; 92 case 'similarity_threshold': 93 //error_log('MXChat Save: Processing similarity_threshold'); 94 // Save to the options array 95 $options[$name] = $value; 96 break; 97 case 'user_message_bg_color': 98 case 'user_message_font_color': 99 case 'bot_message_bg_color': 100 case 'bot_message_font_color': 101 case 'top_bar_bg_color': 102 case 'send_button_font_color': 103 case 'chatbot_background_color': 104 case 'icon_color': 105 case 'chat_input_font_color': 106 case 'live_agent_message_bg_color': 107 case 'live_agent_message_font_color': 108 case 'mode_indicator_bg_color': 109 case 'mode_indicator_font_color': 110 case 'toolbar_icon_color': 111 case 'quick_questions_toggle_color': 112 //error_log('MXChat Save: Processing color value: ' . $name); 113 // Store color values directly 114 $options[$name] = $value; 115 break; 116 case 'live_agent_status': 117 //error_log('MXChat Save: Processing live_agent_status'); 118 // Set the new value 119 $options[$name] = ($value === 'on') ? 'on' : 'off'; 120 break; 121 case 'enable_woocommerce_integration': 122 //error_log('MXChat Save: Processing enable_woocommerce_integration'); 123 // Handle values that used to be 1/0 124 $options[$name] = ($value === 'on' || $value === '1') ? 'on' : 'off'; 125 break; 126 default: 127 // First check for rate limits settings 128 if (strpos($name, 'mxchat_options[rate_limits]') !== false) { 129 //error_log('MXChat Save: Detected rate_limits field: ' . $name); 130 131 // Extract role ID and setting from the name 132 preg_match('/\[rate_limits\]\[(.*?)\]\[(.*?)\]/', $name, $matches); 133 //error_log('MXChat Save: Regex matches: ' . print_r($matches, true)); 134 135 if (isset($matches[1]) && isset($matches[2])) { 136 $role_id = $matches[1]; 137 $setting_key = $matches[2]; // limit, timeframe, or message 138 139 //error_log('MXChat Save: Role ID = ' . $role_id . ', Setting Key = ' . $setting_key); 140 141 // Initialize rate_limits if it doesn't exist 142 if (!isset($options['rate_limits'])) { 143 // //error_log('MXChat Save: Initializing rate_limits array'); 144 $options['rate_limits'] = []; 145 } 146 147 // Initialize role settings if it doesn't exist 148 if (!isset($options['rate_limits'][$role_id])) { 149 //error_log('MXChat Save: Initializing rate_limits for role: ' . $role_id); 150 $options['rate_limits'][$role_id] = [ 151 'limit' => ($role_id === 'logged_out') ? '10' : '100', 152 'timeframe' => 'daily', 153 'message' => 'Rate limit exceeded. Please try again later.' 154 ]; 155 } 156 157 // Update the specific setting 158 $options['rate_limits'][$role_id][$setting_key] = $value; 159 //error_log('MXChat Save: Updated rate_limits[' . $role_id . '][' . $setting_key . '] = ' . $value); 160 } else { 161 //error_log('MXChat Save: Failed to parse rate_limits pattern: ' . $name); 162 } 163 } 164 // Then check for role rate limits (old format) 165 else if (strpos($name, 'mxchat_options[role_rate_limits]') !== false) { 166 //error_log('MXChat Save: Processing role_rate_limits field: ' . $name); 167 // Extract role ID from the name 168 preg_match('/\[role_rate_limits\]\[(.*?)\]/', $name, $matches); 169 //error_log('MXChat Save: Regex matches: ' . print_r($matches, true)); 170 171 if (isset($matches[1])) { 172 $role_id = $matches[1]; 173 // Initialize role_rate_limits if it doesn't exist 174 if (!isset($options['role_rate_limits'])) { 175 //error_log('MXChat Save: Initializing role_rate_limits array'); 176 $options['role_rate_limits'] = []; 177 } 178 // Update the specific role's rate limit 179 $options['role_rate_limits'][$role_id] = sanitize_text_field($value); 180 //error_log('MXChat Save: Updated role_rate_limits[' . $role_id . '] = ' . $value); 181 } else { 182 //error_log('MXChat Save: Failed to parse role_rate_limits pattern: ' . $name); 183 } 184 } 185 // Handle toggles 186 else if (strpos($name, 'toggle') !== false || in_array($name, [ 187 'chat_persistence_toggle', 188 'privacy_toggle', 189 'complianz_toggle', 190 'chat_toolbar_toggle', 191 'show_pdf_upload_button', 192 'show_word_upload_button', 193 'enable_streaming_toggle', 194 'contextual_awareness_toggle' // Add this line 195 ])) { 196 //error_log('MXChat Save: Processing toggle: ' . $name); 197 $options[$name] = ($value === 'on') ? 'on' : 'off'; 47 /** 48 * Validates and saves chat settings via AJAX request 49 */ 50 public function mxchat_save_setting_callback() { 51 check_ajax_referer('mxchat_save_setting_nonce'); 52 if (!current_user_can('manage_options')) { 53 ('MXChat Save: Unauthorized access attempt'); 54 wp_send_json_error(['message' => esc_html__('Unauthorized', 'mxchat')]); 55 } 56 57 $name = isset($_POST['name']) ? $_POST['name'] : ''; 58 // Strip slashes from the value before saving 59 $value = isset($_POST['value']) ? stripslashes($_POST['value']) : ''; 60 61 //error_log('MXChat Save: Processing field name: ' . $name); 62 //error_log('MXChat Save: Field value: ' . $value); 63 64 if (empty($name)) { 65 //error_log('MXChat Save: Empty field name detected'); 66 wp_send_json_error(['message' => esc_html__('Invalid field name', 'mxchat')]); 67 } 68 69 // Load the full options array 70 $options = get_option('mxchat_options', []); 71 //error_log('MXChat Save: Current options array: ' . print_r($options, true)); 72 73 // Handle special cases 74 switch ($name) { 75 case 'additional_popular_questions': 76 //error_log('MXChat Save: Processing additional_popular_questions'); 77 $questions = json_decode($value, true); // No need for stripslashes here 78 if (is_array($questions)) { 79 $options[$name] = $questions; 80 // Also update old option for backwards compatibility 81 update_option('additional_popular_questions', $questions); 82 //error_log('MXChat Save: Saved ' . count($questions) . ' additional questions'); 83 } else { 84 //error_log('MXChat Save: Failed to decode questions JSON'); 85 } 86 break; 87 case 'email_blocker_header_content': 88 //error_log('MXChat Save: Processing email_blocker_header_content'); 89 // Allow HTML content but sanitize it safely 90 $options[$name] = wp_kses_post($value); 91 break; 92 case 'email_blocker_button_text': 93 //error_log('MXChat Save: Processing email_blocker_button_text'); 94 $options[$name] = sanitize_text_field($value); 95 break; 96 case 'name_field_placeholder': 97 //error_log('MXChat Save: Processing name_field_placeholder'); 98 $options[$name] = sanitize_text_field($value); 99 break; 100 case 'similarity_threshold': 101 //error_log('MXChat Save: Processing similarity_threshold'); 102 // Save to the options array 103 $options[$name] = $value; 104 break; 105 case 'user_message_bg_color': 106 case 'user_message_font_color': 107 case 'bot_message_bg_color': 108 case 'bot_message_font_color': 109 case 'top_bar_bg_color': 110 case 'send_button_font_color': 111 case 'chatbot_background_color': 112 case 'icon_color': 113 case 'chat_input_font_color': 114 case 'live_agent_message_bg_color': 115 case 'live_agent_message_font_color': 116 case 'mode_indicator_bg_color': 117 case 'mode_indicator_font_color': 118 case 'toolbar_icon_color': 119 case 'quick_questions_toggle_color': 120 //error_log('MXChat Save: Processing color value: ' . $name); 121 // Store color values directly 122 $options[$name] = $value; 123 break; 124 case 'live_agent_status': 125 //error_log('MXChat Save: Processing live_agent_status'); 126 // Set the new value 127 $options[$name] = ($value === 'on') ? 'on' : 'off'; 128 break; 129 case 'enable_woocommerce_integration': 130 //error_log('MXChat Save: Processing enable_woocommerce_integration'); 131 // Handle values that used to be 1/0 132 $options[$name] = ($value === 'on' || $value === '1') ? 'on' : 'off'; 133 break; 134 default: 135 // First check for rate limits settings 136 if (strpos($name, 'mxchat_options[rate_limits]') !== false) { 137 //error_log('MXChat Save: Detected rate_limits field: ' . $name); 138 139 // Extract role ID and setting from the name 140 preg_match('/\[rate_limits\]\[(.*?)\]\[(.*?)\]/', $name, $matches); 141 //error_log('MXChat Save: Regex matches: ' . print_r($matches, true)); 142 143 if (isset($matches[1]) && isset($matches[2])) { 144 $role_id = $matches[1]; 145 $setting_key = $matches[2]; // limit, timeframe, or message 146 147 //error_log('MXChat Save: Role ID = ' . $role_id . ', Setting Key = ' . $setting_key); 148 149 // Initialize rate_limits if it doesn't exist 150 if (!isset($options['rate_limits'])) { 151 // //error_log('MXChat Save: Initializing rate_limits array'); 152 $options['rate_limits'] = []; 153 } 154 155 // Initialize role settings if it doesn't exist 156 if (!isset($options['rate_limits'][$role_id])) { 157 //error_log('MXChat Save: Initializing rate_limits for role: ' . $role_id); 158 $options['rate_limits'][$role_id] = [ 159 'limit' => ($role_id === 'logged_out') ? '10' : '100', 160 'timeframe' => 'daily', 161 'message' => 'Rate limit exceeded. Please try again later.' 162 ]; 163 } 164 165 // Update the specific setting 166 $options['rate_limits'][$role_id][$setting_key] = $value; 167 //error_log('MXChat Save: Updated rate_limits[' . $role_id . '][' . $setting_key . '] = ' . $value); 198 168 } else { 199 //error_log('MXChat Save: Processing standard field: ' . $name); 200 // Store all other values directly 201 $options[$name] = $value; 202 } 203 break; 204 } 205 206 // Save all updates to the options array 207 $updated = update_option('mxchat_options', $options); 208 //error_log('MXChat Save: Update result: ' . ($updated ? 'success' : 'unchanged') . ' for field: ' . $name); 209 //error_log('MXChat Save: Updated options array: ' . print_r($options, true)); 210 211 // Always return success even if WordPress says nothing changed 212 // (which happens when the value is the same as before) 213 wp_send_json_success(['message' => esc_html__('Setting saved', 'mxchat')]); 214 } 169 //error_log('MXChat Save: Failed to parse rate_limits pattern: ' . $name); 170 } 171 } 172 // Then check for role rate limits (old format) 173 else if (strpos($name, 'mxchat_options[role_rate_limits]') !== false) { 174 //error_log('MXChat Save: Processing role_rate_limits field: ' . $name); 175 // Extract role ID from the name 176 preg_match('/\[role_rate_limits\]\[(.*?)\]/', $name, $matches); 177 //error_log('MXChat Save: Regex matches: ' . print_r($matches, true)); 178 179 if (isset($matches[1])) { 180 $role_id = $matches[1]; 181 // Initialize role_rate_limits if it doesn't exist 182 if (!isset($options['role_rate_limits'])) { 183 //error_log('MXChat Save: Initializing role_rate_limits array'); 184 $options['role_rate_limits'] = []; 185 } 186 // Update the specific role's rate limit 187 $options['role_rate_limits'][$role_id] = sanitize_text_field($value); 188 //error_log('MXChat Save: Updated role_rate_limits[' . $role_id . '] = ' . $value); 189 } else { 190 //error_log('MXChat Save: Failed to parse role_rate_limits pattern: ' . $name); 191 } 192 } 193 // Handle toggles 194 else if (strpos($name, 'toggle') !== false || in_array($name, [ 195 'chat_persistence_toggle', 196 'privacy_toggle', 197 'complianz_toggle', 198 'chat_toolbar_toggle', 199 'show_pdf_upload_button', 200 'show_word_upload_button', 201 'enable_streaming_toggle', 202 'contextual_awareness_toggle', 203 'enable_email_block', 204 'enable_name_field' 205 ])) { 206 //error_log('MXChat Save: Processing toggle: ' . $name); 207 $options[$name] = ($value === 'on') ? 'on' : 'off'; 208 } else { 209 //error_log('MXChat Save: Processing standard field: ' . $name); 210 // Store all other values directly 211 $options[$name] = $value; 212 } 213 break; 214 } 215 216 // Save all updates to the options array 217 $updated = update_option('mxchat_options', $options); 218 //error_log('MXChat Save: Update result: ' . ($updated ? 'success' : 'unchanged') . ' for field: ' . $name); 219 //error_log('MXChat Save: Updated options array: ' . print_r($options, true)); 220 221 // Always return success even if WordPress says nothing changed 222 // (which happens when the value is the same as before) 223 wp_send_json_success(['message' => esc_html__('Setting saved', 'mxchat')]); 224 } 215 225 216 226 -
mxchat-basic/trunk/admin/class-knowledge-manager.php
r3333920 r3343848 723 723 // If we get here, nonce passed 724 724 error_log('Nonce verification PASSED'); 725 726 // Verify permissions 727 if (!current_user_can('manage_options')) { 728 wp_send_json_error(esc_html__('Permission denied.', 'mxchat')); 729 return; 730 } 731 732 global $wpdb; 733 $table_name = $wpdb->prefix . 'mxchat_system_prompt_content'; 734 735 // Validate and sanitize input data 736 $prompt_id = isset($_POST['id']) ? absint($_POST['id']) : 0; 737 $article_content = isset($_POST['article_content']) ? sanitize_textarea_field($_POST['article_content']) : ''; 738 $article_url = isset($_POST['article_url']) ? esc_url_raw($_POST['article_url']) : ''; 739 740 if ($prompt_id > 0 && !empty($article_content)) { 741 // Re-generate the embedding vector for the updated content 742 $embedding_vector = $this->mxchat_generate_embedding($article_content); 743 744 if (is_array($embedding_vector)) { 745 // Serialize the embedding vector before storing it 746 $embedding_vector_serialized = serialize($embedding_vector); 747 748 // Update the prompt in the database 749 $updated = $wpdb->update( 750 $table_name, 751 array( 752 'article_content' => $article_content, 753 'embedding_vector' => $embedding_vector_serialized, 754 'source_url' => $article_url, 755 ), 756 array('id' => $prompt_id), 757 array('%s', '%s', '%s'), 758 array('%d') 759 ); 760 761 if ($updated !== false) { 762 wp_send_json_success(); 763 } else { 764 wp_send_json_error(esc_html__('Database update failed.', 'mxchat')); 765 } 766 } else { 767 wp_send_json_error(esc_html__('Embedding generation failed.', 'mxchat')); 768 } 769 } else { 770 wp_send_json_error(esc_html__('Invalid data.', 'mxchat')); 771 } 772 } 725 726 // Verify permissions 727 if (!current_user_can('manage_options')) { 728 wp_send_json_error(esc_html__('Permission denied.', 'mxchat')); 729 return; 730 } 731 732 global $wpdb; 733 $table_name = $wpdb->prefix . 'mxchat_system_prompt_content'; 734 735 // Validate and sanitize input data - FIXED LINE BELOW 736 $prompt_id = isset($_POST['id']) ? absint($_POST['id']) : 0; 737 $article_content = isset($_POST['article_content']) ? sanitize_textarea_field(wp_unslash($_POST['article_content'])) : ''; 738 $article_url = isset($_POST['article_url']) ? esc_url_raw($_POST['article_url']) : ''; 739 740 if ($prompt_id > 0 && !empty($article_content)) { 741 // Re-generate the embedding vector for the updated content 742 $embedding_vector = $this->mxchat_generate_embedding($article_content); 743 if (is_array($embedding_vector)) { 744 // Serialize the embedding vector before storing it 745 $embedding_vector_serialized = serialize($embedding_vector); 746 // Update the prompt in the database 747 $updated = $wpdb->update( 748 $table_name, 749 array( 750 'article_content' => $article_content, 751 'embedding_vector' => $embedding_vector_serialized, 752 'source_url' => $article_url, 753 ), 754 array('id' => $prompt_id), 755 array('%s', '%s', '%s'), 756 array('%d') 757 ); 758 if ($updated !== false) { 759 wp_send_json_success(); 760 } else { 761 wp_send_json_error(esc_html__('Database update failed.', 'mxchat')); 762 } 763 } else { 764 wp_send_json_error(esc_html__('Embedding generation failed.', 'mxchat')); 765 } 766 } else { 767 wp_send_json_error(esc_html__('Invalid data.', 'mxchat')); 768 } 769 } 773 770 774 771 -
mxchat-basic/trunk/css/admin-style.css
r3341601 r3343848 5223 5223 border-left: 4px solid #72aee6; 5224 5224 } 5225 5226 5227 /* Hide email-dependent fields by default */ 5228 tr:has(#email_blocker_header_content), 5229 tr:has(#email_blocker_button_text), 5230 tr:has(#enable_name_field), 5231 tr:has(#name_field_placeholder) { 5232 display: none; 5233 } 5234 5235 /* Show them when email block is enabled */ 5236 body.email-block-enabled tr:has(#email_blocker_header_content), 5237 body.email-block-enabled tr:has(#email_blocker_button_text), 5238 body.email-block-enabled tr:has(#enable_name_field), 5239 body.email-block-enabled tr:has(#name_field_placeholder) { 5240 display: table-row; 5241 } 5242 5243 /* Style for email-dependent fields */ 5244 .email-dependent-field { 5245 background-color: #f8f9fa; 5246 border-left: 4px solid #0073aa; 5247 padding-left: 15px; 5248 margin-left: 10px; 5249 } 5250 5251 .email-dependent-field td, 5252 .email-dependent-field th { 5253 background-color: #f8f9fa; 5254 } -
mxchat-basic/trunk/css/chat-style.css
r3323559 r3343848 59 59 } 60 60 61 .email-blocker input[type="email"] { 61 .email-blocker input[type="email"], 62 .email-blocker .mxchat-name-input { 62 63 width: 100%; 63 64 padding: 12px; … … 71 72 } 72 73 73 .email-blocker input[type="email"]:focus { 74 .email-blocker input[type="email"]:focus, 75 .email-blocker .mxchat-name-input:focus { 74 76 border-color: #0073aa; 75 77 box-shadow: 0 0 8px rgba(0, 115, 170, 0.3); -
mxchat-basic/trunk/includes/class-mxchat-addons.php
r3341601 r3343848 161 161 */ 162 162 public function enqueue_styles() { 163 $plugin_version = '2.3. 7';163 $plugin_version = '2.3.8'; 164 164 165 165 wp_enqueue_style( -
mxchat-basic/trunk/includes/class-mxchat-admin.php
r3341601 r3343848 45 45 46 46 add_action('admin_notices', array($this, 'display_admin_notices')); 47 47 48 48 add_action('wp_ajax_mxchat_test_streaming_actual', [$this, 'mxchat_handle_test_streaming_actual']); 49 49 add_action('wp_ajax_mxchat_test_streaming', [$this, 'mxchat_handle_test_streaming']); // Keep existing as fallback 50 50 51 51 52 52 } … … 96 96 'email_blocker_header_content' => __("<h2>Welcome to Our Chat!</h2>\n<p>Let's get started. Enter your email to begin chatting with us.</p>", 'mxchat'), 97 97 'email_blocker_button_text' => esc_html__('Start Chat', 'mxchat'), 98 'enable_name_field' => 'off', // NEW 99 'name_field_placeholder' => esc_html__('Enter your name', 'mxchat'), // NEW 98 100 'top_bar_title' => esc_html__('MxChat', 'mxchat'), 99 101 'intro_message' => __('Hello! How can I assist you today?', 'mxchat'), … … 237 239 public function mxchat_handle_test_streaming_actual() { 238 240 check_ajax_referer('mxchat_test_streaming_nonce', 'nonce'); 239 241 240 242 // Check if headers have already been sent 241 243 if (headers_sent()) { … … 243 245 return; 244 246 } 245 247 246 248 // Check for required functions 247 249 if (!function_exists('curl_init')) { … … 249 251 return; 250 252 } 251 253 252 254 // Get user's selected model and API key 253 255 $options = get_option('mxchat_options', []); 254 256 $selected_model = $options['model'] ?? 'gpt-4o'; 255 257 256 258 // Get the provider from the model 257 259 $model_parts = explode('-', $selected_model); 258 260 $provider = strtolower($model_parts[0]); 259 261 260 262 // Get the appropriate API key 261 263 $api_key = ''; … … 283 285 break; 284 286 } 285 287 286 288 if (empty($api_key)) { 287 289 wp_send_json_error(['message' => "API key not configured for {$provider} provider"]); 288 290 return; 289 291 } 290 292 291 293 // Test streaming with the selected model and provider 292 294 try { … … 305 307 header('Cache-Control: no-cache'); 306 308 header('X-Accel-Buffering: no'); // Disable nginx buffering 307 309 308 310 // Prepare test message 309 311 $test_message = "Please respond with exactly: 'Streaming test successful!' - send this as a short response for testing."; 310 312 311 313 // Configure API request based on provider 312 314 $url = ''; 313 315 $headers = []; 314 316 $body = []; 315 317 316 318 switch ($provider) { 317 319 case 'gpt': … … 330 332 ]; 331 333 break; 332 334 333 335 case 'claude': 334 336 $url = 'https://api.anthropic.com/v1/messages'; … … 346 348 ]; 347 349 break; 348 350 349 351 case 'grok': 350 352 $url = 'https://api.x.ai/v1/chat/completions'; … … 361 363 ]; 362 364 break; 363 365 364 366 case 'deepseek': 365 367 $url = 'https://api.deepseek.com/v1/chat/completions'; … … 376 378 ]; 377 379 break; 378 380 379 381 default: 380 382 echo "data: " . json_encode(['error' => 'Unsupported provider for streaming test: ' . $provider]) . "\n\n"; … … 382 384 return; 383 385 } 384 386 385 387 // Initialize cURL 386 388 $ch = curl_init(); … … 395 397 return $this->process_streaming_test_data($data, $provider); 396 398 }); 397 399 398 400 // Send initial test message 399 401 echo "data: " . json_encode(['content' => '[Starting streaming test...]']) . "\n\n"; 400 402 flush(); 401 403 402 404 $result = curl_exec($ch); 403 405 $http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE); 404 406 $curl_error = curl_error($ch); 405 407 curl_close($ch); 406 408 407 409 if ($curl_error) { 408 410 echo "data: " . json_encode(['error' => 'cURL Error: ' . $curl_error]) . "\n\n"; … … 410 412 return; 411 413 } 412 414 413 415 if ($http_code !== 200) { 414 416 echo "data: " . json_encode(['error' => 'API returned HTTP ' . $http_code]) . "\n\n"; … … 416 418 return; 417 419 } 418 420 419 421 // Send completion signal 420 422 echo "data: [DONE]\n\n"; … … 427 429 private function process_streaming_test_data($data, $provider) { 428 430 static $chunk_count = 0; 429 431 430 432 $lines = explode("\n", $data); 431 433 432 434 foreach ($lines as $line) { 433 435 if (trim($line) === '') { 434 436 continue; 435 437 } 436 438 437 439 // Handle different provider formats 438 440 if ($provider === 'claude') { … … 441 443 $json_str = substr($line, 6); 442 444 $json = json_decode($json_str, true); 443 445 444 446 if (isset($json['type']) && $json['type'] === 'content_block_delta') { 445 447 if (isset($json['delta']['text'])) { … … 457 459 if (strpos($line, 'data: ') === 0) { 458 460 $json_str = substr($line, 6); 459 461 460 462 if ($json_str === '[DONE]') { 461 463 // Don't echo [DONE] here, let the main function handle it 462 464 continue; 463 465 } 464 466 465 467 $json = json_decode($json_str, true); 466 468 if (isset($json['choices'][0]['delta']['content'])) { … … 475 477 } 476 478 } 477 479 478 480 return strlen($data); 479 481 } … … 484 486 public function mxchat_handle_test_streaming() { 485 487 check_ajax_referer('mxchat_test_streaming_nonce', 'nonce'); 486 488 487 489 // Use the actual streaming test instead 488 490 $this->mxchat_handle_test_streaming_actual(); … … 549 551 public function show_live_agent_disabled_banner() { 550 552 $show_disabled_notice = get_option('mxchat_show_live_agent_disabled_notice', false); 551 553 552 554 if ($show_disabled_notice) { 553 555 ?> … … 609 611 </div> 610 612 <?php endif; ?> 611 612 <?php 613 $this->show_live_agent_disabled_banner(); 613 614 <?php 615 $this->show_live_agent_disabled_banner(); 614 616 ?> 615 617 … … 700 702 701 703 <div class="tutorial-grid"> 702 704 703 705 <div class="tutorial-item"> 704 706 <h3><?php echo esc_html__('AI Theme Generator Tutorial', 'mxchat'); ?></h3> … … 712 714 </div> 713 715 714 716 715 717 <div class="tutorial-item"> 716 718 <h3><?php echo esc_html__('MxChat Forms Tutorial', 'mxchat'); ?></h3> … … 860 862 //error_log('dismiss_live_agent_notice called'); 861 863 //error_log('POST data: ' . print_r($_POST, true)); 862 864 863 865 // Verify nonce 864 866 if (!wp_verify_nonce($_POST['nonce'], 'dismiss_live_agent_notice')) { … … 866 868 wp_die('Security check failed'); 867 869 } 868 870 869 871 // Remove the notice flag 870 872 $deleted = delete_option('mxchat_show_live_agent_disabled_notice'); 871 873 //error_log('Option deleted: ' . ($deleted ? 'yes' : 'no')); 872 874 873 875 wp_send_json_success(); 874 876 } … … 1198 1200 session_id LIKE %s 1199 1201 OR user_email LIKE %s 1202 OR user_name LIKE %s 1200 1203 OR user_identifier LIKE %s 1201 1204 OR message LIKE %s 1202 1205 )"; 1203 $search_params = array_fill(0, 4, '%' . $wpdb->esc_like($search) . '%');1206 $search_params = array_fill(0, 5, '%' . $wpdb->esc_like($search) . '%'); 1204 1207 } 1205 1208 … … 1250 1253 $session_data = $originating_columns_exist 1251 1254 ? $wpdb->get_row($wpdb->prepare( 1252 "SELECT user_email, user_ identifier, originating_page_url, originating_page_title, timestamp1255 "SELECT user_email, user_name, user_identifier, originating_page_url, originating_page_title, timestamp 1253 1256 FROM {$table_name} WHERE session_id = %s ORDER BY timestamp ASC LIMIT 1", 1254 1257 $session_id 1255 1258 )) 1256 1259 : $wpdb->get_row($wpdb->prepare( 1257 "SELECT user_email, user_ identifier, timestamp FROM {$table_name}1260 "SELECT user_email, user_name, user_identifier, timestamp FROM {$table_name} 1258 1261 WHERE session_id = %s LIMIT 1", 1259 1262 $session_id … … 1286 1289 1287 1290 $user_email = !empty($session_data->user_email) ? $session_data->user_email : ''; 1291 $user_name = !empty($session_data->user_name) ? $session_data->user_name : ''; // NEW 1288 1292 $user_identifier = !empty($session_data->user_identifier) ? $session_data->user_identifier : 'Guest'; 1289 $user_display = !empty($user_email) ? $user_email : $user_identifier; 1290 1293 1294 // NEW: Build user display with name if available 1295 if (!empty($user_email)) { 1296 $user_display = $user_email; 1297 if (!empty($user_name)) { 1298 $user_display .= ' (' . $user_name . ')'; 1299 } 1300 } else { 1301 $user_display = $user_identifier; 1302 } 1291 1303 echo '<div class="mxchat-session">'; 1292 1304 echo '<div class="mxchat-session-header" data-session-id="' . esc_attr($session_id) . '">'; … … 1447 1459 ); 1448 1460 } 1449 1461 1450 1462 // First apply standard sanitization 1451 1463 $message_content = wp_kses( … … 1457 1469 ] 1458 1470 ); 1459 1471 1460 1472 // Process each clicked URL 1461 1473 foreach ($clicked_urls as $clicked_url) { … … 1469 1481 '/<a([^>]*href=["\']' . preg_quote(htmlentities($clicked_url), '/') . '["\'][^>]*)>/i', 1470 1482 ]; 1471 1483 1472 1484 foreach ($patterns as $pattern) { 1473 1485 if (preg_match($pattern, $message_content)) { … … 1477 1489 $full_match = $matches[0]; 1478 1490 $attributes = $matches[1]; 1479 1491 1480 1492 // Check if it already has the class 1481 1493 if (strpos($full_match, 'mxchat-clicked-link') !== false) { 1482 1494 return $full_match; 1483 1495 } 1484 1496 1485 1497 // Check if class attribute exists 1486 1498 if (preg_match('/class=["\']([^"\']*)["\']/', $attributes, $class_matches)) { … … 1495 1507 $new_attributes = $attributes . ' class="mxchat-clicked-link"'; 1496 1508 } 1497 1509 1498 1510 // Add title if not present 1499 1511 if (strpos($new_attributes, 'title=') === false) { 1500 1512 $new_attributes .= ' title="User clicked this link"'; 1501 1513 } 1502 1514 1503 1515 return '<a' . $new_attributes . '>'; 1504 1516 }, 1505 1517 $message_content 1506 1518 ); 1507 1519 1508 1520 // If we found and replaced, break out of the patterns loop 1509 1521 break; … … 1511 1523 } 1512 1524 } 1513 1525 1514 1526 return $message_content; 1515 1527 } … … 1517 1529 public function mxchat_create_prompts_page() { 1518 1530 //error_log('=== DEBUG: mxchat_create_prompts_page started ==='); 1519 1531 1520 1532 global $wpdb; 1521 1533 $table_name = $wpdb->prefix . 'mxchat_system_prompt_content'; 1522 1534 1523 1535 $knowledge_manager = MxChat_Knowledge_Manager::get_instance(); 1524 1536 $pinecone_manager = MxChat_Pinecone_Manager::get_instance(); … … 1546 1558 $pinecone_options = get_option('mxchat_pinecone_addon_options', array()); 1547 1559 //error_log('DEBUG: Pinecone options retrieved: ' . print_r($pinecone_options, true)); 1548 1560 1549 1561 $use_pinecone = ($pinecone_options['mxchat_use_pinecone'] ?? '0') === '1'; 1550 1562 //error_log('DEBUG: use_pinecone decision: ' . ($use_pinecone ? 'TRUE' : 'FALSE')); 1551 1563 1552 1564 $pinecone_api_key = $pinecone_options['mxchat_pinecone_api_key'] ?? ''; 1553 1565 //error_log('DEBUG: Pinecone API key present: ' . (!empty($pinecone_api_key) ? 'YES' : 'NO')); … … 1559 1571 $pinecone_manager = MxChat_Pinecone_Manager::get_instance(); 1560 1572 //error_log('DEBUG: About to call mxchat_fetch_pinecone_records'); 1561 1573 1562 1574 $records = $pinecone_manager->mxchat_fetch_pinecone_records($pinecone_options, $search_query, $current_page, $per_page); 1563 1575 $total_records = $records['total'] ?? 0; … … 1567 1579 1568 1580 $total_pages = ceil($total_records / $per_page); 1569 1581 1570 1582 //error_log('DEBUG: Pinecone - total_records: ' . $total_records); 1571 1583 //error_log('DEBUG: Pinecone - prompts count: ' . count($prompts)); … … 1577 1589 // WORDPRESS DB DATA SOURCE (your existing logic) 1578 1590 $data_source = 'wordpress'; 1579 1591 1580 1592 // Initialize these variables for WordPress DB 1581 1593 $total_in_database = 0; … … 1593 1605 $count_query = "SELECT COUNT(*) FROM {$table_name} {$sql_search}"; 1594 1606 //error_log('DEBUG: WordPress count query: ' . $count_query); 1595 1607 1596 1608 $total_records = $wpdb->get_var($count_query); 1597 1609 //error_log('DEBUG: WordPress total_records: ' . $total_records); 1598 1610 1599 1611 $total_pages = ceil($total_records / $per_page); 1600 1612 … … 1606 1618 ); 1607 1619 //error_log('DEBUG: WordPress prompts query: ' . $prompts_query); 1608 1620 1609 1621 $prompts = $wpdb->get_results($prompts_query); 1610 1622 //error_log('DEBUG: WordPress prompts count: ' . count($prompts)); … … 1649 1661 1650 1662 //error_log('=== DEBUG: mxchat_create_prompts_page data preparation completed ==='); 1651 1663 1652 1664 ?> 1653 1665 … … 1776 1788 </div> 1777 1789 </button> 1778 1790 1779 1791 <!-- PDF Import Option --> 1780 1792 <button type="button" class="mxchat-import-box" data-option="pdf" data-placeholder="<?php esc_attr_e('Enter PDF URL here', 'mxchat'); ?>" data-type="pdf"> … … 1846 1858 <div class="mxchat-status-header"> 1847 1859 <h4><?php esc_html_e('PDF Processing Status', 'mxchat'); ?></h4> 1848 1860 1849 1861 <!-- Processing controls --> 1850 1862 <div class="mxchat-processing-controls"> … … 1856 1868 </button> 1857 1869 </form> 1858 1859 <button type="button" class="mxchat-manual-batch-btn" 1870 1871 <button type="button" class="mxchat-manual-batch-btn" 1860 1872 data-process-type="pdf" 1861 1873 data-url="<?php echo esc_attr(get_transient('mxchat_last_pdf_url')); ?>"> … … 1864 1876 </div> 1865 1877 </div> 1866 1878 1867 1879 <div class="mxchat-progress-bar"> 1868 1880 <div class="mxchat-progress-fill" style="width: <?php echo esc_attr($pdf_status['percentage']); ?>%"></div> 1869 1881 </div> 1870 1882 1871 1883 <div class="mxchat-status-details"> 1872 1884 <p><?php printf( … … 1876 1888 absint($pdf_status['percentage']) 1877 1889 ); ?></p> 1878 1890 1879 1891 <?php if (!empty($pdf_status['failed_pages']) && $pdf_status['failed_pages'] > 0) : ?> 1880 1892 <p><strong><?php esc_html_e('Failed pages:', 'mxchat'); ?></strong> <?php echo esc_html($pdf_status['failed_pages']); ?></p> 1881 1893 <?php endif; ?> 1882 1894 1883 1895 <p><strong><?php esc_html_e('Status:', 'mxchat'); ?></strong> <?php echo esc_html(ucfirst($pdf_status['status'])); ?></p> 1884 1896 <p><strong><?php esc_html_e('Last update:', 'mxchat'); ?></strong> <?php echo esc_html($pdf_status['last_update']); ?></p> … … 1892 1904 <div class="mxchat-status-header"> 1893 1905 <h4><?php esc_html_e('Sitemap Processing Status', 'mxchat'); ?></h4> 1894 1906 1895 1907 <!-- Processing controls --> 1896 1908 <div class="mxchat-processing-controls"> … … 1902 1914 </button> 1903 1915 </form> 1904 1905 <button type="button" class="mxchat-manual-batch-btn" 1916 1917 <button type="button" class="mxchat-manual-batch-btn" 1906 1918 data-process-type="sitemap" 1907 1919 data-url="<?php echo esc_attr(get_transient('mxchat_last_sitemap_url')); ?>"> … … 1910 1922 </div> 1911 1923 </div> 1912 1924 1913 1925 <div class="mxchat-progress-bar"> 1914 1926 <div class="mxchat-progress-fill" style="width: <?php echo esc_attr($sitemap_status['percentage']); ?>%"></div> 1915 1927 </div> 1916 1928 1917 1929 <div class="mxchat-status-details"> 1918 1930 <p><?php printf( … … 1922 1934 absint($sitemap_status['percentage']) 1923 1935 ); ?></p> 1924 1936 1925 1937 <?php if (!empty($sitemap_status['failed_urls']) && $sitemap_status['failed_urls'] > 0) : ?> 1926 1938 <p><strong><?php esc_html_e('Failed URLs:', 'mxchat'); ?></strong> <?php echo esc_html($sitemap_status['failed_urls']); ?></p> 1927 1939 <?php endif; ?> 1928 1940 1929 1941 <p><strong><?php esc_html_e('Status:', 'mxchat'); ?></strong> <?php echo esc_html(ucfirst($sitemap_status['status'])); ?></p> 1930 1942 <p><strong><?php esc_html_e('Last update:', 'mxchat'); ?></strong> <?php echo esc_html($sitemap_status['last_update']); ?></p> 1931 1943 1932 1944 <?php if (!empty($sitemap_status['error']) || !empty($sitemap_status['last_error'])) : ?> 1933 1945 <div class="mxchat-error-notice"> … … 1945 1957 1946 1958 <!-- Single URL Submission Status --> 1947 <?php 1959 <?php 1948 1960 // Get single URL status 1949 1961 $single_url_status = $this->knowledge_manager->mxchat_get_single_url_status(); 1950 $is_active_processing = 1951 ($sitemap_status && $sitemap_status['status'] === 'processing') || 1962 $is_active_processing = 1963 ($sitemap_status && $sitemap_status['status'] === 'processing') || 1952 1964 ($pdf_status && $pdf_status['status'] === 'processing'); 1953 1965 ?> … … 1965 1977 </div> 1966 1978 <div class="mxchat-status-details"> 1967 <p><strong><?php esc_html_e('URL:', 'mxchat'); ?></strong> 1979 <p><strong><?php esc_html_e('URL:', 'mxchat'); ?></strong> 1968 1980 <a href="<?php echo esc_url($single_url_status['url']); ?>" target="_blank"> 1969 1981 <?php echo esc_html(strlen($single_url_status['url']) > 60 ? substr($single_url_status['url'], 0, 57) . '...' : $single_url_status['url']); ?> … … 1986 1998 <?php endif; ?> 1987 1999 </div> 1988 2000 1989 2001 <!-- Completed Status Cards - Handles completed PDF/Sitemap processing --> 1990 2002 <?php … … 2049 2061 </div> 2050 2062 </div> 2051 2063 2052 2064 <!-- Recent Entries Info Banner --> 2053 2065 <?php if ($showing_recent_only && $total_in_database > 1000): ?> … … 2125 2137 <textarea class="content-edit" style="display:none;" 2126 2138 <?php if (preg_match('/[\x{0590}-\x{05FF}]/u', $prompt->article_content)) echo 'dir="rtl" lang="he"'; ?>> 2127 <?php echo esc_textarea($prompt->article_content); ?>2139 <?php echo htmlspecialchars($prompt->article_content, ENT_QUOTES, 'UTF-8'); ?> 2128 2140 </textarea> 2129 2141 <?php endif; ?> … … 2142 2154 <?php if ($data_source === 'wordpress') : ?> 2143 2155 <input type="text" class="url-edit" style="display:none;" 2144 value="<?php echo esc_attr($prompt->source_url); ?>" />2156 value="<?php echo htmlspecialchars($prompt->source_url, ENT_QUOTES, 'UTF-8'); ?>" /> 2145 2157 <?php endif; ?> 2146 2158 </td> … … 2177 2189 <?php if ($data_source === 'pinecone') : ?> 2178 2190 <!-- AJAX Delete for Pinecone --> 2179 <button type="button" 2191 <button type="button" 2180 2192 class="mxchat-button-icon delete-button-ajax" 2181 2193 data-vector-id="<?php echo esc_attr($prompt->id); ?>" … … 2574 2586 <?php 2575 2587 } 2588 2589 2576 2590 public function mxchat_delete_chat_history() { 2577 2591 if (!current_user_can('manage_options')) { … … 2621 2635 wp_die(); 2622 2636 } 2623 2624 2637 public function display_admin_notices() { 2625 2638 // Check if we're on a MXChat admin page … … 2667 2680 $license_error = get_option('mxchat_license_error', ''); 2668 2681 $current_domain = parse_url(home_url(), PHP_URL_HOST); 2669 2670 // Your website URL - change this to your actual website 2671 $license_management_url = 'https://mxchat.ai/my-account/license-management/'; 2672 2682 2683 $license_management_url = 'https://mxchat.ai/my-account/orders/'; 2684 2673 2685 // Check if this activation has been linked to a domain 2674 2686 $is_domain_linked = $this->is_current_activation_linked($current_domain); … … 2687 2699 </p> 2688 2700 </div> 2689 2701 2690 2702 <?php if ($license_status === 'inactive' && !empty($license_error)): ?> 2691 2703 <div class="error notice"> … … 2693 2705 </div> 2694 2706 <?php endif; ?> 2695 2707 2696 2708 <!-- Domain Linking Notice for Existing Users --> 2697 2709 <?php if ($license_status === 'active' && !$is_domain_linked): ?> … … 2709 2721 </div> 2710 2722 <?php endif; ?> 2711 2723 2712 2724 <!-- Activation Form --> 2713 2725 <form id="mxchat-activation-form" class="mxchat-pro-form" style="<?php echo $license_status === 'active' ? 'display: none;' : ''; ?>"> … … 2727 2739 </tr> 2728 2740 </table> 2729 2741 2730 2742 <!-- Hidden field for domain --> 2731 2743 <input type="hidden" id="mxchat_domain" name="domain" value="<?php echo esc_attr($current_domain); ?>" /> 2732 2744 2733 2745 <?php if ($license_status !== 'active'): ?> 2734 2746 <div class="mxchat-pro-button-container"> … … 2739 2751 </div> 2740 2752 </form> 2741 2753 2742 2754 <!-- License Status Display --> 2743 2755 <div class="mxchat-pro-status"> … … 2747 2759 </span> 2748 2760 </h3> 2749 2761 2750 2762 <?php if ($license_status === 'active'): ?> 2751 2763 <div class="mxchat-license-details"> … … 2758 2770 </p> 2759 2771 <p><strong><?php esc_html_e('Email:', 'mxchat'); ?></strong> <?php echo esc_html(get_option('mxchat_pro_email')); ?></p> 2760 <p><strong><?php esc_html_e('License Key:', 'mxchat'); ?></strong> 2772 <p><strong><?php esc_html_e('License Key:', 'mxchat'); ?></strong> 2761 2773 <code style="background: #f1f1f1; padding: 2px 6px; border-radius: 3px;"> 2762 2774 <?php echo esc_html(get_option('mxchat_activation_key')); ?> … … 2765 2777 <p> 2766 2778 <small> 2767 <?php esc_html_e('Manage all your licenses and domains on', 'mxchat'); ?> 2779 <?php esc_html_e('Manage all your licenses and domains on', 'mxchat'); ?> 2768 2780 <a href="<?php echo esc_url($license_management_url); ?>" target="_blank"> 2769 2781 <?php esc_html_e('your account dashboard', 'mxchat'); ?> … … 2771 2783 </small> 2772 2784 </p> 2773 2785 2774 2786 <!-- Deactivation Section --> 2775 2787 <div class="mxchat-deactivation-section" style="margin-top: 20px; padding: 15px; background: #fff3cd; border-left: 4px solid #ffc107; border-radius: 4px;"> … … 2788 2800 <?php endif; ?> 2789 2801 </div> 2790 2802 2791 2803 <!-- Hidden fields for JavaScript --> 2792 2804 <input type="hidden" id="mxchat-ajax-url" value="<?php echo admin_url('admin-ajax.php'); ?>" /> … … 2804 2816 $license_key = get_option('mxchat_activation_key'); 2805 2817 $email = get_option('mxchat_pro_email'); 2806 2818 2807 2819 if (empty($license_key) || empty($email)) { 2808 2820 return false; 2809 2821 } 2810 2822 2811 2823 // Check with YOUR website's API 2812 2824 $response = wp_remote_post('https://mxchat.ai/mxchat-api/check-domain', array( … … 2819 2831 'sslverify' => false 2820 2832 )); 2821 2833 2822 2834 if (is_wp_error($response)) { 2823 2835 return false; 2824 2836 } 2825 2837 2826 2838 $body = json_decode(wp_remote_retrieve_body($response), true); 2827 2839 return isset($body['success']) && $body['success'] && isset($body['data']['linked']) && $body['data']['linked']; … … 3752 3764 'mxchat_chatbot_section' 3753 3765 ); 3754 3766 3755 3767 add_settings_field( 3756 3768 'contextual_awareness_toggle', … … 3832 3844 ) 3833 3845 ); 3834 3846 3835 3847 add_settings_field( 3836 3848 'enable_streaming_toggle', … … 3853 3865 'mxchat_chatbot_section' 3854 3866 ); 3855 3867 3856 3868 add_settings_field( 3857 3869 'embedding_model', … … 3907 3919 esc_html__('Require Email Chat Button Text', 'mxchat'), 3908 3920 [$this, 'email_blocker_button_text_callback'], 3921 'mxchat-chatbot', 3922 'mxchat_chatbot_section' 3923 ); 3924 3925 add_settings_field( 3926 'enable_name_field', 3927 esc_html__('Require Name Field', 'mxchat'), 3928 array($this, 'enable_name_field_callback'), 3929 'mxchat-chatbot', 3930 'mxchat_chatbot_section' 3931 ); 3932 3933 add_settings_field( 3934 'name_field_placeholder', 3935 esc_html__('Name Field Placeholder', 'mxchat'), 3936 array($this, 'name_field_placeholder_callback'), 3909 3937 'mxchat-chatbot', 3910 3938 'mxchat_chatbot_section' … … 4204 4232 'mxchat_live_agent_section' 4205 4233 ); 4206 4234 4207 4235 add_settings_field( 4208 4236 'live_agent_user_ids', … … 4502 4530 esc_textarea($custom_message) . 4503 4531 '</textarea>'; 4504 echo '<p class="description">' . 4505 esc_html__('Example: Rate limit reached! [Visit our pricing page](https://example.com/pricing) to upgrade.', 'mxchat') . 4532 echo '<p class="description">' . 4533 esc_html__('Example: Rate limit reached! [Visit our pricing page](https://example.com/pricing) to upgrade.', 'mxchat') . 4506 4534 '</p>'; 4507 4535 echo '</div>'; // End message … … 4853 4881 $enabled = isset($this->options['enable_streaming_toggle']) ? $this->options['enable_streaming_toggle'] : 'on'; 4854 4882 $checked = ($enabled === 'on') ? 'checked' : ''; 4855 4883 4856 4884 echo '<label class="toggle-switch">'; 4857 4885 echo sprintf( … … 4861 4889 echo '<span class="slider"></span>'; 4862 4890 echo '</label>'; 4863 echo '<p class="description">' . 4864 esc_html__('Enable real-time streaming responses for supported models (OpenAI, Claude, and Grok). When disabled, responses will load all at once.', 'mxchat') . 4891 echo '<p class="description">' . 4892 esc_html__('Enable real-time streaming responses for supported models (OpenAI, Claude, and Grok). When disabled, responses will load all at once.', 'mxchat') . 4865 4893 '</p>'; 4866 4894 4867 4895 // Test button with better styling 4868 4896 echo '<div style="margin-top: 15px;">'; … … 4981 5009 echo '<p class="description">'; 4982 5010 echo esc_html__('Enter the text you want on the submit button, e.g. "Start Chat".', 'mxchat'); 5011 echo '</p>'; 5012 } 5013 5014 5015 //Enable name field callback 5016 public function enable_name_field_callback() { 5017 // Load full plugin options array 5018 $all_options = get_option('mxchat_options', []); 5019 // Get the value, default to 'off' 5020 $enable_name_field = isset($all_options['enable_name_field']) ? $all_options['enable_name_field'] : 'off'; 5021 // Check if it's 'on' 5022 $checked = ($enable_name_field === 'on') ? 'checked' : ''; 5023 echo '<label class="toggle-switch">'; 5024 echo sprintf( 5025 '<input type="checkbox" id="enable_name_field" name="enable_name_field" value="on" %s />', 5026 esc_attr($checked) 5027 ); 5028 echo '<span class="slider"></span>'; 5029 echo '</label>'; 5030 echo '<p class="description">' . esc_html__('Enable this to also require users to enter their name along with their email before chatting.', 'mxchat') . '</p>'; 5031 } 5032 //Name field placeholder callback 5033 public function name_field_placeholder_callback() { 5034 $all_options = get_option('mxchat_options', []); 5035 $placeholder = isset($all_options['name_field_placeholder']) 5036 ? $all_options['name_field_placeholder'] 5037 : esc_html__('Enter your name', 'mxchat'); 5038 5039 echo '<input type="text" id="name_field_placeholder" name="name_field_placeholder" value="' . esc_attr($placeholder) . '" style="width: 300px;" />'; 5040 echo '<p class="description">'; 5041 echo esc_html__('Placeholder text for the name field.', 'mxchat'); 4983 5042 echo '</p>'; 4984 5043 } … … 5907 5966 $fresh_options = get_option('mxchat_options'); 5908 5967 $status = isset($fresh_options['live_agent_status']) ? $fresh_options['live_agent_status'] : 'off'; 5909 5968 5910 5969 echo '<label class="toggle-switch">'; 5911 5970 echo sprintf( … … 5976 6035 5977 6036 public function mxchat_live_agent_user_ids_callback() { 5978 $user_ids = isset($this->options['live_agent_user_ids']) 5979 ? esc_textarea($this->options['live_agent_user_ids']) 6037 $user_ids = isset($this->options['live_agent_user_ids']) 6038 ? esc_textarea($this->options['live_agent_user_ids']) 5980 6039 : ''; 5981 6040 5982 6041 printf( 5983 6042 '<textarea id="live_agent_user_ids" name="live_agent_user_ids" rows="4" class="large-text">%s</textarea>', … … 6022 6081 public function mxchat_enqueue_admin_assets() { 6023 6082 // Get plugin version (define this in your main plugin file) 6024 $version = defined('MXCHAT_VERSION') ? MXCHAT_VERSION : '2.3. 7';6025 6083 $version = defined('MXCHAT_VERSION') ? MXCHAT_VERSION : '2.3.8'; 6084 6026 6085 // Use file modification time for development (remove in production) 6027 6086 if (defined('WP_DEBUG') && WP_DEBUG) { 6028 6087 $version = filemtime(plugin_dir_path(__FILE__) . '../mxchat-basic.php'); 6029 6088 } 6030 6089 6031 6090 $current_page = isset($_GET['page']) ? $_GET['page'] : ''; 6032 6091 $plugin_url = plugin_dir_url(__FILE__) . '../'; 6033 6092 6034 6093 // Only load on MxChat pages 6035 6094 if (strpos($current_page, 'mxchat') === false) { 6036 6095 return; 6037 6096 } 6038 6097 6039 6098 // Always load these on all MxChat pages 6040 6099 $this->enqueue_core_admin_assets($plugin_url, $version); … … 6046 6105 wp_enqueue_style('mxchat-admin-css', $plugin_url . 'css/admin-style.css', array(), $version); 6047 6106 wp_enqueue_style('mxchat-knowledge-css', $plugin_url . 'css/knowledge-style.css', array(), $version); 6048 6107 6049 6108 // Core admin scripts 6050 6109 wp_enqueue_script('mxchat-admin-js', $plugin_url . 'js/mxchat-admin.js', array('jquery'), $version, true); … … 6059 6118 wp_enqueue_script('mxchat-knowledge-processing', $plugin_url . 'js/knowledge-processing.js', array('jquery'), $version, true); 6060 6119 break; 6061 6120 6062 6121 case 'mxchat-transcripts': 6063 6122 wp_enqueue_style('mxchat-chat-transcripts-css', $plugin_url . 'css/chat-transcripts.css', array(), $version); 6064 6123 wp_enqueue_script('mxchat-transcripts-js', $plugin_url . 'js/mxchat_transcripts.js', array('jquery'), $version, true); 6065 6124 break; 6066 6125 6067 6126 case 'mxchat-actions': 6068 6127 wp_enqueue_style('mxchat-intent-css', $plugin_url . 'css/intent-style.css', array(), $version); 6069 6128 break; 6070 6129 6071 6130 case 'mxchat-activation': 6072 6131 wp_enqueue_script('mxchat-activation-js', $plugin_url . 'js/activation-script.js', array('jquery'), $version, true); … … 6107 6166 'ajaxurl' => admin_url('admin-ajax.php') // For jQuery fallback 6108 6167 ); 6109 6168 6110 6169 // Localize main admin script with base data 6111 6170 wp_localize_script('mxchat-admin-js', 'mxchatAdmin', $base_data); 6112 6171 6113 6172 // Page-specific localizations 6114 6173 $this->localize_page_specific_scripts($current_page); … … 6122 6181 'nonce' => wp_create_nonce('mxchat_status_nonce') 6123 6182 )); 6124 6183 6125 6184 // Content selector localization 6126 6185 wp_localize_script('mxchat-content-selector-js', 'mxchatSelector', array( … … 6135 6194 ) 6136 6195 )); 6137 6196 6138 6197 // NEW: Knowledge processing script localization using mxchatAdmin 6139 6198 wp_localize_script('mxchat-knowledge-processing', 'mxchatAdmin', array( … … 6146 6205 )); 6147 6206 break; 6148 6207 6149 6208 case 'mxchat-activation': 6150 6209 wp_localize_script('mxchat-activation-js', 'mxchatAdmin', array( … … 6153 6212 )); 6154 6213 break; 6155 6214 6156 6215 case 'mxchat-settings': 6157 6216 default: … … 6194 6253 break; 6195 6254 } 6196 6255 6197 6256 // Additional localization that was in the original code 6198 6257 wp_localize_script('mxchat-admin-js', 'mxchatPromptsAdmin', array( … … 6221 6280 $new_input['claude_api_key'] = sanitize_text_field($input['claude_api_key']); 6222 6281 } 6223 6282 6224 6283 if (isset($input['enable_streaming_toggle'])) { 6225 6284 $new_input['enable_streaming_toggle'] = ($input['enable_streaming_toggle'] === 'on') ? 'on' : 'off'; … … 6228 6287 $new_input['enable_streaming_toggle'] = 'off'; 6229 6288 } 6230 6289 6231 6290 6232 6291 if (isset($input['deepseek_api_key'])) { … … 6271 6330 $new_input['append_to_body'] = $input['append_to_body'] === 'on' ? 'on' : 'off'; 6272 6331 } 6273 6332 6274 6333 if (isset($input['contextual_awareness_toggle'])) { 6275 6334 $new_input['contextual_awareness_toggle'] = $input['contextual_awareness_toggle'] === 'on' ? 'on' : 'off'; … … 6295 6354 $new_input['email_blocker_button_text'] = sanitize_text_field($input['email_blocker_button_text']); 6296 6355 } 6297 6356 // NEW: Sanitize name field toggle 6357 if (isset($input['enable_name_field'])) { 6358 $new_input['enable_name_field'] = ($input['enable_name_field'] === 'on') ? 'on' : 'off'; 6359 } else { 6360 $new_input['enable_name_field'] = 'off'; 6361 } 6362 // NEW: Sanitize name field placeholder 6363 if (isset($input['name_field_placeholder'])) { 6364 $new_input['name_field_placeholder'] = sanitize_text_field($input['name_field_placeholder']); 6365 } 6298 6366 if (isset($input['intro_message'])) { 6299 6367 $new_input['intro_message'] = wp_kses_post($input['intro_message']); // Use wp_kses_post instead … … 6463 6531 $new_input['top_bar_bg_color'] = sanitize_hex_color($input['top_bar_bg_color']); 6464 6532 } 6465 6533 6466 6534 if (isset($input['quick_questions_toggle_color'])) { 6467 6535 $new_input['quick_questions_toggle_color'] = sanitize_hex_color($input['quick_questions_toggle_color']); … … 6611 6679 $new_input['live_agent_bot_token'] = sanitize_text_field($input['live_agent_bot_token']); 6612 6680 } 6613 6681 6614 6682 if (isset($input['live_agent_user_ids'])) { 6615 6683 $new_input['live_agent_user_ids'] = sanitize_textarea_field($input['live_agent_user_ids']); … … 6715 6783 delete_option('mxchat_pinecone_processed_cache'); 6716 6784 delete_option('mxchat_processed_content_cache'); 6717 6785 6718 6786 // CLEAR THE PINECONE RECORDS CACHE (NEW LINE) 6719 6787 delete_transient('mxchat_pinecone_recent_1k_cache'); 6720 6788 6721 6789 } else { 6722 6790 //error_log('[MXCHAT-DELETE] Pinecone not enabled - deleting from WordPress database'); … … 6945 7013 exit; 6946 7014 } 6947 6948 7015 7016 6949 7017 /** 6950 7018 * Checks user permissions for managing options … … 6955 7023 } 6956 7024 check_admin_referer('mxchat_add_intent_nonce'); 6957 7025 6958 7026 global $wpdb; 6959 7027 $table_name = $wpdb->prefix . 'mxchat_intents'; 6960 7028 6961 7029 // Sanitize and get form data 6962 7030 $intent_label = isset($_POST['intent_label']) ? sanitize_text_field($_POST['intent_label']) : ''; 6963 7031 $phrases_input = isset($_POST['phrases']) ? sanitize_textarea_field($_POST['phrases']) : ''; 6964 7032 $callback_function = isset($_POST['callback_function']) ? sanitize_text_field($_POST['callback_function']) : ''; 6965 7033 6966 7034 // Get similarity threshold from form (convert percentage to decimal) 6967 7035 $similarity_threshold = isset($_POST['similarity_threshold']) ? floatval($_POST['similarity_threshold']) / 100 : 0.85; 6968 7036 6969 7037 // Validate required fields 6970 7038 if (empty($intent_label) || empty($callback_function) || empty($phrases_input)) { … … 6972 7040 return; 6973 7041 } 6974 7042 6975 7043 // Validate callback function 6976 7044 $available_callbacks = $this->mxchat_get_available_callbacks(); … … 6979 7047 return; 6980 7048 } 6981 7049 6982 7050 // Check Pro requirements 6983 7051 $is_pro_only = $available_callbacks[$callback_function]['pro_only']; … … 6986 7054 return; 6987 7055 } 6988 7056 6989 7057 // Process phrases 6990 7058 $phrases_array = array_map('sanitize_text_field', array_filter(array_map('trim', explode(',', $phrases_input)))); … … 6993 7061 return; 6994 7062 } 6995 7063 6996 7064 // Generate embeddings with improved error handling 6997 7065 $vectors = []; … … 7005 7073 } 7006 7074 } 7007 7075 7008 7076 // Check for embedding failures 7009 7077 if (!empty($failed_phrases)) { … … 7016 7084 return; 7017 7085 } 7018 7086 7019 7087 if (empty($vectors)) { 7020 7088 $this->handle_embedding_error(__('No valid embeddings generated. Please check your phrases.', 'mxchat')); 7021 7089 return; 7022 7090 } 7023 7091 7024 7092 // Create combined vector and insert into database 7025 7093 $combined_vector = $this->mxchat_average_vectors($vectors); 7026 7094 $serialized_vector = maybe_serialize($combined_vector); 7027 7095 7028 7096 $result = $wpdb->insert($table_name, [ 7029 7097 'intent_label' => $intent_label, … … 7033 7101 'similarity_threshold' => $similarity_threshold, // Now uses the actual form value 7034 7102 ]); 7035 7103 7036 7104 if ($result === false) { 7037 7105 $this->handle_embedding_error(__('Database error: ', 'mxchat') . $wpdb->last_error); 7038 7106 return; 7039 7107 } 7040 7108 7041 7109 // Set success message and redirect 7042 7110 set_transient('mxchat_admin_notice_success', __('New intent added successfully!', 'mxchat'), 60); … … 7044 7112 exit; 7045 7113 } 7046 7114 7047 7115 /** 7048 7116 * Averages multiple vectors into a single vector … … 7066 7134 return $sum_vector; 7067 7135 } 7068 7069 7070 7071 7136 7137 7138 7139 7072 7140 /** 7073 7141 * Generates embeddings from input text for MXChat -
mxchat-basic/trunk/includes/class-mxchat-integrator.php
r3341601 r3343848 372 372 //error_log("[DEBUG] mxchat_save_chat_message -> Checking wp_options for email_option_key: {$email_option_key}, found: {$saved_email}"); 373 373 374 // If found, update DB user_email 375 if ($saved_email) { 376 $update_res = $wpdb->update( 377 $table_name, 378 ['user_email' => $saved_email], 379 ['session_id' => $session_id], 380 ['%s'], 381 ['%s'] 382 ); 383 //error_log("[DEBUG] mxchat_save_chat_message -> Attempted DB user_email update for session_id {$session_id}. update_res: {$update_res}"); 374 // NEW: Check for a saved name in wp_options 375 $name_option_key = "mxchat_name_{$session_id}"; 376 $saved_name = get_option($name_option_key); 377 //error_log("[DEBUG] mxchat_save_chat_message -> Checking wp_options for name_option_key: {$name_option_key}, found: {$saved_name}"); 378 379 // If found, update DB user_email and user_name 380 if ($saved_email || $saved_name) { 381 $update_data = []; 382 if ($saved_email) { 383 $update_data['user_email'] = $saved_email; 384 } 385 if ($saved_name) { 386 $update_data['user_name'] = $saved_name; 387 } 388 389 if (!empty($update_data)) { 390 $update_res = $wpdb->update( 391 $table_name, 392 $update_data, 393 ['session_id' => $session_id], 394 array_fill(0, count($update_data), '%s'), 395 ['%s'] 396 ); 397 //error_log("[DEBUG] mxchat_save_chat_message -> Attempted DB user_email/user_name update for session_id {$session_id}. update_res: {$update_res}"); 398 } 384 399 } 385 400 … … 402 417 'user_identifier'=> $user_identifier, 403 418 'user_email' => $saved_email ?: $user_email, 419 'user_name' => $saved_name ?: '', // NEW: Add name to insert data 404 420 'session_id' => $session_id, 405 421 'role' => $role, … … 483 499 return $message_id; 484 500 } 485 486 501 private function send_new_chat_notification($session_id, $user_info = array()) { 487 502 $options = get_option('mxchat_transcripts_options'); … … 530 545 public function mxchat_handle_save_email_and_response() { 531 546 //error_log('[DEBUG] ---------- mxchat_handle_save_email_and_response START ----------'); 547 error_log('DEBUG: POST data: ' . print_r($_POST, true)); 532 548 533 549 // Validate nonce … … 540 556 $session_id = isset($_POST['session_id']) ? sanitize_text_field($_POST['session_id']) : ''; 541 557 $email = isset($_POST['email']) ? sanitize_email($_POST['email']) : ''; 542 543 //error_log("[DEBUG] handle_save_email_and_response -> session_id: {$session_id}, email: {$email}"); 558 $name = isset($_POST['name']) ? sanitize_text_field($_POST['name']) : ''; // NEW 559 560 //error_log("[DEBUG] handle_save_email_and_response -> session_id: {$session_id}, email: {$email}, name: {$name}"); 544 561 545 562 if (empty($session_id) || empty($email)) { … … 549 566 } 550 567 551 // 1) Always store in wp_options 552 $option_key = "mxchat_email_{$session_id}"; 553 update_option($option_key, $email); 554 //error_log("[DEBUG] handle_save_email_and_response -> updated option: {$option_key} => {$email}"); 568 // NEW: Validate name if provided (check if name field is enabled and name is required) 569 $options = get_option('mxchat_options', []); 570 $name_field_enabled = isset($options['enable_name_field']) && 571 ($options['enable_name_field'] === '1' || $options['enable_name_field'] === 'on'); 572 573 if ($name_field_enabled && (empty($name) || strlen(trim($name)) < 2 || strlen(trim($name)) > 100)) { 574 //error_log("[ERROR] Invalid name: {$name} (enabled: {$name_field_enabled})"); 575 wp_send_json_error(['message' => esc_html__('Name must be between 2 and 100 characters.', 'mxchat')]); 576 wp_die(); 577 } 578 579 // 1) Always store email in wp_options 580 $email_option_key = "mxchat_email_{$session_id}"; 581 update_option($email_option_key, $email); 582 //error_log("[DEBUG] handle_save_email_and_response -> updated option: {$email_option_key} => {$email}"); 583 584 // NEW: Store name in wp_options if provided 585 if (!empty($name)) { 586 $name_option_key = "mxchat_name_{$session_id}"; 587 update_option($name_option_key, $name); 588 //error_log("[DEBUG] handle_save_email_and_response -> updated option: {$name_option_key} => {$name}"); 589 } 555 590 556 591 // 2) (Optional) Also store in DB if a row already exists … … 565 600 566 601 if ($session_count) { 567 // Update user_email if row(s) exist 568 $update_sql = $wpdb->prepare( 569 "UPDATE {$table_name} SET user_email = %s WHERE session_id = %s", 570 $email, 571 $session_id 572 ); 602 // NEW: Update both user_email and user_name if row(s) exist 603 if (!empty($name)) { 604 $update_sql = $wpdb->prepare( 605 "UPDATE {$table_name} SET user_email = %s, user_name = %s WHERE session_id = %s", 606 $email, 607 $name, 608 $session_id 609 ); 610 } else { 611 $update_sql = $wpdb->prepare( 612 "UPDATE {$table_name} SET user_email = %s WHERE session_id = %s", 613 $email, 614 $session_id 615 ); 616 } 573 617 $wpdb->query($update_sql); 574 618 //error_log("[DEBUG] handle_save_email_and_response -> DB updated: {$update_sql}"); 575 619 } else { 576 //error_log("[INFO] handle_save_email_and_response -> No DB entry for {$session_id}, so email is only in wp_options.");577 } 578 579 // Provide success response 620 //error_log("[INFO] handle_save_email_and_response -> No DB entry for {$session_id}, so email/name is only in wp_options."); 621 } 622 623 // Provide success response (same as original) 580 624 $bot_message = __('Thanks for providing your email! You can continue chatting now.', 'mxchat'); 581 625 //error_log("[DEBUG] handle_save_email_and_response -> success, returning bot_message: {$bot_message}"); … … 602 646 $current_user = wp_get_current_user(); 603 647 //error_log("[DEBUG] User is logged in as {$current_user->user_email}"); 604 wp_send_json_success(['logged_in' => true, 'email' => $current_user->user_email]); 605 } 606 607 $option_key = "mxchat_email_{$session_id}"; 608 $stored_email = get_option($option_key, ''); 609 610 //error_log("[DEBUG] mxchat_check_email_provided -> Checking option: {$option_key}, found: {$stored_email}"); 611 612 if (!empty($stored_email)) { 613 //error_log("[DEBUG] mxchat_check_email_provided -> Email found, returning success"); 614 wp_send_json_success(['email' => $stored_email]); 648 649 // NEW: Get user's display name for logged in users 650 $user_name = !empty($current_user->display_name) ? $current_user->display_name : 651 (!empty($current_user->first_name) ? $current_user->first_name : ''); 652 653 $response_data = ['logged_in' => true, 'email' => $current_user->user_email]; 654 if (!empty($user_name)) { 655 $response_data['name'] = $user_name; 656 } 657 658 wp_send_json_success($response_data); 659 } 660 661 // NEW: Check if name field is required 662 $options = get_option('mxchat_options', []); 663 $name_field_enabled = isset($options['enable_name_field']) && 664 ($options['enable_name_field'] === '1' || $options['enable_name_field'] === 'on'); 665 666 $email_option_key = "mxchat_email_{$session_id}"; 667 $stored_email = get_option($email_option_key, ''); 668 669 // NEW: Check for stored name 670 $name_option_key = "mxchat_name_{$session_id}"; 671 $stored_name = get_option($name_option_key, ''); 672 673 //error_log("[DEBUG] mxchat_check_email_provided -> Checking email option: {$email_option_key}, found: {$stored_email}"); 674 //error_log("[DEBUG] mxchat_check_email_provided -> Checking name option: {$name_option_key}, found: {$stored_name}, required: " . ($name_field_enabled ? 'yes' : 'no')); 675 676 // NEW: Check if we have email and name (if name is required) 677 $has_required_info = !empty($stored_email); 678 679 if ($name_field_enabled) { 680 $has_required_info = $has_required_info && !empty($stored_name); 681 } 682 683 if ($has_required_info) { 684 //error_log("[DEBUG] mxchat_check_email_provided -> Required info found, returning success"); 685 686 $response_data = ['email' => $stored_email]; 687 if (!empty($stored_name)) { 688 $response_data['name'] = $stored_name; 689 } 690 691 wp_send_json_success($response_data); 615 692 } else { 616 //error_log("[DEBUG] mxchat_check_email_provided -> No email found, returning error");693 //error_log("[DEBUG] mxchat_check_email_provided -> Required info missing, returning error"); 617 694 wp_send_json_error(['message' => esc_html__('No email found', 'mxchat')]); 618 695 } … … 2558 2635 if (empty($channel_id)) { 2559 2636 // Create new channel with session ID as name 2560 $channel_name = 'chat-' . strtolower(preg_replace('/[^a-zA-Z0-9]/', '', $session_id));2637 $channel_name = $this->generate_channel_name($session_id); 2561 2638 2562 2639 //error_log("Attempting to create channel: $channel_name"); … … 2695 2772 ]); 2696 2773 wp_die(); 2774 } 2775 private function generate_channel_name($session_id) { 2776 $email = null; 2777 2778 // 1. First priority: Check if user is logged in and get their email 2779 if (is_user_logged_in()) { 2780 $current_user = wp_get_current_user(); 2781 if (!empty($current_user->user_email)) { 2782 $email = $current_user->user_email; 2783 error_log("[DEBUG] Using logged-in user email for channel: {$email}"); 2784 } 2785 } 2786 2787 // 2. Second priority: Check for saved email from "require email to chat" option 2788 if (empty($email)) { 2789 $email_option_key = "mxchat_email_{$session_id}"; 2790 $saved_email = get_option($email_option_key); 2791 if (!empty($saved_email)) { 2792 $email = $saved_email; 2793 error_log("[DEBUG] Using saved email from session for channel: {$email}"); 2794 } 2795 } 2796 2797 // 3. Third priority: Check existing chat transcript for email 2798 if (empty($email)) { 2799 global $wpdb; 2800 $table_name = $wpdb->prefix . 'mxchat_chat_transcripts'; 2801 $existing_email = $wpdb->get_var($wpdb->prepare( 2802 "SELECT user_email FROM $table_name WHERE session_id = %s AND user_email IS NOT NULL AND user_email != '' LIMIT 1", 2803 $session_id 2804 )); 2805 if (!empty($existing_email)) { 2806 $email = $existing_email; 2807 error_log("[DEBUG] Using email from chat transcript for channel: {$email}"); 2808 } 2809 } 2810 2811 // 4. Generate channel name based on what we found 2812 if (!empty($email)) { 2813 // Convert email to valid Slack channel name 2814 // Slack channel names must be lowercase, no spaces, and only certain special chars 2815 $channel_name = 'chat-' . strtolower(str_replace(['@', '.', '+', '_'], ['-at-', '-', '-plus-', '-'], $email)); 2816 // Remove any remaining invalid characters 2817 $channel_name = preg_replace('/[^a-z0-9\-]/', '', $channel_name); 2818 // Ensure it doesn't end with a hyphen 2819 $channel_name = rtrim($channel_name, '-'); 2820 // Slack channel names have a 21 character limit, so truncate if needed 2821 if (strlen($channel_name) > 21) { 2822 $channel_name = substr($channel_name, 0, 21); 2823 $channel_name = rtrim($channel_name, '-'); // Remove trailing hyphen if truncation created one 2824 } 2825 } else { 2826 // Fallback to session ID if no email found 2827 $channel_name = 'chat-' . strtolower(preg_replace('/[^a-zA-Z0-9]/', '', $session_id)); 2828 error_log("[DEBUG] No email found, using session ID for channel: {$channel_name}"); 2829 } 2830 2831 error_log("[DEBUG] Generated channel name: {$channel_name}"); 2832 return $channel_name; 2697 2833 } 2698 2834 public function mxchat_send_user_message_to_agent($message, $user_id, $session_id) { … … 5524 5660 public function mxchat_enqueue_scripts_styles() { 5525 5661 // Define version numbers for the styles and scripts 5526 $chat_style_version = '2.3. 7';5527 $chat_script_version = '2.3. 7';5662 $chat_style_version = '2.3.8'; 5663 $chat_script_version = '2.3.8'; 5528 5664 // Enqueue the script 5529 5665 wp_enqueue_script( … … 5575 5711 'toolbar_icon_color' => $this->options['toolbar_icon_color'] ?? '#212121', 5576 5712 'use_pinecone' => $prompts_options['mxchat_use_pinecone'] ?? '0', 5713 'email_collection_enabled' => $enable_email_block, 5714 'initial_email_state' => $email_state ?? null, 5715 'skip_email_check' => true, 5577 5716 'pinecone_enabled' => isset($prompts_options['mxchat_use_pinecone']) && $prompts_options['mxchat_use_pinecone'] === '1' 5578 5717 ); -
mxchat-basic/trunk/includes/class-mxchat-public.php
r3335923 r3343848 96 96 } 97 97 98 public function render_chatbot_shortcode($atts) { 99 $attributes = shortcode_atts(array( 100 'floating' => 'yes', 101 'has_consent' => 'yes' // Add default 102 ), $atts); 103 104 $is_floating = $attributes['floating'] === 'yes'; 105 106 // Check for Complianz consent if the toggle is enabled 107 $initial_visibility = 'hidden'; 108 $additional_class = ''; 109 110 if (isset($this->options['complianz_toggle']) && $this->options['complianz_toggle'] === 'on') { 111 // If Complianz is enabled, add no-consent class by default 112 $additional_class = ' no-consent'; 113 } 114 $visibility_class = $initial_visibility . $additional_class; 115 116 $theme_options = get_option('mxchat_theme_options', array()); 117 $custom_send_image = isset($theme_options['custom_send_button_image']) ? esc_url($theme_options['custom_send_button_image']) : ''; 118 $send_width = isset($theme_options['send_button_width']) ? intval($theme_options['send_button_width']) : 24; 119 $send_height = isset($theme_options['send_button_height']) ? intval($theme_options['send_button_height']) : 24; 120 $send_rotation = isset($theme_options['send_button_rotation']) ? intval($theme_options['send_button_rotation']) : 0; 121 122 // Use null coalescing operator (??) for fallbacks instead of having duplicate defaults 123 $bg_color = $this->options['chatbot_background_color'] ?? '#fff'; 124 $user_message_bg_color = $this->options['user_message_bg_color'] ?? '#fff'; 125 $user_message_font_color = $this->options['user_message_font_color'] ?? '#212121'; 126 $bot_message_bg_color = $this->options['bot_message_bg_color'] ?? '#212121'; 127 $bot_message_font_color = $this->options['bot_message_font_color'] ?? '#fff'; 128 $top_bar_bg_color = $this->options['top_bar_bg_color'] ?? '#212121'; 129 $send_button_font_color = $this->options['send_button_font_color'] ?? '#212121'; 130 $intro_message = $this->options['intro_message'] ?? esc_html__('Hello! How can I assist you today?', 'mxchat'); 131 $top_bar_title = $this->options['top_bar_title'] ?? esc_html__('MxChat: Basic', 'mxchat'); 132 $chatbot_background_color = $this->options['chatbot_background_color'] ?? '#212121'; 133 $icon_color = $this->options['icon_color'] ?? '#fff'; 134 $chat_input_font_color = $this->options['chat_input_font_color'] ?? '#212121'; 135 $close_button_color = $this->options['close_button_color'] ?? '#fff'; 136 $chatbot_bg_color = $this->options['chatbot_bg_color'] ?? '#fff'; 137 $pre_chat_message = isset($this->options['pre_chat_message']) ? sanitize_text_field(trim($this->options['pre_chat_message'])) : ''; 138 $user_id = sanitize_key($this->mxchat_get_user_identifier()); 139 $transient_key = 'mxchat_pre_chat_message_dismissed_' . $user_id; 140 $input_copy = isset($this->options['input_copy']) ? esc_attr($this->options['input_copy']) : esc_attr__('How can I assist?', 'mxchat'); 141 $rate_limit_message = isset($this->options['rate_limit_message']) ? esc_attr($this->options['rate_limit_message']) : esc_attr__('Rate limit exceeded. Please try again later.', 'mxchat'); 142 $mode_indicator_bg_color = $this->options['mode_indicator_bg_color'] ?? '#212121'; 143 $mode_indicator_font_color = $this->options['mode_indicator_font_color'] ?? '#fff'; 144 $quick_questions_toggle_color = $this->options['quick_questions_toggle_color'] ?? '#212121'; 145 146 $privacy_toggle = isset($this->options['privacy_toggle']) && $this->options['privacy_toggle'] === 'on'; 147 $privacy_text = isset($this->options['privacy_text']) ? wp_kses_post($this->options['privacy_text']) : wp_kses_post(__('By chatting, you agree to our <a href="https://example.com/privacy-policy" target="_blank">privacy policy</a>.', 'mxchat')); 148 149 $popular_question_1 = isset($this->options['popular_question_1']) ? esc_html($this->options['popular_question_1']) : ''; 150 $popular_question_2 = isset($this->options['popular_question_2']) ? esc_html($this->options['popular_question_2']) : ''; 151 $popular_question_3 = isset($this->options['popular_question_3']) ? esc_html($this->options['popular_question_3']) : ''; 152 $additional_questions = isset($this->options['additional_popular_questions']) ? $this->options['additional_popular_questions'] : []; 153 $custom_icon = isset($this->options['custom_icon']) ? esc_url($this->options['custom_icon']) : ''; 154 $title_icon = isset($this->options['title_icon']) ? esc_url($this->options['title_icon']) : ''; 155 $ai_agent_text = isset($this->options['ai_agent_text']) ? esc_html($this->options['ai_agent_text']) : esc_html__('AI Agent', 'mxchat'); 156 157 $live_agent_message_bg_color = $this->options['live_agent_message_bg_color'] ?? '#212121'; 158 $live_agent_message_font_color = $this->options['live_agent_message_font_color'] ?? '#fff'; 159 $enable_email_block = isset($this->options['enable_email_block']) && 160 ($this->options['enable_email_block'] === '1' || $this->options['enable_email_block'] === 'on'); 161 162 ob_start(); 98 public function render_chatbot_shortcode($atts) { 99 $attributes = shortcode_atts(array( 100 'floating' => 'yes', 101 'has_consent' => 'yes' 102 ), $atts); 103 104 $is_floating = $attributes['floating'] === 'yes'; 105 106 // Check for Complianz consent if the toggle is enabled 107 $initial_visibility = 'hidden'; 108 $additional_class = ''; 109 110 if (isset($this->options['complianz_toggle']) && $this->options['complianz_toggle'] === 'on') { 111 $additional_class = ' no-consent'; 112 } 113 $visibility_class = $initial_visibility . $additional_class; 114 115 $theme_options = get_option('mxchat_theme_options', array()); 116 $custom_send_image = isset($theme_options['custom_send_button_image']) ? esc_url($theme_options['custom_send_button_image']) : ''; 117 $send_width = isset($theme_options['send_button_width']) ? intval($theme_options['send_button_width']) : 24; 118 $send_height = isset($theme_options['send_button_height']) ? intval($theme_options['send_button_height']) : 24; 119 $send_rotation = isset($theme_options['send_button_rotation']) ? intval($theme_options['send_button_rotation']) : 0; 120 121 // Existing variables... 122 $bg_color = $this->options['chatbot_background_color'] ?? '#fff'; 123 $user_message_bg_color = $this->options['user_message_bg_color'] ?? '#fff'; 124 $user_message_font_color = $this->options['user_message_font_color'] ?? '#212121'; 125 $bot_message_bg_color = $this->options['bot_message_bg_color'] ?? '#212121'; 126 $bot_message_font_color = $this->options['bot_message_font_color'] ?? '#fff'; 127 $top_bar_bg_color = $this->options['top_bar_bg_color'] ?? '#212121'; 128 $send_button_font_color = $this->options['send_button_font_color'] ?? '#212121'; 129 $intro_message = $this->options['intro_message'] ?? esc_html__('Hello! How can I assist you today?', 'mxchat'); 130 $top_bar_title = $this->options['top_bar_title'] ?? esc_html__('MxChat: Basic', 'mxchat'); 131 $chatbot_background_color = $this->options['chatbot_background_color'] ?? '#212121'; 132 $icon_color = $this->options['icon_color'] ?? '#fff'; 133 $chat_input_font_color = $this->options['chat_input_font_color'] ?? '#212121'; 134 $close_button_color = $this->options['close_button_color'] ?? '#fff'; 135 $chatbot_bg_color = $this->options['chatbot_bg_color'] ?? '#fff'; 136 $pre_chat_message = isset($this->options['pre_chat_message']) ? sanitize_text_field(trim($this->options['pre_chat_message'])) : ''; 137 $user_id = sanitize_key($this->mxchat_get_user_identifier()); 138 $email_state = $this->determine_email_collection_state(); 139 $show_email_form = $email_state['show_email_form']; 140 $user_email = $email_state['user_email'] ?? ''; 141 $user_name = $email_state['user_name'] ?? ''; 142 $transient_key = 'mxchat_pre_chat_message_dismissed_' . $user_id; 143 $input_copy = isset($this->options['input_copy']) ? esc_attr($this->options['input_copy']) : esc_attr__('How can I assist?', 'mxchat'); 144 $rate_limit_message = isset($this->options['rate_limit_message']) ? esc_attr($this->options['rate_limit_message']) : esc_attr__('Rate limit exceeded. Please try again later.', 'mxchat'); 145 $mode_indicator_bg_color = $this->options['mode_indicator_bg_color'] ?? '#212121'; 146 $mode_indicator_font_color = $this->options['mode_indicator_font_color'] ?? '#fff'; 147 $quick_questions_toggle_color = $this->options['quick_questions_toggle_color'] ?? '#212121'; 148 149 $privacy_toggle = isset($this->options['privacy_toggle']) && $this->options['privacy_toggle'] === 'on'; 150 $privacy_text = isset($this->options['privacy_text']) ? wp_kses_post($this->options['privacy_text']) : wp_kses_post(__('By chatting, you agree to our <a href="https://example.com/privacy-policy" target="_blank">privacy policy</a>.', 'mxchat')); 151 152 $popular_question_1 = isset($this->options['popular_question_1']) ? esc_html($this->options['popular_question_1']) : ''; 153 $popular_question_2 = isset($this->options['popular_question_2']) ? esc_html($this->options['popular_question_2']) : ''; 154 $popular_question_3 = isset($this->options['popular_question_3']) ? esc_html($this->options['popular_question_3']) : ''; 155 $additional_questions = isset($this->options['additional_popular_questions']) ? $this->options['additional_popular_questions'] : []; 156 $custom_icon = isset($this->options['custom_icon']) ? esc_url($this->options['custom_icon']) : ''; 157 $title_icon = isset($this->options['title_icon']) ? esc_url($this->options['title_icon']) : ''; 158 $ai_agent_text = isset($this->options['ai_agent_text']) ? esc_html($this->options['ai_agent_text']) : esc_html__('AI Agent', 'mxchat'); 159 160 $live_agent_message_bg_color = $this->options['live_agent_message_bg_color'] ?? '#212121'; 161 $live_agent_message_font_color = $this->options['live_agent_message_font_color'] ?? '#fff'; 162 $enable_email_block = isset($this->options['enable_email_block']) && 163 ($this->options['enable_email_block'] === '1' || $this->options['enable_email_block'] === 'on'); 164 165 // NEW: Add name field variables 166 $enable_name_field = isset($this->options['enable_name_field']) && 167 ($this->options['enable_name_field'] === '1' || $this->options['enable_name_field'] === 'on'); 168 $name_field_placeholder = isset($this->options['name_field_placeholder']) ? 169 esc_attr($this->options['name_field_placeholder']) : 170 esc_attr__('Enter your name', 'mxchat'); 171 172 ob_start(); 163 173 164 174 // Check if floating attribute is set to 'yes' and wrap accordingly … … 190 200 echo ' <div id="mxchat-chatbot" style="background-color: ' . esc_attr($chatbot_bg_color) . ';">'; 191 201 192 if ($enable_email_block) { 193 echo '<div id="email-blocker" class="email-blocker">'; 194 echo ' <div class="email-blocker-header">'; 195 196 // Safely echo the user-provided HTML 197 // (We rely on wp_kses_post() from the sanitize step to ensure it's safe) 198 $header_html = isset($this->options['email_blocker_header_content']) 199 ? $this->options['email_blocker_header_content'] 200 : ''; 201 echo wp_kses_post($header_html); 202 203 echo ' </div>'; 204 echo ' <form id="email-collection-form">'; 205 echo ' <label for="user-email" class="sr-only">' . esc_html__('Email Address', 'mxchat') . '</label>'; 206 echo ' <input type="email" id="user-email" name="user_email" required placeholder="' . esc_attr__('Enter your email address', 'mxchat') . '" />'; 207 echo '<button type="submit" id="email-submit-button">'; 208 // If not set, fallback to default. Typically, $this->options includes defaults merged in. 209 $button_text = isset($this->options['email_blocker_button_text']) 210 ? $this->options['email_blocker_button_text'] 211 : esc_html__('Start Chat', 'mxchat'); // fallback just in case 212 echo esc_html($button_text); 213 echo '</button>'; 214 echo ' </form>'; 215 echo '</div>'; 216 } 217 218 echo ' <div id="chat-container" style="' . ($enable_email_block ? 'display: none;' : '') . '">'; 202 if ($enable_email_block) { 203 echo '<div id="email-blocker" class="email-blocker" style="' . ($show_email_form ? '' : 'display: none;') . '">'; 204 echo ' <div class="email-blocker-header">'; 205 206 $header_html = isset($this->options['email_blocker_header_content']) 207 ? $this->options['email_blocker_header_content'] 208 : ''; 209 echo wp_kses_post($header_html); 210 211 echo ' </div>'; 212 echo ' <form id="email-collection-form">'; 213 214 // NEW: Add name field if enabled 215 if ($enable_name_field) { 216 echo ' <label for="user-name" class="sr-only mxchat-name-label">' . esc_html__('Name', 'mxchat') . '</label>'; 217 echo ' <input type="text" id="user-name" name="user_name" class="mxchat-name-input" required placeholder="' . $name_field_placeholder . '" />'; 218 } 219 220 echo ' <label for="user-email" class="sr-only">' . esc_html__('Email Address', 'mxchat') . '</label>'; 221 echo ' <input type="email" id="user-email" name="user_email" required placeholder="' . esc_attr__('Enter your email address', 'mxchat') . '" />'; 222 echo '<button type="submit" id="email-submit-button">'; 223 $button_text = isset($this->options['email_blocker_button_text']) 224 ? $this->options['email_blocker_button_text'] 225 : esc_html__('Start Chat', 'mxchat'); 226 echo esc_html($button_text); 227 echo '</button>'; 228 echo ' </form>'; 229 echo '</div>'; 230 } 231 232 echo ' <div id="chat-container" style="' . ($enable_email_block && $show_email_form ? 'display: none;' : '') . '">'; 219 233 echo ' <div id="chat-box">'; 220 234 echo ' <div class="bot-message" style="background: ' . esc_attr($bot_message_bg_color) . ';">'; … … 383 397 return ob_get_clean(); 384 398 } 399 400 401 402 private function determine_email_collection_state() { 403 // Get session ID 404 $session_id = 'mxchat_chat_' . wp_generate_uuid4(); // You'll need to use your actual session generation logic 405 406 // Check if user is logged in first 407 if (is_user_logged_in()) { 408 $current_user = wp_get_current_user(); 409 return [ 410 'show_email_form' => false, 411 'user_email' => $current_user->user_email, 412 'user_name' => $current_user->display_name ?: $current_user->first_name ?: '' 413 ]; 414 } 415 416 // Check stored email for session 417 $stored_email = get_option("mxchat_email_{$session_id}", ''); 418 $stored_name = get_option("mxchat_name_{$session_id}", ''); 419 420 // Check if name is required 421 $name_field_enabled = isset($this->options['enable_name_field']) && 422 ($this->options['enable_name_field'] === '1' || $this->options['enable_name_field'] === 'on'); 423 424 $has_required_info = !empty($stored_email); 425 if ($name_field_enabled) { 426 $has_required_info = $has_required_info && !empty($stored_name); 427 } 428 429 return [ 430 'show_email_form' => !$has_required_info, 431 'user_email' => $stored_email, 432 'user_name' => $stored_name 433 ]; 434 } 435 436 437 438 439 440 385 441 } 386 442 ?> -
mxchat-basic/trunk/js/chat-script.js
r3340699 r3343848 2037 2037 2038 2038 // ==================================== 2039 // IMPROVEDEMAIL COLLECTION SETUP2039 // EMAIL COLLECTION SETUP 2040 2040 // ==================================== 2041 2042 2041 // Email collection form setup and handlers 2043 2042 const emailForm = document.getElementById('email-collection-form'); … … 2046 2045 2047 2046 if (emailForm && emailBlocker && chatbotWrapper) { 2047 2048 // NEW: Check if server already provided the email state 2049 if (mxchatChat.skip_email_check && mxchatChat.initial_email_state) { 2050 console.log('Using server-provided email state:', mxchatChat.initial_email_state); 2051 2052 // Use server-provided state instead of making AJAX call 2053 const emailState = mxchatChat.initial_email_state; 2054 if (emailState.show_email_form) { 2055 showEmailForm(); 2056 } else { 2057 showChatContainer(); 2058 } 2059 2060 // Continue to set up form handlers but skip the AJAX check 2061 setupFormHandlers(); 2062 2063 } else { 2064 // FALLBACK: Use existing AJAX approach if server state not available 2065 console.log('Server state not available, using AJAX fallback'); 2066 setupFormHandlers(); 2067 // Initialize email check with delay to prevent race conditions 2068 setTimeout(checkSessionAndEmail, 100); 2069 } 2070 2048 2071 // Add loading state management 2049 2072 let isSubmitting = false; … … 2118 2141 } 2119 2142 2143 // Enhanced name validation 2144 function isValidName(name) { 2145 return name && name.trim().length >= 2 && name.trim().length <= 100; 2146 } 2147 2120 2148 // Show loading state with spinner 2121 2149 function setSubmissionState(loading) { 2122 2150 const submitButton = document.getElementById('email-submit-button'); 2123 2151 const emailInput = document.getElementById('user-email'); 2152 const nameInput = document.getElementById('user-name'); 2124 2153 2125 2154 if (loading) { … … 2127 2156 submitButton.disabled = true; 2128 2157 emailInput.disabled = true; 2158 if (nameInput) nameInput.disabled = true; 2129 2159 2130 2160 // Store original content and add spinner … … 2150 2180 submitButton.disabled = false; 2151 2181 emailInput.disabled = false; 2182 if (nameInput) nameInput.disabled = false; 2152 2183 2153 2184 // Restore original content … … 2159 2190 submitButton.style.opacity = '1'; 2160 2191 } 2161 }2162 2163 // Add CSS for spinner animation if not already present2164 if (!document.getElementById('email-spinner-styles')) {2165 const style = document.createElement('style');2166 style.id = 'email-spinner-styles';2167 style.textContent = `2168 @keyframes spin {2169 from { transform: rotate(0deg); }2170 to { transform: rotate(360deg); }2171 }2172 .email-spinner {2173 display: inline-block;2174 vertical-align: middle;2175 }2176 `;2177 document.head.appendChild(style);2178 }2179 2180 // Handle email form submission with improved error handling2181 emailForm.addEventListener('submit', function (event) {2182 event.preventDefault();2183 2184 // Prevent double submission2185 if (isSubmitting) {2186 return;2187 }2188 2189 const userEmail = document.getElementById('user-email').value.trim();2190 const sessionId = getChatSession();2191 2192 // Validate email before submission2193 if (!userEmail) {2194 showEmailError('Please enter your email address.');2195 return;2196 }2197 2198 if (!isValidEmail(userEmail)) {2199 showEmailError('Please enter a valid email address.');2200 return;2201 }2202 2203 // Clear any existing errors2204 clearEmailError();2205 setSubmissionState(true);2206 2207 // Add timeout for submission2208 const controller = new AbortController();2209 const timeoutId = setTimeout(() => {2210 controller.abort();2211 setSubmissionState(false);2212 showEmailError('Request timed out. Please try again.');2213 }, 15000); // 15 second timeout2214 2215 fetch(mxchatChat.ajax_url, {2216 method: 'POST',2217 headers: {2218 'Content-Type': 'application/x-www-form-urlencoded',2219 },2220 body: new URLSearchParams({2221 action: 'mxchat_handle_save_email_and_response',2222 email: userEmail,2223 session_id: sessionId,2224 nonce: mxchatChat.nonce,2225 }),2226 signal: controller.signal2227 })2228 .then((response) => {2229 clearTimeout(timeoutId);2230 if (!response.ok) {2231 throw new Error(`HTTP error! status: ${response.status}`);2232 }2233 return response.json();2234 })2235 .then((data) => {2236 setSubmissionState(false);2237 2238 if (data.success) {2239 // Show chat immediately2240 showChatContainer();2241 2242 // Handle bot response if provided2243 if (data.message && typeof appendMessage === 'function') {2244 setTimeout(() => {2245 appendMessage('bot', data.message);2246 if (typeof scrollToBottom === 'function') {2247 scrollToBottom();2248 }2249 }, 100);2250 }2251 } else {2252 showEmailError(data.message || 'Failed to save email. Please try again.');2253 }2254 })2255 .catch((error) => {2256 clearTimeout(timeoutId);2257 setSubmissionState(false);2258 2259 if (error.name === 'AbortError') {2260 showEmailError('Request timed out. Please try again.');2261 } else {2262 console.error('Email submission error:', error);2263 showEmailError('An error occurred. Please try again.');2264 }2265 });2266 });2267 2268 // Real-time email validation2269 const emailInput = document.getElementById('user-email');2270 if (emailInput) {2271 let validationTimeout;2272 2273 emailInput.addEventListener('input', function() {2274 // Clear previous validation timeout2275 if (validationTimeout) {2276 clearTimeout(validationTimeout);2277 }2278 2279 // Debounce validation2280 validationTimeout = setTimeout(() => {2281 const email = this.value.trim();2282 clearEmailError();2283 2284 if (email && !isValidEmail(email)) {2285 showEmailError('Please enter a valid email address.');2286 }2287 }, 500);2288 });2289 2290 // Handle Enter key2291 emailInput.addEventListener('keypress', function(e) {2292 if (e.key === 'Enter' && !isSubmitting) {2293 emailForm.dispatchEvent(new Event('submit'));2294 }2295 });2296 2192 } 2297 2193 … … 2334 2230 emailForm.appendChild(errorDiv); 2335 2231 2336 // Add shake animation to input 2232 // Add shake animation to inputs 2233 const emailInput = document.getElementById('user-email'); 2234 const nameInput = document.getElementById('user-name'); 2235 2337 2236 if (emailInput) { 2338 2237 emailInput.classList.add('email-input-shake'); … … 2341 2240 }, 500); 2342 2241 } 2242 2243 if (nameInput) { 2244 nameInput.classList.add('email-input-shake'); 2245 setTimeout(() => { 2246 nameInput.classList.remove('email-input-shake'); 2247 }, 500); 2248 } 2343 2249 } 2344 2250 … … 2348 2254 } 2349 2255 2350 // Initialize email check with delay to prevent race conditions 2351 setTimeout(checkSessionAndEmail, 100); 2352 2353 } else if (mxchatChat.email_collection_enabled) { 2256 // NEW: Separate function to set up all form handlers 2257 function setupFormHandlers() { 2258 // Add CSS for spinner animation if not already present 2259 if (!document.getElementById('email-spinner-styles')) { 2260 const style = document.createElement('style'); 2261 style.id = 'email-spinner-styles'; 2262 style.textContent = ` 2263 @keyframes spin { 2264 from { transform: rotate(0deg); } 2265 to { transform: rotate(360deg); } 2266 } 2267 .email-spinner { 2268 display: inline-block; 2269 vertical-align: middle; 2270 } 2271 `; 2272 document.head.appendChild(style); 2273 } 2274 2275 // Handle email form submission with improved error handling 2276 emailForm.addEventListener('submit', function (event) { 2277 event.preventDefault(); 2278 2279 // Prevent double submission 2280 if (isSubmitting) { 2281 return; 2282 } 2283 2284 const userEmail = document.getElementById('user-email').value.trim(); 2285 const nameInput = document.getElementById('user-name'); 2286 const userName = nameInput ? nameInput.value.trim() : ''; 2287 const sessionId = getChatSession(); 2288 2289 // Validate email before submission 2290 if (!userEmail) { 2291 showEmailError('Please enter your email address.'); 2292 return; 2293 } 2294 2295 if (!isValidEmail(userEmail)) { 2296 showEmailError('Please enter a valid email address.'); 2297 return; 2298 } 2299 2300 // Validate name if field exists 2301 if (nameInput && !isValidName(userName)) { 2302 showEmailError('Please enter a valid name (2-100 characters).'); 2303 return; 2304 } 2305 2306 // Clear any existing errors 2307 clearEmailError(); 2308 setSubmissionState(true); 2309 2310 // Add timeout for submission 2311 const controller = new AbortController(); 2312 const timeoutId = setTimeout(() => { 2313 controller.abort(); 2314 setSubmissionState(false); 2315 showEmailError('Request timed out. Please try again.'); 2316 }, 15000); // 15 second timeout 2317 2318 // Prepare form data with optional name 2319 const formData = new URLSearchParams({ 2320 action: 'mxchat_handle_save_email_and_response', 2321 email: userEmail, 2322 session_id: sessionId, 2323 nonce: mxchatChat.nonce, 2324 }); 2325 2326 // Add name to form data if provided 2327 if (userName) { 2328 formData.append('name', userName); 2329 } 2330 2331 fetch(mxchatChat.ajax_url, { 2332 method: 'POST', 2333 headers: { 2334 'Content-Type': 'application/x-www-form-urlencoded', 2335 }, 2336 body: formData, 2337 signal: controller.signal 2338 }) 2339 .then((response) => { 2340 clearTimeout(timeoutId); 2341 if (!response.ok) { 2342 throw new Error(`HTTP error! status: ${response.status}`); 2343 } 2344 return response.json(); 2345 }) 2346 .then((data) => { 2347 setSubmissionState(false); 2348 2349 if (data.success) { 2350 // Show chat immediately 2351 showChatContainer(); 2352 2353 // Handle bot response if provided 2354 if (data.message && typeof appendMessage === 'function') { 2355 setTimeout(() => { 2356 appendMessage('bot', data.message); 2357 if (typeof scrollToBottom === 'function') { 2358 scrollToBottom(); 2359 } 2360 }, 100); 2361 } 2362 } else { 2363 showEmailError(data.message || 'Failed to save email. Please try again.'); 2364 } 2365 }) 2366 .catch((error) => { 2367 clearTimeout(timeoutId); 2368 setSubmissionState(false); 2369 2370 if (error.name === 'AbortError') { 2371 showEmailError('Request timed out. Please try again.'); 2372 } else { 2373 console.error('Email submission error:', error); 2374 showEmailError('An error occurred. Please try again.'); 2375 } 2376 }); 2377 }); 2378 2379 // Real-time email validation 2380 const emailInput = document.getElementById('user-email'); 2381 if (emailInput) { 2382 let validationTimeout; 2383 2384 emailInput.addEventListener('input', function() { 2385 // Clear previous validation timeout 2386 if (validationTimeout) { 2387 clearTimeout(validationTimeout); 2388 } 2389 2390 // Debounce validation 2391 validationTimeout = setTimeout(() => { 2392 const email = this.value.trim(); 2393 clearEmailError(); 2394 2395 if (email && !isValidEmail(email)) { 2396 showEmailError('Please enter a valid email address.'); 2397 } 2398 }, 500); 2399 }); 2400 2401 // Handle Enter key 2402 emailInput.addEventListener('keypress', function(e) { 2403 if (e.key === 'Enter' && !isSubmitting) { 2404 emailForm.dispatchEvent(new Event('submit')); 2405 } 2406 }); 2407 } 2408 2409 // Real-time name validation 2410 const nameInput = document.getElementById('user-name'); 2411 if (nameInput) { 2412 let nameValidationTimeout; 2413 2414 nameInput.addEventListener('input', function() { 2415 // Clear previous validation timeout 2416 if (nameValidationTimeout) { 2417 clearTimeout(nameValidationTimeout); 2418 } 2419 2420 // Debounce validation 2421 nameValidationTimeout = setTimeout(() => { 2422 const name = this.value.trim(); 2423 clearEmailError(); 2424 2425 if (name && !isValidName(name)) { 2426 showEmailError('Name must be between 2 and 100 characters.'); 2427 } 2428 }, 500); 2429 }); 2430 2431 // Handle Enter key 2432 nameInput.addEventListener('keypress', function(e) { 2433 if (e.key === 'Enter' && !isSubmitting) { 2434 emailForm.dispatchEvent(new Event('submit')); 2435 } 2436 }); 2437 } 2438 } 2439 2440 } else if (mxchatChat && mxchatChat.email_collection_enabled) { 2354 2441 console.error('Essential elements for email handling are missing:', { 2355 2442 emailForm: !!emailForm, -
mxchat-basic/trunk/js/mxchat-admin.js
r3341601 r3343848 2069 2069 } 2070 2070 }); 2071 2072 jQuery(document).ready(function($) { 2073 var emailDependentFields = [ 2074 '#email_blocker_header_content', 2075 '#email_blocker_button_text', 2076 '#enable_name_field', 2077 '#name_field_placeholder' 2078 ]; 2079 2080 // Add visual indicators 2081 emailDependentFields.forEach(function(fieldId) { 2082 var $row = $(fieldId).closest('tr'); 2083 $row.addClass('email-dependent-field'); 2084 2085 // Add an icon to show it's dependent 2086 var $label = $row.find('th label, th'); 2087 $label.prepend('<span class="email-dependent-icon" style="color: #0073aa; margin-right: 5px;">↳</span>'); 2088 }); 2089 2090 // Hide initially with opacity for smoother transition 2091 emailDependentFields.forEach(function(fieldId) { 2092 $(fieldId).closest('tr').hide().css('opacity', '0'); 2093 }); 2094 2095 function toggleEmailFields() { 2096 var emailEnabled = $('#enable_email_block').is(':checked'); 2097 2098 emailDependentFields.forEach(function(fieldId) { 2099 var $row = $(fieldId).closest('tr'); 2100 if (emailEnabled) { 2101 $row.slideDown(400).animate({opacity: 1}, 200); 2102 } else { 2103 $row.animate({opacity: 0}, 200).slideUp(400); 2104 } 2105 }); 2106 } 2107 2108 toggleEmailFields(); 2109 $('#enable_email_block').on('change', toggleEmailFields); 2110 }); 2111 -
mxchat-basic/trunk/mxchat-basic.php
r3341601 r3343848 3 3 * Plugin Name: MxChat 4 4 * Description: AI chatbot for WordPress with OpenAI, Claude, xAI, DeepSeek, live agent, PDF uploads, WooCommerce, and training on website data. 5 * Version: 2.3. 75 * Version: 2.3.8 6 6 * Author: MxChat 7 7 * Author URI: https://mxchat.ai … … 17 17 18 18 // Define plugin version constant for asset versioning 19 define('MXCHAT_VERSION', '2.3. 7');19 define('MXCHAT_VERSION', '2.3.8'); 20 20 21 21 function mxchat_load_textdomain() { … … 50 50 51 51 /** 52 * NEW:Create URL click tracking table52 * Create URL click tracking table 53 53 */ 54 54 function mxchat_create_url_clicks_table() { … … 76 76 } 77 77 78 function mxchat_activate() { 78 /** 79 * FIXED: Robust table creation and column management 80 */ 81 function mxchat_create_chat_transcripts_table() { 79 82 global $wpdb; 83 84 $table_name = $wpdb->prefix . 'mxchat_chat_transcripts'; 80 85 $charset_collate = $wpdb->get_charset_collate(); 81 82 // Chat Transcripts Table 83 $chat_transcripts_table = $wpdb->prefix . 'mxchat_chat_transcripts'; 84 $sql_chat_transcripts = "CREATE TABLE $chat_transcripts_table ( 86 87 // Create table with ALL columns including user_name from the start 88 $sql = "CREATE TABLE $table_name ( 85 89 id MEDIUMINT(9) NOT NULL AUTO_INCREMENT, 86 90 user_id MEDIUMINT(9) DEFAULT 0, … … 89 93 message TEXT NOT NULL, 90 94 user_email VARCHAR(255) DEFAULT NULL, 95 user_name VARCHAR(100) DEFAULT NULL, 96 user_identifier VARCHAR(255) DEFAULT NULL, 97 originating_page_url TEXT DEFAULT NULL, 98 originating_page_title VARCHAR(500) DEFAULT NULL, 91 99 timestamp TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL, 92 PRIMARY KEY (id) 100 PRIMARY KEY (id), 101 KEY session_id (session_id), 102 KEY user_email (user_email), 103 KEY timestamp (timestamp) 93 104 ) $charset_collate;"; 105 106 require_once(ABSPATH . 'wp-admin/includes/upgrade.php'); 107 $result = dbDelta($sql); 108 109 // Log the result for debugging 110 if (empty($result)) { 111 //error_log("MxChat: dbDelta returned empty result for chat transcripts table"); 112 } else { 113 //error_log("MxChat: dbDelta result: " . print_r($result, true)); 114 } 115 116 // IMPORTANT: Ensure all columns exist for existing installations 117 mxchat_ensure_all_columns($table_name); 118 } 119 120 /** 121 * IMPROVED: Ensure all required columns exist (for upgrades) 122 */ 123 function mxchat_ensure_all_columns($table_name) { 124 global $wpdb; 125 126 // First check if table exists 127 $table_exists = $wpdb->get_var("SHOW TABLES LIKE '$table_name'") === $table_name; 128 if (!$table_exists) { 129 //error_log("MxChat: Table $table_name does not exist, cannot add columns"); 130 return; 131 } 132 133 // Define all required columns and their types 134 $required_columns = [ 135 'user_identifier' => 'VARCHAR(255) DEFAULT NULL', 136 'user_email' => 'VARCHAR(255) DEFAULT NULL', 137 'user_name' => 'VARCHAR(100) DEFAULT NULL', 138 'originating_page_url' => 'TEXT DEFAULT NULL', 139 'originating_page_title' => 'VARCHAR(500) DEFAULT NULL' 140 ]; 141 142 // Get existing columns 143 $existing_columns = $wpdb->get_results("SHOW COLUMNS FROM $table_name"); 144 if (empty($existing_columns)) { 145 //error_log("MxChat: Could not get columns for table $table_name"); 146 return; 147 } 148 149 $existing_column_names = array_column($existing_columns, 'Field'); 150 151 // Add missing columns 152 foreach ($required_columns as $column_name => $column_definition) { 153 if (!in_array($column_name, $existing_column_names)) { 154 $alter_sql = "ALTER TABLE $table_name ADD COLUMN $column_name $column_definition"; 155 $result = $wpdb->query($alter_sql); 156 157 if ($result === false) { 158 //error_log("MxChat: Failed to add column $column_name to $table_name. Error: " . $wpdb->last_error); 159 } else { 160 //error_log("MxChat: Successfully added column $column_name to $table_name"); 161 } 162 } 163 } 164 } 165 166 function mxchat_activate() { 167 global $wpdb; 168 $charset_collate = $wpdb->get_charset_collate(); 169 170 //error_log("MxChat: Running activation function"); 171 172 // Create chat transcripts table with improved function 173 mxchat_create_chat_transcripts_table(); 94 174 95 175 // System Prompt Content Table … … 114 194 callback_function VARCHAR(255) NOT NULL, 115 195 similarity_threshold FLOAT DEFAULT 0.85, 196 enabled TINYINT(1) NOT NULL DEFAULT 1, 116 197 PRIMARY KEY (id) 117 198 ) $charset_collate;"; … … 119 200 require_once ABSPATH . 'wp-admin/includes/upgrade.php'; 120 201 121 // Create or update tables 122 dbDelta($sql_chat_transcripts); 202 // Create other tables 123 203 dbDelta($sql_system_prompt); 124 204 dbDelta($sql_intents_table); 125 205 126 // NEW:Create URL click tracking table206 // Create URL click tracking table 127 207 mxchat_create_url_clicks_table(); 128 208 129 // Ensure additional columns in `mxchat_chat_transcripts` 130 mxchat_add_missing_columns($chat_transcripts_table, 'user_identifier', 'VARCHAR(255)'); 131 mxchat_add_missing_columns($chat_transcripts_table, 'user_email', 'VARCHAR(255) DEFAULT NULL'); 132 133 // NEW: Add originating page tracking columns 134 mxchat_add_missing_columns($chat_transcripts_table, 'originating_page_url', 'TEXT DEFAULT NULL'); 135 mxchat_add_missing_columns($chat_transcripts_table, 'originating_page_title', 'VARCHAR(500) DEFAULT NULL'); 136 137 // Ensure additional columns in `mxchat_system_prompt_content` 138 mxchat_add_missing_columns($system_prompt_table, 'embedding_vector', 'LONGTEXT'); 139 mxchat_add_missing_columns($system_prompt_table, 'source_url', 'VARCHAR(255) DEFAULT NULL'); 209 // Ensure additional columns in system prompt table 210 $existing_system_columns = $wpdb->get_results("SHOW COLUMNS FROM $system_prompt_table"); 211 if (!empty($existing_system_columns)) { 212 $existing_system_column_names = array_column($existing_system_columns, 'Field'); 213 214 if (!in_array('embedding_vector', $existing_system_column_names)) { 215 $wpdb->query("ALTER TABLE $system_prompt_table ADD COLUMN embedding_vector LONGTEXT"); 216 } 217 if (!in_array('source_url', $existing_system_column_names)) { 218 $wpdb->query("ALTER TABLE $system_prompt_table ADD COLUMN source_url VARCHAR(255) DEFAULT NULL"); 219 } 220 } 140 221 141 222 // Set default thresholds for existing intents 142 223 $wpdb->query("UPDATE {$intents_table} SET similarity_threshold = 0.85 WHERE similarity_threshold IS NULL"); 143 mxchat_add_missing_columns($intents_table, 'enabled', 'TINYINT(1) NOT NULL DEFAULT 1'); 144 145 // SETUP CRON JOB HERE (ONCE ON ACTIVATION) 224 225 // Ensure enabled column exists in intents table 226 $existing_intent_columns = $wpdb->get_results("SHOW COLUMNS FROM $intents_table"); 227 if (!empty($existing_intent_columns)) { 228 $existing_intent_column_names = array_column($existing_intent_columns, 'Field'); 229 230 if (!in_array('enabled', $existing_intent_column_names)) { 231 $wpdb->query("ALTER TABLE $intents_table ADD COLUMN enabled TINYINT(1) NOT NULL DEFAULT 1"); 232 } 233 } 234 235 // Setup cron jobs 146 236 mxchat_setup_cron_jobs(); 147 237 148 // U se the constant instead of hardcodedversion238 // Update version 149 239 update_option('mxchat_plugin_version', MXCHAT_VERSION); 240 241 //error_log("MxChat: Activation function completed"); 150 242 } 151 243 … … 162 254 update_option('mxchat_use_fallback_rate_limits', true); 163 255 update_option('mxchat_next_rate_limit_check', time() + 3600); 164 //error_log('MxChat: WordPress cron disabled, using fallback system');165 256 return; 166 257 } … … 173 264 update_option('mxchat_use_fallback_rate_limits', true); 174 265 update_option('mxchat_next_rate_limit_check', time() + 3600); 175 //error_log('MxChat: Failed to schedule cron on activation, using fallback');176 266 } else { 177 267 // Clear fallback flags if cron scheduling succeeded 178 268 delete_option('mxchat_use_fallback_rate_limits'); 179 //error_log('MxChat: Successfully scheduled cron on activation');180 269 } 181 270 } … … 192 281 delete_option('mxchat_next_rate_limit_check'); 193 282 delete_option('mxchat_fallback_check_interval'); 194 195 //error_log('MxChat: Cleaned up cron jobs on deactivation');196 283 } 197 284 … … 220 307 } 221 308 222 function mxchat_add_missing_columns($table, $column_name, $column_type) { 223 global $wpdb; 224 $column_exists = $wpdb->get_results($wpdb->prepare("SHOW COLUMNS FROM $table LIKE %s", $column_name)); 225 if (empty($column_exists)) { 226 $wpdb->query("ALTER TABLE $table ADD COLUMN $column_name $column_type"); 227 } 228 } 229 309 /** 310 * FIXED: Robust update checking with proper version handling 311 */ 230 312 function mxchat_check_for_update() { 313 global $wpdb; // CRITICAL: Declare this at the top 314 231 315 try { 232 $current_version = get_option('mxchat_plugin_version' );316 $current_version = get_option('mxchat_plugin_version', '0.0.0'); 233 317 $plugin_version = MXCHAT_VERSION; 234 318 319 // Always run activation to ensure tables exist (safe for existing installations) 235 320 if ($current_version !== $plugin_version) { 321 //error_log("MxChat: Version change detected: $current_version -> $plugin_version"); 322 236 323 // Run live agent update BEFORE updating the stored version 237 324 mxchat_handle_live_agent_update(); 238 325 239 // Run existing update processes326 // Run activation (this will create/update all tables and columns) 240 327 mxchat_activate(); 328 329 // Run migration functions 241 330 mxchat_migrate_live_agent_status(); 242 331 243 // Add the newcleanup function for version 2.1.8332 // Add the cleanup function for version 2.1.8 244 333 if (version_compare($current_version, '2.1.8', '<')) { 245 334 $deleted = mxchat_cleanup_orphaned_chat_history(); 246 335 } 247 336 248 // Update version LAST so the live agent update logic can work337 // Update version LAST 249 338 update_option('mxchat_plugin_version', $plugin_version); 250 } 339 340 //error_log("MxChat: Updated from version $current_version to $plugin_version"); 341 } 342 343 // CRITICAL: Always ensure tables exist, even if version matches 344 // This handles cases where tables were manually deleted 345 $table_name = $wpdb->prefix . 'mxchat_chat_transcripts'; 346 $table_exists = $wpdb->get_var("SHOW TABLES LIKE '$table_name'") === $table_name; 347 348 if (!$table_exists) { 349 //error_log("MxChat: Chat transcripts table missing, recreating..."); 350 mxchat_activate(); // Run full activation instead of just table creation 351 } 352 251 353 } catch (Exception $e) { 252 354 //error_log('MxChat update error: ' . $e->getMessage()); 253 355 // Don't update version if there was an error 356 } 357 } 358 359 /** 360 * CRITICAL: Ensure tables exist on every load for fresh installations 361 */ 362 function mxchat_ensure_tables_exist() { 363 global $wpdb; 364 365 // Only run for admin users to avoid performance impact 366 if (!current_user_can('administrator')) { 367 return; 368 } 369 370 $table_name = $wpdb->prefix . 'mxchat_chat_transcripts'; 371 $table_exists = $wpdb->get_var("SHOW TABLES LIKE '$table_name'") === $table_name; 372 373 if (!$table_exists) { 374 //error_log("MxChat: Tables missing on admin load, running activation"); 375 mxchat_activate(); 254 376 } 255 377 } … … 288 410 // Also delete related metadata 289 411 delete_option("mxchat_email_{$session_id}"); 412 delete_option("mxchat_name_{$session_id}"); 290 413 delete_option("mxchat_agent_name_{$session_id}"); 291 414 $count++; … … 364 487 mxchat_check_for_update(); 365 488 489 // CRITICAL: Ensure tables exist (for fresh installations that don't trigger activation hook) 490 add_action('admin_init', 'mxchat_ensure_tables_exist', 1); 491 366 492 // Add fallback rate limit check 367 493 add_action('init', 'mxchat_check_fallback_rate_limits', 5); -
mxchat-basic/trunk/readme.txt
r3341601 r3343848 6 6 Tested up to: 6.8 7 7 Requires PHP: 7.2 8 Stable tag: 2.3. 78 Stable tag: 2.3.8 9 9 License: GPLv2 or later 10 10 License URI: https://www.gnu.org/licenses/gpl-2.0.html … … 34 34 ✅ **Extensive Add-On Ecosystem**: Forms, moderation, recommendations, theme customization, and more 35 35 36 ### 2.3.7 37 🤖 **New Models** 38 - Added **GPT-5 family** models: 39 - **GPT-5** – Flagship for coding, reasoning, and agentic tasks across domains. 40 - **GPT-5 Mini** – Faster, more cost-efficient for well-defined tasks and precise prompts. 41 - **GPT-5 Nano** – Fastest and most affordable; ideal for summarization and classification. 36 ## 🔥 What's New in Version 2.3.8 37 🔧 **Fixed Extra Characters in Knowledgebase** – Prevented extra backslashes from appearing when editing content in the knowledgebase. 38 👤 **Enhanced Require Email to Chat Form** – Added an optional name field to the require email to chat form. Now, at the top of chat transcripts, it will show email + name if enabled. 39 💬 **Improved Slack Channel Naming** – When notifying live agents via Slack, the channel name will now be: the user's email if logged in; their email if require email to chat is enabled; otherwise, the chat ID. 42 40 43 41 ## 🚀 Core Features That Set MxChat Apart … … 175 173 == Changelog == 176 174 175 = 2.3.8 - August 12, 2025 = 176 - Fixed extra backslashes appearing in knowledgebase content during editing. 177 - Added optional name field to Require Email to Chat form; transcripts now display email and name if enabled. 178 - Updated Slack channel naming for live agent notifications: uses user's email if logged in, email if Require Email to Chat is enabled, or chat ID otherwise. 179 177 180 = 2.3.7 - August 8, 2025 = 178 181 - New Models: Added GPT-5 family (GPT-5, GPT-5 Mini, GPT-5 Nano) to expand capabilities with faster, smarter, and more cost-efficient options. 179 180 182 = 2.3.6 - August 6, 2025 = 181 183 - Bug Fix: Fixed streaming fallback to properly display responses when streaming fails, preventing blank chat bubbles. … … 505 507 == Upgrade Notice == 506 508 507 = 2.3.7 = 508 - New Models: Added GPT-5 family (GPT-5, GPT-5 Mini, GPT-5 Nano) for faster, smarter, and more versatile AI responses. 509 = 2.3.8 = 510 - Fixed extra backslashes appearing in knowledgebase content during editing. 511 - Added optional name field to Require Email to Chat form; transcripts now display email and name if enabled. 512 - Updated Slack channel naming for live agent notifications: uses user's email if logged in, email if Require Email to Chat is enabled, or chat ID otherwise. 509 513 510 514 == License & Warranty ==
Note: See TracChangeset
for help on using the changeset viewer.