PluginProbe
MxChat – AI Chatbot & Content Generation for WordPress / 1.0.6
MxChat – AI Chatbot & Content Generation for WordPress v1.0.6
3.2.21 3.2.20 3.2.19 3.2.18 3.2.17 3.2.16 3.2.15 3.2.14 3.2.12 3.2.13 3.2.11 3.2.10 3.2.9 3.2.8 3.2.7 3.2.6 3.2.5 3.2.4 3.2.3 3.2.2 3.2.1 2.0.3 2.0.4 2.0.5 2.0.6 All 152 releases
← All changes | includes/class-mxchat-admin.php +1036 -5406 2.0.51.0.6 View file →
@@ -20,9 +20,8 @@
20 20
21 21 // Add admin menu and initialize settings
22 22 add_action('admin_menu', array($this, 'mxchat_add_plugin_page'));
23 23 add_action('admin_init', array($this, 'mxchat_page_init'));
24 - add_action('admin_init', array($this, 'mxchat_prompts_page_init'));
25 24 add_action('admin_enqueue_scripts', array($this, 'mxchat_enqueue_admin_assets'));
26 25 add_action('wp_ajax_mxchat_delete_chat_history', array($this, 'mxchat_delete_chat_history'));
27 26 add_action('admin_post_mxchat_submit_content', array($this, 'mxchat_handle_content_submission'));
28 27 add_action('admin_post_mxchat_delete_prompt', array($this, 'mxchat_handle_delete_prompt'));
@@ -33,1345 +32,491 @@
33 32 add_action('admin_head-mxchat-prompts', array($this, 'mxchat_enqueue_admin_assets'));
34 33 add_action('admin_head-toplevel_page_mxchat-max', array($this, 'mxchat_enqueue_admin_assets'));
35 34 add_action('wp_ajax_mxchat_activate_license', array($this, 'mxchat_handle_activate_license'));
36 35 add_action('admin_notices', array($this, 'mxchat_display_admin_notice'));
37 - add_action('wp_ajax_mxchat_save_inline_prompt', array($this, 'mxchat_save_inline_prompt'));
38 - add_action('admin_post_mxchat_delete_all_prompts', array($this, 'mxchat_handle_delete_all_prompts'));
39 - add_action('admin_post_mxchat_add_intent', array($this, 'mxchat_handle_add_intent'));
40 - add_action('admin_post_mxchat_delete_intent', array($this, 'mxchat_handle_delete_intent'));
41 - add_action('admin_post_mxchat_update_intent_threshold', array($this, 'mxchat_handle_update_intent_threshold'));
42 - add_action('admin_post_mxchat_stop_processing', array($this, 'mxchat_stop_processing'));
43 - add_action('admin_post_mxchat_edit_intent', array($this, 'handle_edit_intent'));
44 - add_action('save_post', array($this, 'handle_post_update'), 10, 3);
45 - add_action('post_updated', array($this, 'handle_post_update'), 10, 3);
46 - add_action('wp_ajax_mxchat_save_setting', array($this, 'mxchat_save_setting_callback'));
47 - add_action('wp_trash_post', array($this, 'mxchat_handle_post_delete'));
48 - add_action('before_delete_post', array($this, 'mxchat_handle_post_delete'));
49 - add_action('wp_ajax_mxchat_export_transcripts', array($this, 'export_chat_transcripts'));
50 - add_action('wp_ajax_mxchat_save_prompts_setting', array($this, 'mxchat_save_prompts_setting_callback'));
51 - if (isset($this->options['enable_woocommerce_integration']) &&
52 - ($this->options['enable_woocommerce_integration'] === '1' ||
53 - $this->options['enable_woocommerce_integration'] === 'on')) {
54 36
55 - //error_log('MxChat Admin: WooCommerce integration is enabled, adding hooks');
56 - add_action('wp_insert_post', array($this, 'mxchat_handle_product_change'), 10, 3);
57 - add_action('wp_trash_post', array($this, 'mxchat_handle_product_delete'));
58 - add_action('before_delete_post', array($this, 'mxchat_handle_product_delete'));
59 - }
60 37 }
61 38
62 39 // Method to check if the license is active
63 -private function is_license_active() {
64 - $license_status = get_option('mxchat_license_status', esc_html__('inactive', 'mxchat'));
65 - return $license_status === esc_html__('active', 'mxchat');
40 + private function is_license_active() {
41 + $license_status = get_option('mxchat_license_status', 'inactive');
42 + return $license_status === 'active';
66 43 }
67 44
68 45 // Initialize default options
69 -private function initialize_default_options() {
70 - $default_options = array(
71 - 'api_key' => '',
72 - 'xai_api_key' => '',
73 - 'claude_api_key' => '',
74 - 'deepseek_api_key' => '',
75 - 'system_prompt_instructions' => esc_html__('[EXAMPLE INSTRUCTIONS] You are an AI Chatbot assistant for this website. The primary subject you should focus on is [insert proper subject here]. Your main goal is to assist visitors with questions related to this specific topic. Here are some key things to keep in mind:
76 - - Your name is [Chatbot Name].
77 - - Stay focused on topics related to [insert proper subject here]. If a visitor asks about an unrelated topic, politely redirect the conversation to how you can assist them with this subject.
78 - - Do not make up links to pages. Only use specific links you see in your knowledgebase from [insert your domain]. Do not make assumptions or make up URLs.
79 - - Keep your responses short, concise, and to the point. Provide clear and direct answers suitable for a chatbot interaction.
80 - - Provide answers based on the knowledge available to you. If you do not have an answer to a specific question, let the visitor know that you don’t have the information.', 'mxchat'),
81 - 'model' => esc_html__('gpt-4o', 'mxchat'),
82 - 'rate_limit_logged_out' => esc_html__('100', 'mxchat'),
83 - 'role_rate_limits' => array(),
84 - 'rate_limit_message' => esc_html__('Rate limit exceeded. Please try again later.', 'mxchat'),
85 - 'enable_email_block' => '',
86 - 'email_blocker_header_content' => esc_html__("<h2>Welcome to Our Chat!</h2>\n<p>Let's get started. Enter your email to begin chatting with us.</p>", 'mxchat'),
87 - 'email_blocker_button_text' => esc_html__('Start Chat', 'mxchat'),
88 - 'top_bar_title' => esc_html__('MxChat', 'mxchat'),
89 - 'intro_message' => esc_html__('Hello! How can I assist you today?', 'mxchat'),
90 - 'input_copy' => esc_html__('How can I assist?', 'mxchat'),
91 - 'append_to_body' => esc_html__('off', 'mxchat'),
92 - 'close_button_color' => esc_html__('#fff', 'mxchat'),
93 - 'chatbot_bg_color' => esc_html__('#fff', 'mxchat'),
94 - 'user_message_bg_color' => esc_html__('#fff', 'mxchat'),
95 - 'user_message_font_color' => esc_html__('#212121', 'mxchat'),
96 - 'bot_message_bg_color' => esc_html__('#212121', 'mxchat'),
97 - 'bot_message_font_color' => esc_html__('#fff', 'mxchat'),
98 - 'top_bar_bg_color' => esc_html__('#212121', 'mxchat'),
99 - 'send_button_font_color' => esc_html__('#212121', 'mxchat'),
100 - 'chat_input_font_color' => esc_html__('#212121', 'mxchat'),
101 - 'chatbot_background_color' => esc_html__('#212121', 'mxchat'),
102 - 'icon_color' => esc_html__('#fff', 'mxchat'),
103 - 'enable_woocommerce_integration' => esc_html__('0', 'mxchat'),
104 - 'link_target_toggle' => esc_html__('off', 'mxchat'),
105 - 'pre_chat_message' => esc_html__('Hey there! Ask me anything!', 'mxchat'),
46 + private function initialize_default_options() {
47 + $default_options = array(
48 + 'api_key' => '',
49 + 'system_prompt_instructions' => '[EXAMPLE INSTRUCTIONS] You are an AI Chatbot assistant for this website. The primary subject you should focus on is [insert proper subject here]. Your main goal is to assist visitors with questions related to this specific topic. Here are some key things to keep in mind:
50 + - Your name is [Chatbot Name]. Always introduce yourself as this name when appropriate.
51 + - Stay focused on topics related to [insert proper subject here]. If a visitor asks about an unrelated topic, politely redirect the conversation to how you can assist them with this subject. If there is an exception topic (e.g., "parking") that you should assist with, you may do so if instructed.
52 + - When appropriate, highlight the benefits of [insert proper subject here]. Offer to guide visitors to relevant pages or provide them with more information.
53 + - If a visitor asks for a purchase link or further information, provide them with this link: [Insert Purchase Link Here]. Always ensure that the link is relevant and directly related to the website\'s offerings.
54 + - Keep your responses short, concise, and to the point. Provide clear and direct answers suitable for a chatbot interaction.
55 + - If you reference specific content, provide a hyperlink to the relevant page using hypertext. Avoid including links that do not directly relate to the content or answer the visitor\'s query.
56 + - Provide answers based on the knowledge available to you. If you do not have an answer to a specific question, let the visitor know that you don’t have the information and suggest where they might find it or offer to help with something else.',
57 + 'model' => 'gpt-3.5-turbo',
58 + 'rate_limit' => '100',
59 + 'rate_limit_message' => 'Rate limit exceeded. Please try again later.',
60 + 'top_bar_title' => 'MxChat',
61 + 'intro_message' => 'Hello! How can I assist you today?',
62 + 'append_to_body' => 'on',
63 + 'close_button_color' => '#fff',
64 + 'chatbot_bg_color' => '#fff',
65 + 'user_message_bg_color' => '#fff',
66 + 'user_message_font_color' => '#212121',
67 + 'bot_message_bg_color' => '#212121',
68 + 'bot_message_font_color' => '#fff',
69 + 'top_bar_bg_color' => '#212121',
70 + 'send_button_font_color' => '#212121',
71 + 'chat_input_font_color' => '#212121',
72 + 'chatbot_background_color' => '#212121',
73 + 'icon_color' => '#fff',
74 + 'enable_woocommerce_integration' => '0',
75 + );
106 76
107 - // New fields for Loops Integration
108 - 'loops_api_key' => '',
109 - 'loops_mailing_list' => '',
110 - 'triggered_phrase_response' => esc_html__('Would you like to join our mailing list? Please provide your email below.', 'mxchat'),
111 - 'email_capture_response' => esc_html__('Thank you for providing your email! You\'ve been added to our list.', 'mxchat'),
112 - 'popular_question_1' => '',
113 - 'popular_question_2' => '',
114 - 'popular_question_3' => '',
115 - 'pdf_intent_trigger_text' => esc_html__("Please provide the URL to the PDF you'd like to discuss.", 'mxchat'),
116 - 'pdf_intent_success_text' => esc_html__("I've processed the PDF. What questions do you have about it?", 'mxchat'),
117 - 'pdf_intent_error_text' => esc_html__("Sorry, I couldn't process the PDF. Please ensure it's a valid file.", 'mxchat'),
118 - 'pdf_max_pages' => 69,
119 -
120 - // Live Agent Integration
121 - 'live_agent_webhook_url' => '',
122 - 'live_agent_secret_key' => '',
123 - 'live_agent_bot_token' => '',
124 - 'live_agent_message_bg_color' => esc_html__('#ffffff', 'mxchat'),
125 - 'live_agent_message_font_color' => esc_html__('#333333', 'mxchat'),
126 - 'chat_toolbar_toggle' => esc_html__('off', 'mxchat'),
127 - 'mode_indicator_bg_color' => esc_html__('#767676', 'mxchat'),
128 - 'mode_indicator_font_color' => esc_html__('#ffffff', 'mxchat'),
129 - 'toolbar_icon_color' => esc_html__('#212121', 'mxchat'),
130 - );
131 -
132 -
77 +
133 78 // Merge existing options with defaults
134 79 $existing_options = get_option('mxchat_options', array());
135 80 $merged_options = wp_parse_args($existing_options, $default_options);
136 -
81 +
137 82 // Update the options if they have changed
138 83 if ($existing_options !== $merged_options) {
139 84 update_option('mxchat_options', $merged_options);
140 85 }
141 -
142 - // Add default limits for each role
143 - $roles = wp_roles()->get_names();
144 - foreach ($roles as $role_id => $role_name) {
145 - $default_options['role_rate_limits'][$role_id] = esc_html__('100', 'mxchat');
146 - }
147 -
148 - return $default_options;
149 -
86 +
150 87 // Update the $this->options property
151 88 $this->options = $merged_options;
152 89 }
153 90
154 -
155 -
156 -public function mxchat_add_plugin_page() {
157 - // Main menu page
158 - add_menu_page(
159 - esc_html__('MxChat Settings', 'mxchat'),
160 - esc_html__('MxChat', 'mxchat'),
161 - 'manage_options',
162 - 'mxchat-max',
163 - array($this, 'mxchat_create_admin_page'),
164 - 'dashicons-testimonial',
165 - 6
166 - );
167 -
168 - // Submenu page for Knowledge
169 - add_submenu_page(
170 - 'mxchat-max',
171 - esc_html__('Prompts', 'mxchat'),
172 - esc_html__('Knowledge', 'mxchat'),
173 - 'manage_options',
174 - 'mxchat-prompts',
175 - array($this, 'mxchat_create_prompts_page')
176 - );
177 -
178 - add_submenu_page(
179 - 'mxchat-max',
180 - esc_html__('Chat Transcripts', 'mxchat'),
181 - esc_html__('Transcripts', 'mxchat'),
182 - 'manage_options',
183 - 'mxchat-transcripts',
184 - array($this, 'mxchat_create_transcripts_page')
185 - );
186 -
187 - add_submenu_page(
188 - 'mxchat-max',
189 - esc_html__('MxChat Intents', 'mxchat'),
190 - esc_html__('Intents', 'mxchat'),
191 - 'manage_options',
192 - 'mxchat-intents',
193 - array($this, 'mxchat_intents_page_html')
194 - );
195 -
91 + public function mxchat_add_plugin_page() {
92 + // Main menu page
93 + add_menu_page(
94 + 'MxChat Settings',
95 + 'MxChat',
96 + 'manage_options',
97 + 'mxchat-max',
98 + array($this, 'mxchat_create_admin_page'),
99 + 'dashicons-testimonial',
100 + 6
101 + );
102 +
103 + // Submenu page for Knowledge
196 104 add_submenu_page(
197 105 'mxchat-max',
198 - esc_html__('Add Ons', 'mxchat'),
199 - esc_html__('Add Ons', 'mxchat'),
106 + 'Prompts',
107 + 'Knowledge',
200 108 'manage_options',
201 - 'mxchat-addons',
202 - array($this, 'mxchat_create_addons_page')
109 + 'mxchat-prompts',
110 + array($this, 'mxchat_create_prompts_page')
203 111 );
112 +
113 + // Submenu page for Chat Transcripts
114 + add_submenu_page(
115 + 'mxchat-max', // Corrected parent slug to match the main menu
116 + 'Chat Transcripts',
117 + 'Transcripts',
118 + 'manage_options',
119 + 'mxchat-transcripts',
120 + array($this, 'mxchat_create_transcripts_page') // Prefixed function name with mxchat_
121 + );
122 +
123 + // Submenu page for Activation Key
124 + add_submenu_page(
125 + 'mxchat-max',
126 + 'Pro Upgrade',
127 + 'Pro Upgrade',
128 + 'manage_options',
129 + 'mxchat-activation',
130 + array($this, 'mxchat_create_activation_page')
131 + );
132 + }
204 133
205 - // Submenu page for Activation Key
206 - add_submenu_page(
207 - 'mxchat-max',
208 - esc_html__('Pro Upgrade', 'mxchat'),
209 - esc_html__('Pro Upgrade', 'mxchat'),
210 - 'manage_options',
211 - 'mxchat-activation',
212 - array($this, 'mxchat_create_activation_page')
213 - );
214 -}
215 134
216 -public function mxchat_create_addons_page() {
217 - require_once plugin_dir_path(__FILE__) . 'class-mxchat-addons.php';
218 - $addons_page = new MxChat_Addons();
219 - $addons_page->render_page();
220 -}
135 +public function mxchat_handle_content_submission() {
136 + // Check if the form was submitted and the user has sufficient permissions
137 + if (!isset($_POST['submit_content']) || !current_user_can('manage_options')) {
138 + return;
139 + }
221 140
222 -public function mxchat_save_setting_callback() {
223 - check_ajax_referer('mxchat_save_setting_nonce');
224 - if (!current_user_can('manage_options')) {
225 - wp_send_json_error(['message' => esc_html__('Unauthorized', 'mxchat')]);
141 + // Verify the nonce field for security
142 + $nonce = isset($_POST['mxchat_submit_content_nonce']) ? sanitize_text_field(wp_unslash($_POST['mxchat_submit_content_nonce'])) : '';
143 + if (!wp_verify_nonce($nonce, 'mxchat_submit_content_action')) {
144 + wp_die('Nonce verification failed.');
226 145 }
227 - $name = isset($_POST['name']) ? $_POST['name'] : '';
228 - // Strip slashes from the value before saving
229 - $value = isset($_POST['value']) ? stripslashes($_POST['value']) : '';
230 - if (empty($name)) {
231 - wp_send_json_error(['message' => esc_html__('Invalid field name', 'mxchat')]);
232 - }
233 - // Load the full options array
234 - $options = get_option('mxchat_options', []);
235 - // Handle special cases
236 - switch ($name) {
237 - case 'additional_popular_questions':
238 - $questions = json_decode($value, true); // No need for stripslashes here
239 - if (is_array($questions)) {
240 - $options[$name] = $questions;
241 - // Also update old option for backwards compatibility
242 - update_option('additional_popular_questions', $questions);
243 - }
244 - break;
245 - case 'user_message_bg_color':
246 - case 'user_message_font_color':
247 - case 'bot_message_bg_color':
248 - case 'bot_message_font_color':
249 - case 'top_bar_bg_color':
250 - case 'send_button_font_color':
251 - case 'chatbot_background_color':
252 - case 'icon_color':
253 - case 'chat_input_font_color':
254 - case 'live_agent_message_bg_color':
255 - case 'live_agent_message_font_color':
256 - case 'mode_indicator_bg_color':
257 - case 'mode_indicator_font_color':
258 - case 'toolbar_icon_color':
259 - // Store color values directly
260 - $options[$name] = $value;
261 - break;
262 - case 'live_agent_status':
263 - // Set the new value
264 - $options[$name] = ($value === 'on') ? 'on' : 'off';
265 - break;
266 - case 'enable_woocommerce_integration':
267 - // Handle values that used to be 1/0
268 - $options[$name] = ($value === 'on' || $value === '1') ? 'on' : 'off';
269 - break;
270 - default:
271 - // Handle role rate limits
272 - if (strpos($name, 'mxchat_options[role_rate_limits]') !== false) {
273 - // Extract role ID from the name
274 - preg_match('/\[role_rate_limits\]\[(.*?)\]/', $name, $matches);
275 - if (isset($matches[1])) {
276 - $role_id = $matches[1];
277 - // Initialize role_rate_limits if it doesn't exist
278 - if (!isset($options['role_rate_limits'])) {
279 - $options['role_rate_limits'] = [];
280 - }
281 - // Update the specific role's rate limit
282 - $options['role_rate_limits'][$role_id] = sanitize_text_field($value);
283 - break;
284 - }
285 - }
286 - // Handle toggles
287 - if (strpos($name, 'toggle') !== false || in_array($name, [
288 - 'chat_persistence_toggle',
289 - 'privacy_toggle',
290 - 'complianz_toggle',
291 - 'chat_toolbar_toggle' // Removed live_agent_status from here
292 - ])) {
293 - $options[$name] = ($value === 'on') ? 'on' : 'off';
294 - } else {
295 - // Store all other values directly
296 - $options[$name] = $value;
297 - }
298 - break;
299 - }
300 - // Save all updates
301 - $updated = update_option('mxchat_options', $options);
302 - // Handle backwards compatibility for certain fields
303 - $legacy_fields = ['brave_api_key', 'brave_image_count', 'brave_safe_search', 'brave_news_count',
304 - 'brave_country', 'brave_language', 'similarity_threshold'];
305 - if (in_array($name, $legacy_fields)) {
306 - // Also update the individual option for backwards compatibility
307 - update_option($name, $value);
308 - }
309 - if ($updated) {
310 - wp_send_json_success(['message' => esc_html__('Setting saved', 'mxchat')]);
311 - } else {
312 - wp_send_json_error(['message' => esc_html__('Update failed or no changes', 'mxchat')]);
313 - }
314 -}
315 146
316 -/**
317 - * Handles AJAX auto-save for prompts and auto-sync settings.
318 - */
319 -public function mxchat_save_prompts_setting_callback() {
320 - // Check the correct nonce for this action.
321 - check_ajax_referer( 'mxchat_prompts_setting_nonce', '_ajax_nonce' );
147 + // Sanitize the content input
148 + $article_content = sanitize_textarea_field($_POST['article_content']);
322 149
323 - if ( ! current_user_can( 'manage_options' ) ) {
324 - wp_send_json_error( [ 'message' => esc_html__( 'Unauthorized', 'mxchat' ) ] );
325 - }
150 + // Generate the embedding vector for the content
151 + $embedding_vector = $this->mxchat_generate_embedding($article_content);
326 152
327 - $name = isset( $_POST['name'] ) ? sanitize_text_field( wp_unslash( $_POST['name'] ) ) : '';
328 - $value = isset( $_POST['value'] ) ? sanitize_text_field( wp_unslash( $_POST['value'] ) ) : '';
153 + global $wpdb;
154 + $table_name = $wpdb->prefix . 'mxchat_system_prompt_content';
329 155
330 - if ( empty( $name ) ) {
331 - wp_send_json_error( [ 'message' => esc_html__( 'Invalid field name', 'mxchat' ) ] );
156 + // Check if the 'source_url' column exists in the table and add it if it doesn't
157 + if ($wpdb->get_var($wpdb->prepare("SHOW COLUMNS FROM {$table_name} LIKE %s", 'source_url')) != 'source_url') {
158 + // Use wpdb::query and a prepared statement to avoid SQL injection
159 + $wpdb->query($wpdb->prepare("ALTER TABLE {$table_name} ADD source_url VARCHAR(255) DEFAULT ''"));
332 160 }
333 161
334 - // Handle standalone auto-sync settings.
335 - if ( in_array( $name, [ 'mxchat_auto_sync_posts', 'mxchat_auto_sync_pages' ], true ) ) {
336 - // Convert checkbox value to "1" if checked, "0" if not.
337 - $value = ( $value === 'on' ) ? '1' : '0';
338 - update_option( $name, $value );
339 - wp_send_json_success( [ 'message' => esc_html__( 'Setting saved', 'mxchat' ) ] );
340 - }
162 + if (is_array($embedding_vector)) {
163 + // Serialize the embedding vector before storing it
164 + $embedding_vector_serialized = serialize($embedding_vector);
341 165
342 - // Handle fields stored in the 'mxchat_prompts_options' array.
343 -// Handle fields stored in the 'mxchat_prompts_options' array.
344 -if ( false !== strpos( $name, 'mxchat_prompts_options[' ) ) {
345 - // Extract the key name using regex.
346 - if ( preg_match( '/mxchat_prompts_options\[(.*?)\]/', $name, $matches ) && ! empty( $matches[1] ) ) {
347 - $key = sanitize_text_field( $matches[1] );
348 - $options = get_option( 'mxchat_prompts_options', [] );
166 + // Insert the content and embedding vector into the database, using a prepared statement
167 + $inserted = $wpdb->insert(
168 + $table_name,
169 + array(
170 + 'article_content' => $article_content,
171 + 'embedding_vector' => $embedding_vector_serialized,
172 + 'source_url' => '', // Empty string as a placeholder for now, or pass a valid URL if applicable
173 + ),
174 + array(
175 + '%s', // Format for article_content (string)
176 + '%s', // Format for embedding_vector (serialized string)
177 + '%s', // Format for source_url (string)
178 + )
179 + );
349 180
350 - // Remove Pinecone-specific settings from the main plugin handling.
351 - if ( 'mxchat_use_pinecone' === $key ) {
352 - // Optionally, you could simply ignore this field or set a default value.
353 - // For example, ensure it's always 0 or remove it entirely:
354 - // $options[ $key ] = '0';
355 - // Or, if you prefer, just return an error so that the main plugin doesn't handle it:
356 - wp_send_json_error( [ 'message' => esc_html__( 'Pinecone settings are now handled in the add-on.', 'mxchat' ) ] );
181 + if ($inserted === false) {
182 + error_log('Error inserting content: ' . $wpdb->last_error);
183 + set_transient('mxchat_admin_notice', 'Error inserting content into the database. Please try again.', 30);
357 184 } else {
358 - // For all other fields, use the existing logic.
359 - $options[ $key ] = ( $value === 'on' || $value === '1' ) ? '1' : $value;
185 + set_transient('mxchat_admin_notice', 'Content successfully submitted!', 30);
360 186 }
361 - update_option( 'mxchat_prompts_options', $options );
362 - wp_send_json_success( [ 'message' => esc_html__( 'Setting saved', 'mxchat' ) ] );
187 + } else {
188 + error_log('Embedding generation failed for article content: ' . $article_content);
189 + set_transient('mxchat_admin_notice', 'Embedding generation failed. Please ensure your API key is correct and try again.', 30);
363 190 }
364 -}
365 191
366 -
367 - wp_send_json_error( [ 'message' => esc_html__( 'Field not recognized', 'mxchat' ) ] );
192 + // Redirect after setting the transient
193 + wp_safe_redirect(esc_url(admin_url('admin.php?page=mxchat-prompts')));
194 + exit;
368 195 }
369 196
370 197 public function mxchat_display_admin_notice() {
371 - // Success notice
372 - if ($message = get_transient('mxchat_admin_notice_success')) {
373 - ?>
374 - <div class="notice notice-success is-dismissible">
375 - <p><?php echo esc_html($message); ?></p>
376 - <button type="button" class="notice-dismiss"><span class="screen-reader-text"><?php echo esc_html__('Dismiss this notice.', 'mxchat'); ?></span></button>
377 - </div>
378 - <?php
379 - delete_transient('mxchat_admin_notice_success'); // Clear the transient after displaying
380 - }
198 + // Get the message from the transient
199 + $message = get_transient('mxchat_admin_notice');
200 +
201 + if ($message) {
202 + echo '<div class="notice notice-error is-dismissible">';
203 + echo '<p>' . esc_html($message) . '</p>';
204 + echo '</div>';
381 205
382 - // Error notice
383 - if ($message = get_transient('mxchat_admin_notice_error')) {
384 - ?>
385 - <div class="notice notice-error is-dismissible">
386 - <p><?php echo esc_html($message); ?></p>
387 - <button type="button" class="notice-dismiss"><span class="screen-reader-text"><?php echo esc_html__('Dismiss this notice.', 'mxchat'); ?></span></button>
388 - </div>
389 - <?php
390 - delete_transient('mxchat_admin_notice_error'); // Clear the transient after displaying
206 + // Delete the transient after displaying the message
207 + delete_transient('mxchat_admin_notice');
391 208 }
392 209 }
393 210
394 211
212 + public function mxchat_handle_delete_prompt() {
213 + // Sanitize and validate nonce using wp_unslash and sanitize_text_field
214 + $nonce = isset($_GET['_wpnonce']) ? sanitize_text_field(wp_unslash($_GET['_wpnonce'])) : '';
215 + if (empty($nonce) || !wp_verify_nonce($nonce, 'mxchat_delete_prompt_nonce')) {
216 + wp_die('Nonce verification failed.');
217 + }
395 218
219 + // Check user permissions
220 + if (!current_user_can('manage_options')) {
221 + wp_die('You do not have sufficient permissions to delete prompts.');
222 + }
396 223
224 + // Sanitize and validate the 'id' parameter
225 + $id = isset($_GET['id']) ? intval($_GET['id']) : 0;
226 + if ($id <= 0) {
227 + wp_die('Invalid prompt ID.');
228 + }
397 229
230 + global $wpdb;
231 + $table_name = $wpdb->prefix . 'mxchat_system_prompt_content';
232 +
233 + // Clear relevant cache before deletion
234 + $cache_key = 'prompt_' . $id;
235 + wp_cache_delete($cache_key, 'mxchat_prompts');
236 +
237 + // Delete the record using a prepared statement
238 + $deleted = $wpdb->delete($table_name, array('id' => $id), array('%d'));
239 +
240 + if ($deleted !== false) {
241 + // Optionally, clear a general cache if you have one
242 + wp_cache_delete('all_prompts', 'mxchat_prompts');
243 + }
244 +
245 + // Redirect to the prompts page with a success message
246 + $redirect_url = add_query_arg(array(
247 + 'page' => 'mxchat-prompts',
248 + 'deleted' => 'true'
249 + ), admin_url('admin.php'));
250 +
251 + wp_safe_redirect($redirect_url);
252 + exit;
253 + }
254 +
255 +
398 256 public function mxchat_create_admin_page() {
399 -
400 257 ?>
401 258 <div class="wrap mxchat-admin">
402 - <?php if (!$this->is_activated): ?>
403 259 <div class="mxchat-pro-banner">
404 - <p>
405 - <?php echo esc_html__('For a limited time, get lifetime access and save $20 on MxChat Pro!', 'mxchat'); ?>
406 - <a href="https://mxchat.ai/" target="_blank"><?php echo esc_html__('Upgrade to Pro today', 'mxchat'); ?></a>
407 - </p>
260 + <p>
261 + Want even more features such as a fully customizable theme, WooCommerce integration, dedicated support, and much more?
262 + <a href="https://mxchat.ai/" target="_blank">Upgrade to MxChat Pro today and get a special launch lifetime license for only $49.97!</a>
263 + </p>
408 264 </div>
409 - <?php endif; ?>
410 -
411 - <div class="mxchat-agents-banner">
412 - <p>
413 - <strong><?php echo esc_html__('The MxChat Add-Ons Platform', 'mxchat'); ?></strong><?php echo esc_html__(' is here! Pro users get unlimited access to our growing collection of powerful add-ons. ', 'mxchat'); ?><a href="<?php echo admin_url('admin.php?page=mxchat-addons'); ?>"><?php echo esc_html__('Explore all add-ons', 'mxchat'); ?></a><?php echo esc_html__(' including Forms Builder, Theme Customizer, Content Moderation, and more – all included with your lifetime Pro license!', 'mxchat'); ?>
414 - </p>
415 - </div>
416 -
417 - <h2 class="mxchat-nav-tab-wrapper">
418 - <a href="#chatbot" class="mxchat-nav-tab mxchat-nav-tab-active" data-tab="chatbot"><?php echo esc_html__('Chatbot', 'mxchat'); ?></a>
419 - <a href="#embed" class="mxchat-nav-tab" data-tab="embed"><?php echo esc_html__('Integrations', 'mxchat'); ?></a>
420 - <a href="#general" class="mxchat-nav-tab" data-tab="general"><?php echo esc_html__('FAQ', 'mxchat'); ?></a>
265 + <h2 class="admin-title">Mx<span class="admin-emphasis">Chat</span></h2>
266 + <h2 class="nav-tab-wrapper">
267 + <a href="#chatbot" class="nav-tab nav-tab-active" data-tab="chatbot">Chatbot</a>
268 + <a href="#embed" class="nav-tab" data-tab="embed">Embed</a>
269 + <a href="#theme" class="nav-tab" data-tab="theme">Theme</a>
270 + <a href="#general" class="nav-tab" data-tab="general">General</a>
421 271 </h2>
422 -
423 - <div id="chatbot" class="mxchat-tab-content active">
424 - <div class="mxchat-autosave-section">
272 + <form method="post" action="options.php">
273 + <?php
274 + settings_fields('mxchat_option_group');
275 + ?>
276 + <div id="chatbot" class="tab-content active">
425 277 <?php do_settings_sections('mxchat-chatbot'); ?>
426 278 </div>
427 - </div>
428 -
429 - <div id="embed" class="mxchat-tab-content">
430 - <div class="mxchat-autosave-section">
431 -
432 - <div class="mxchat-settings-section">
433 - <h2><?php echo esc_html__('Loops Settings', 'mxchat'); ?></h2>
434 - <table class="form-table">
435 - <?php do_settings_fields('mxchat-embed', 'mxchat_loops_section'); ?>
436 - </table>
437 - </div>
438 -
439 - <div class="section-divider"></div>
440 -
441 - <div class="mxchat-settings-section">
442 - <h2><?php echo esc_html__('Brave Search Settings', 'mxchat'); ?></h2>
443 - <table class="form-table">
444 - <?php do_settings_fields('mxchat-embed', 'mxchat_brave_section'); ?>
445 - </table>
446 - </div>
447 -
448 - <div class="section-divider"></div>
449 -
450 - <div class="mxchat-settings-section">
451 - <h2><?php echo esc_html__('Toolbar Settings & Intents', 'mxchat'); ?></h2>
452 - <table class="form-table">
453 - <?php do_settings_fields('mxchat-embed', 'mxchat_pdf_intent_section'); ?>
454 - </table>
455 - </div>
456 -
457 - <div class="section-divider"></div>
458 -
459 - <!-- Live Agent Settings Section -->
460 - <div class="mxchat-settings-section">
461 - <h2><?php echo esc_html__('Live Agent Settings', 'mxchat'); ?></h2>
462 - <p><?php echo esc_html__('Visit our', 'mxchat'); ?> <a href="https://mxchat.ai/documentation/#slack_integration" target="_blank"><?php echo esc_html__('documentation page', 'mxchat'); ?></a> <?php echo esc_html__('to set up live agent transfer via Slack.', 'mxchat'); ?></p>
463 - <table class="form-table">
464 - <?php do_settings_fields('mxchat-embed', 'mxchat_live_agent_section'); ?>
465 - </table>
466 - </div>
279 + <div id="embed" class="tab-content">
280 + <?php do_settings_sections('mxchat-embed'); ?>
467 281 </div>
468 - </div>
469 -
470 -
471 - <div id="general" class="mxchat-tab-content">
472 - <?php do_settings_sections('mxchat-general'); ?>
473 - <p>
474 - <?php echo esc_html__('If you’re having trouble with setup or getting the responses you need, we encourage you to review our', 'mxchat'); ?>
475 - <a href="https://mxchat.ai/documentation/" target="_blank" rel="noopener noreferrer"><?php echo esc_html__('documentation', 'mxchat'); ?></a> <?php echo esc_html__('or', 'mxchat'); ?>
476 - <a href="https://wordpress.org/support/plugin/mxchat-basic/" target="_blank" rel="noopener noreferrer"><?php echo esc_html__('create a support ticket', 'mxchat'); ?></a>.
477 - </p>
478 - <p>
479 - <?php echo esc_html__('If you like our plugin, please consider', 'mxchat'); ?> <a href="https://wordpress.org/plugins/mxchat-basic/#reviews" target="_blank" rel="noopener noreferrer"><?php echo esc_html__('leaving us a review', 'mxchat'); ?></a>.
480 - </p>
481 -
482 - <div class="faq-item">
483 - <h3><?php echo esc_html__('How does the Claude API integration work?', 'mxchat'); ?></h3>
484 - <p>
485 - <?php echo esc_html__('The Claude API, provided by Anthropic, allows for intelligent, context-aware chatbot responses in MxChat. To use it, you will need both an OpenAI API key and a Claude API key. This is necessary because the system utilizes OpenAI for vector embedding in the Retrieval-Augmented Generation (RAG) process, as Claude does not currently offer an embedding API.', 'mxchat'); ?>
486 - </p>
487 - <p>
488 - <?php echo esc_html__('When using the Claude API, your custom content is sent to Claude for generating responses, while the embeddings are processed through OpenAI. This ensures your chatbot provides accurate and engaging responses while maintaining knowledge relevant to your website.', 'mxchat'); ?>
489 - </p>
490 - <p>
491 - <?php echo esc_html__('You can obtain your Claude API key by signing up on the', 'mxchat'); ?> <a href="https://www.anthropic.com/api" target="_blank" rel="noopener"><?php echo esc_html__('Anthropic API page', 'mxchat'); ?></a>.
492 - </p>
282 + <div id="theme" class="tab-content">
283 + <?php do_settings_sections('mxchat-theme'); ?>
493 284 </div>
494 -
495 - <div class="faq-item">
496 - <h3><?php echo esc_html__('How does the X.AI API integration work?', 'mxchat'); ?></h3>
497 - <p>
498 - <?php echo esc_html__('The X.AI API, released on 10.21.24, is currently in beta. To use it, you will need both an OpenAI API key and an X.AI API key. This is because OpenAI handles vector embeddings in the Retrieval-Augmented Generation (RAG) process, as X.AI does not yet provide an embedding API.', 'mxchat'); ?>
499 - </p>
500 - <p>
501 - <?php echo esc_html__('Custom content is sent to the X.AI API for generating responses, while OpenAI processes the embeddings. This allows the chatbot to provide advanced responses while maintaining context from your website. You can get your X.AI API key from the', 'mxchat'); ?> <a href="https://docs.x.ai/docs" target="_blank" rel="noopener"><?php echo esc_html__('X.AI API documentation', 'mxchat'); ?></a>.
502 - </p>
285 + <div id="general" class="tab-content">
286 + <?php do_settings_sections('mxchat-general'); ?>
287 +
288 + <div class="mxchat-general-notes">
289 + <h3>Important Notes</h3>
290 + <p>
291 + You can add the chatbot to your site using the <code>[mxchat_chatbot floating="yes"]</code> or <code>[mxchat_chatbot floating="no"]</code> shortcode. Additionally, you can automatically append the chatbot to your site’s body element from the settings page.
292 + </p>
293 + <p>
294 + Please note that you must have an OpenAI API key to use the chatbot. You can obtain an API key from the <a href="https://platform.openai.com/signup" target="_blank">OpenAI website</a>. It's easy to sign up, and you'll need to add credits to your account before using the chatbot. Generally, as little as $5 in credits is sufficient to get started.
295 + </p>
296 + </div>
503 297 </div>
504 -
505 - <div class="faq-item">
506 - <h3><?php echo esc_html__('Do I need an OpenAI API key to use the chatbot?', 'mxchat'); ?></h3>
507 - <p>
508 - <?php echo esc_html__('Yes, you will need an OpenAI API key to power the chatbot. You can obtain an API key by signing up on the', 'mxchat'); ?> <a href="https://platform.openai.com/signup" target="_blank" rel="noopener"><?php echo esc_html__('OpenAI platform', 'mxchat'); ?></a>. <?php echo esc_html__('After signing up, you must add credits to your account—typically, $5 in credits is sufficient to get started.', 'mxchat'); ?>
509 - </p>
510 - <p>
511 - <?php echo esc_html__('Once you have your API key, simply enter it in the chatbot\'s settings to enable functionality. The chatbot relies on OpenAI’s models for generating responses, so having sufficient credits in your OpenAI account is essential for smooth operation.', 'mxchat'); ?>
512 - </p>
513 - </div>
514 -
515 - <div class="faq-item">
516 - <h3><?php echo esc_html__('How do I add the chatbot to my site?', 'mxchat'); ?></h3>
517 - <p>
518 - <?php echo esc_html__('You can add the chatbot using the shortcode', 'mxchat'); ?> <code>[mxchat_chatbot floating="yes"]</code> <?php echo esc_html__('or', 'mxchat'); ?> <code>[mxchat_chatbot floating="no"]</code>. <?php echo esc_html__('For initial testing and styling, it\'s best to use the shortcode on a draft or non-public page. Once you’re ready to go live, enable the “Append Chat Widget to Body” option in the settings for site-wide integration (recommended) or add shortcode to the footer.', 'mxchat'); ?>
519 - </p>
520 - </div>
521 -
522 - <div class="faq-item">
523 - <h3><?php echo esc_html__('How does the chatbot use my content to generate responses?', 'mxchat'); ?></h3>
524 - <p>
525 - <?php echo esc_html__('The chatbot uses AI and vector embeddings to connect users with relevant information. When you submit content, it converts it into a mathematical format. When a user asks a question, the bot matches it to your stored content and generates a response based on relevance. For example, submitting "Our phone number is 910-123-4567" allows the bot to retrieve this information when asked about contact details. To ensure related information is provided together, submit it in one entry.', 'mxchat'); ?>
526 - </p>
527 - </div>
528 -
529 - <div class="faq-item">
530 - <h3><?php echo esc_html__('Why does the chatbot sometimes make up links or information?', 'mxchat'); ?></h3>
531 - <p>
532 - <?php echo esc_html__('Occasionally, the chatbot may generate inaccurate links or information, known as "hallucinations." To minimize this, you can add system instructions to guide its behavior. For example, include an instruction like: "Only provide links you directly have access to or retrieve from the knowledge base. Do not make up links or information that you do not have direct access to." This helps the bot stay aligned with your content.', 'mxchat'); ?>
533 - </p>
534 - </div>
535 -
536 - <div class="faq-item">
537 - <h3><?php echo esc_html__('How do intents work in MxChat?', 'mxchat'); ?></h3>
538 - <p>
539 - <?php echo esc_html__('Intents allow MxChat to recognize user requests and trigger specific actions, such as capturing emails or displaying product information. This helps provide a more interactive and responsive experience. For a detailed explanation of each intent, please refer to our', 'mxchat'); ?> <a href="https://mxchat.ai/documentation/#intents" target="_blank" rel="noopener noreferrer"><?php echo esc_html__('Intents Documentation', 'mxchat'); ?></a>.
540 - </p>
541 - </div>
542 -
543 - <div class="faq-item">
544 - <h3><?php echo esc_html__('How does the Complianz integration work?', 'mxchat'); ?></h3>
545 - <p>
546 - <?php echo esc_html__('The Pro version offers direct integration with the Complianz GDPR plugin, making it easy to stay compliant with GDPR. If Complianz is enabled on your website, users must accept consent before the chatbot widget appears. The chatbot will only display once the user has accepted, ensuring compliance with data privacy regulations.', 'mxchat'); ?>
547 - </p>
548 - </div>
549 -
550 - <div class="faq-item">
551 - <h3><?php echo esc_html__('How does the WooCommerce integration work?', 'mxchat'); ?></h3>
552 - <p>
553 - <?php echo esc_html__('With WooCommerce integration, the chatbot automatically embeds new products and updates existing ones. For already-published products, you can click update or submit the product sitemap. The “Order History Access” setting allows the bot to access users\' order history (requires login) and assist with order inquiries. To enable the “Add to Cart” feature, add this system instruction: “After discussing a product, ask if the user wants to add it to their cart. The user must say \'Add to cart\' exactly.” Currently, this feature supports English only, with more languages coming soon.', 'mxchat'); ?>
554 - </p>
555 - </div>
556 -
557 - <div class="faq-item">
558 - <h3><?php echo esc_html__('Why isn\'t my chatbot responding as expected?', 'mxchat'); ?></h3>
559 - <p>
560 - <?php echo esc_html__('AI chatbots can sometimes behave in unexpected ways, especially if you\'re new to configuring AI for specific tasks. We\'re committed to helping you get the most out of your chatbot experience. While we’re working on comprehensive guides and video tutorials, our team is here to assist you directly. If your chatbot isn\'t delivering the responses you need, please don’t hesitate to', 'mxchat'); ?> <a href="https://mxchat.ai/contact/" target="_blank" rel="noopener noreferrer"><?php echo esc_html__('contact us', 'mxchat'); ?></a> <?php echo esc_html__('for personalized support.', 'mxchat'); ?>
561 - </p>
562 - <p>
563 - <?php echo esc_html__('We’re dedicated to your success and ready to guide you in aligning the AI\'s behavior to meet your goals.', 'mxchat'); ?>
564 - </p>
565 - </div>
566 -
567 - <div class="faq-item">
568 - <h3><?php echo esc_html__('What is Loops, and how do I get an API key?', 'mxchat'); ?></h3>
569 - <p>
570 - <?php echo esc_html__('Loops is a powerful SaaS email service that helps you automate and enhance your email marketing campaigns, making it easy to reach and engage with your audience. To integrate Loops with MxChat, you’ll need an API key from Loops. You can obtain this key by logging into your Loops account and navigating to the API settings. Visit the', 'mxchat'); ?> <a href="https://loops.so" target="_blank" rel="noopener noreferrer"><?php echo esc_html__('Loops website', 'mxchat'); ?></a> <?php echo esc_html__('to get started or to sign up for an account.', 'mxchat'); ?>
571 - </p>
572 - </div>
573 -
574 - </div>
298 + <?php submit_button(); ?>
299 + </form>
575 300 </div>
576 301 <?php
577 302 }
578 303
579 -
580 -public function mxchat_create_transcripts_page() {
581 - global $wpdb;
582 - $table_name = $wpdb->prefix . 'mxchat_chat_transcripts';
583 -
584 - // Get basic stats
585 - $total_chats = $wpdb->get_var("SELECT COUNT(DISTINCT session_id) FROM $table_name");
586 - $total_messages = $wpdb->get_var("SELECT COUNT(*) FROM $table_name");
587 -
588 - // Count unique users with detailed breakdown
589 - $total_users = $wpdb->get_var("
590 - SELECT COUNT(DISTINCT
591 - CASE
592 - WHEN user_email != '' AND user_email IS NOT NULL THEN user_email
593 - WHEN user_id != 0 THEN CONCAT('user_', user_id)
594 - WHEN user_identifier NOT LIKE 'Tech-Savvy User'
595 - AND user_identifier NOT LIKE 'Detail-Oriented User'
596 - AND user_identifier NOT LIKE 'Language Learner'
597 - AND user_identifier NOT LIKE 'Casual Browser'
598 - AND user_identifier NOT LIKE 'Policy Enforcer'
599 - AND user_identifier NOT LIKE 'Researcher'
600 - AND user_identifier NOT LIKE 'Loyalty Member'
601 - AND user_identifier NOT LIKE 'Gift Buyer'
602 - AND user_identifier NOT LIKE 'Parent or Caregiver'
603 - THEN user_identifier
604 - ELSE session_id
605 - END
606 - )
607 - FROM $table_name
608 - WHERE role != 'assistant'
609 - ");
610 -
611 - // Get user type breakdown
612 - $registered_users = $wpdb->get_var("
613 - SELECT COUNT(DISTINCT user_email)
614 - FROM $table_name
615 - WHERE user_email != '' AND user_email IS NOT NULL
616 - ");
617 -
618 - $guest_users = $wpdb->get_var("
619 - SELECT COUNT(DISTINCT user_identifier)
620 - FROM $table_name
621 - WHERE (user_email = '' OR user_email IS NULL)
622 - AND role != 'assistant'
623 - AND user_identifier NOT LIKE 'Tech-Savvy User'
624 - AND user_identifier NOT LIKE 'Detail-Oriented User'
625 - AND user_identifier NOT LIKE 'Language Learner'
626 - AND user_identifier NOT LIKE 'Casual Browser'
627 - AND user_identifier NOT LIKE 'Policy Enforcer'
628 - AND user_identifier NOT LIKE 'Researcher'
629 - AND user_identifier NOT LIKE 'Loyalty Member'
630 - AND user_identifier NOT LIKE 'Gift Buyer'
631 - AND user_identifier NOT LIKE 'Parent or Caregiver'
632 - ");
633 -
634 - // Get agent test messages count
635 - $agent_tests = $wpdb->get_var("
636 - SELECT COUNT(DISTINCT session_id)
637 - FROM $table_name
638 - WHERE user_identifier IN (
639 - 'Tech-Savvy User',
640 - 'Detail-Oriented User',
641 - 'Language Learner',
642 - 'Casual Browser',
643 - 'Policy Enforcer',
644 - 'Researcher',
645 - 'Loyalty Member',
646 - 'Gift Buyer',
647 - 'Parent or Caregiver'
648 - )
649 - ");
650 - ?>
651 - <div class="wrap mxchat-transcripts-wrapper">
652 - <!-- Hero Section -->
653 - <div class="mxchat-transcripts-hero">
654 - <h1 class="mxchat-main-title">
655 - Chat <span class="mxchat-gradient-text">Transcripts</span>
656 - </h1>
657 - <p class="mxchat-hero-subtitle">
658 - <?php esc_html_e('Review and manage your chatbot conversations with detailed message history.', 'mxchat'); ?>
659 - </p>
660 - </div>
661 - <div class="mxchat-content">
662 - <!-- Stats Cards -->
663 - <div class="mxchat-stats-grid">
664 - <div class="mxchat-stat-card">
665 - <div class="stat-icon">💬</div>
666 - <div class="stat-content">
667 - <span class="stat-value"><?php echo esc_html($total_chats); ?></span>
668 - <span class="stat-label"><?php esc_html_e('Total Chats', 'mxchat'); ?></span>
669 - </div>
670 - </div>
671 - <div class="mxchat-stat-card">
672 - <div class="stat-icon">📝</div>
673 - <div class="stat-content">
674 - <span class="stat-value"><?php echo esc_html($total_messages); ?></span>
675 - <span class="stat-label"><?php esc_html_e('Total Messages', 'mxchat'); ?></span>
676 - </div>
677 - </div>
678 - <div class="mxchat-stat-card">
679 - <div class="stat-icon">👥</div>
680 - <div class="stat-content">
681 - <span class="stat-value"><?php echo esc_html($total_users); ?></span>
682 - <span class="stat-label"><?php esc_html_e('Unique Users', 'mxchat'); ?></span>
683 - <span class="stat-sublabel">
684 - <?php
685 - echo sprintf(
686 - esc_html__('%d registered, %d guests, %d agent tests', 'mxchat'),
687 - $registered_users,
688 - $guest_users,
689 - $agent_tests
690 - );
691 - ?>
692 - </span>
693 - </div>
694 - </div>
695 - </div>
696 - <!-- Search and Filter Controls -->
697 - <div class="mxchat-controls-wrapper">
698 - <div class="mxchat-search-box">
699 - <input type="text" id="mxchat-search-transcripts"
700 - placeholder="<?php esc_attr_e('Search transcripts...', 'mxchat'); ?>"
701 - class="regular-text">
702 - </div>
304 + public function mxchat_create_transcripts_page() {
305 + ?>
306 + <div class="wrap mxchat-admin">
307 + <h2><?php esc_html_e('Chat Transcripts', 'mxchat'); ?></h2>
703 308 <form id="mxchat-delete-form" method="post">
704 309 <?php wp_nonce_field('mxchat_delete_chat_history', 'mxchat_delete_chat_nonce'); ?>
705 310 <div class="mxchat-controls">
706 - <button type="button" id="mxchat-export-transcripts" class="mxchat-action-button">
707 - <span class="dashicons dashicons-download"></span>
708 - <?php esc_html_e('Export All Chats', 'mxchat'); ?>
709 - </button>
710 - <button type="button" id="mxchat-select-all-transcripts" class="mxchat-select-button">
711 - <span class="dashicons dashicons-yes-alt"></span>
712 - <span class="button-text"><?php esc_html_e('Select All', 'mxchat'); ?></span>
713 - </button>
714 - <button type="submit" class="button delete-chats-button">
715 - <span class="dashicons dashicons-trash"></span>
716 - <?php esc_html_e('Delete Selected', 'mxchat'); ?>
717 - </button>
311 + <label for="mxchat-select-all-transcripts" class="mxchat-select-all-label">
312 + <input type="checkbox" id="mxchat-select-all-transcripts" /> <?php esc_html_e('Select All', 'mxchat'); ?>
313 + </label>
314 + <input type="submit" value="<?php esc_attr_e('Delete Selected', 'mxchat'); ?>" class="button button-primary delete-chats-button" />
718 315 </div>
316 + <div id="mxchat-transcripts">
317 + <!-- Transcripts will be loaded here -->
318 + </div>
719 319 </form>
720 320 </div>
721 - <!-- Transcripts Container -->
722 - <div id="mxchat-transcripts"></div>
723 - </div>
724 - </div>
725 - <?php
726 -}
321 + <?php
322 + }
727 323
728 -public function export_chat_transcripts() {
729 - if (!current_user_can('manage_options')) {
730 - wp_die(esc_html__('You do not have sufficient permissions to access this page.', 'mxchat'));
731 - }
732 324
733 - check_ajax_referer('mxchat_export_transcripts', 'security');
734 325
735 - global $wpdb;
736 - $table_name = $wpdb->prefix . 'mxchat_chat_transcripts';
737 326
738 - // Get all transcripts ordered by session and timestamp
739 - $results = $wpdb->get_results(
740 - "SELECT session_id, user_email, user_identifier, role, message, timestamp
741 - FROM {$table_name}
742 - ORDER BY session_id, timestamp ASC"
743 - );
327 + public function mxchat_create_prompts_page() {
328 + global $wpdb;
329 + $table_name = $wpdb->prefix . 'mxchat_system_prompt_content';
744 330
745 - if (empty($results)) {
746 - wp_send_json_error(array('message' => 'No transcripts found.'));
747 - wp_die();
748 - }
331 + // Verify the nonce before processing the request
332 + $nonce = isset($_GET['_wpnonce']) ? sanitize_text_field($_GET['_wpnonce']) : '';
749 333
750 - // Set headers for CSV download
751 - header('Content-Type: text/csv');
752 - header('Content-Disposition: attachment; filename="chat-transcripts-' . date('Y-m-d') . '.csv"');
753 - header('Pragma: no-cache');
754 - header('Expires: 0');
755 -
756 - // Create output stream
757 - $output = fopen('php://output', 'w');
758 -
759 - // Add UTF-8 BOM for proper Excel encoding
760 - fputs($output, "\xEF\xBB\xBF");
761 -
762 - // Add CSV headers
763 - fputcsv($output, array(
764 - 'Session ID',
765 - 'Email',
766 - 'User Identifier',
767 - 'Role',
768 - 'Message',
769 - 'Timestamp'
770 - ));
771 -
772 - // Add data rows
773 - foreach ($results as $row) {
774 - fputcsv($output, array(
775 - $row->session_id,
776 - $row->user_email,
777 - $row->user_identifier,
778 - $row->role,
779 - $row->message,
780 - $row->timestamp
781 - ));
782 - }
783 -
784 - fclose($output);
785 - wp_die();
786 -}
787 -
788 -public function mxchat_fetch_chat_history() {
789 - global $wpdb;
790 - $table_name = $wpdb->prefix . 'mxchat_chat_transcripts';
791 -
792 - if (!current_user_can('manage_options')) {
793 - wp_die(esc_html__('You do not have sufficient permissions to view this page.', 'mxchat'));
794 - }
795 -
796 - // First get unique session IDs ordered by most recent message in each session
797 - $session_ids = $wpdb->get_col(
798 - $wpdb->prepare(
799 - "SELECT DISTINCT session_id
800 - FROM {$table_name}
801 - GROUP BY session_id
802 - ORDER BY MAX(timestamp) DESC"
803 - )
804 - );
805 -
806 - if (empty($session_ids)) {
807 - wp_die(esc_html__('No chat history available.', 'mxchat'));
808 - }
809 -
810 - ob_start();
811 - echo '<div class="mxchat-transcript">';
812 -
813 - // Iterate through sessions from newest to oldest
814 - foreach ($session_ids as $session_id) {
815 - // Get the email associated with this session (if available)
816 - $email = $wpdb->get_var(
817 - $wpdb->prepare(
818 - "SELECT user_email
819 - FROM {$table_name}
820 - WHERE session_id = %s AND user_email != ''
821 - ORDER BY timestamp ASC
822 - LIMIT 1",
823 - $session_id
824 - )
825 - );
826 -
827 - // Debug: Check email retrieval
828 - if (empty($email)) {
829 - //error_log("No email found for session {$session_id}");
334 + if (!empty($nonce) && wp_verify_nonce($nonce, 'mxchat_prompts_search_nonce')) {
335 + // Sanitize input data
336 + $search_query = isset($_GET['search']) ? sanitize_text_field($_GET['search']) : '';
337 + $current_page = isset($_GET['paged']) ? absint($_GET['paged']) : 1;
830 338 } else {
831 - //error_log("Email for session {$session_id}: " . $email);
339 + $search_query = '';
340 + $current_page = 1;
832 341 }
833 342
834 - // Get messages for this session ordered by timestamp
835 - $messages = $wpdb->get_results(
836 - $wpdb->prepare(
837 - "SELECT * FROM {$table_name}
838 - WHERE session_id = %s
839 - ORDER BY timestamp ASC",
840 - $session_id
841 - )
842 - );
343 + $per_page = 10;
843 344
844 - // Start session block
845 - echo '<div class="mxchat-session">';
846 - echo '<div class="mxchat-session-header">';
847 - // Wrap checkbox and session ID in one block
848 - echo '<div class="mxchat-session-id">';
849 - echo '<input type="checkbox" name="delete_session_ids[]" value="' . esc_attr($session_id) . '"> ';
850 - echo '<strong>' . esc_html__('Session ID:', 'mxchat') . '</strong> ' . esc_html($session_id);
851 - echo '</div>';
345 + // Create cache keys
346 + $cache_key_total = 'total_prompts_' . md5($search_query);
347 + $cache_key_prompts = 'prompts_' . md5($search_query . '_' . $current_page);
852 348
853 - // Place email directly below the session ID block
854 - if (!empty($email)) {
855 - echo '<div class="mxchat-session-email">';
856 - echo '<strong>' . esc_html__('Email:', 'mxchat') . '</strong> ' . esc_html($email);
857 - echo '</div>';
349 + // Retrieve total number of prompts from cache or database
350 + $total_prompts = wp_cache_get($cache_key_total, 'mxchat_prompts');
351 + if ($total_prompts === false) {
352 + if (!empty($search_query)) {
353 + $total_prompts = $wpdb->get_var(
354 + $wpdb->prepare(
355 + "SELECT COUNT(*) FROM {$table_name} WHERE article_content LIKE %s",
356 + '%' . $wpdb->esc_like($search_query) . '%'
357 + )
358 + );
359 + } else {
360 + $total_prompts = $wpdb->get_var("SELECT COUNT(*) FROM {$table_name}");
361 + }
362 + wp_cache_set($cache_key_total, $total_prompts, 'mxchat_prompts', 3600); // Cache for 1 hour
858 363 }
859 - echo '</div>';
860 364
861 - echo '<div class="mxchat-messages">';
365 + $total_pages = ceil($total_prompts / $per_page);
366 + $offset = ($current_page - 1) * $per_page;
862 367
863 - // Display messages for this session
864 - foreach ($messages as $transcript) {
865 - $formatted_timestamp = date_i18n('F j, Y g:i a', strtotime($transcript->timestamp));
866 -
867 - // Determine message styling
868 - switch ($transcript->role) {
869 - case 'assistant':
870 - case 'bot':
871 - $message_class = 'bot-message';
872 - $display_role = esc_html__('Chatbot', 'mxchat');
873 - break;
874 - case 'user':
875 - $message_class = 'user-message';
876 - $display_role = !empty($transcript->user_identifier)
877 - ? sanitize_text_field($transcript->user_identifier)
878 - : esc_html__('User', 'mxchat');
879 - break;
880 - case 'agent':
881 - $message_class = 'agent-message';
882 - $display_role = esc_html__('Agent', 'mxchat');
883 - break;
884 - default:
885 - $message_class = 'unknown-message';
886 - $display_role = esc_html__('Unknown', 'mxchat');
368 + // Retrieve prompts from cache or database
369 + $prompts = wp_cache_get($cache_key_prompts, 'mxchat_prompts');
370 + if ($prompts === false) {
371 + if (!empty($search_query)) {
372 + $prompts = $wpdb->get_results(
373 + $wpdb->prepare(
374 + "SELECT * FROM {$table_name} WHERE article_content LIKE %s ORDER BY timestamp DESC LIMIT %d OFFSET %d",
375 + '%' . $wpdb->esc_like($search_query) . '%',
376 + $per_page,
377 + $offset
378 + )
379 + );
380 + } else {
381 + $prompts = $wpdb->get_results(
382 + $wpdb->prepare(
383 + "SELECT * FROM {$table_name} ORDER BY timestamp DESC LIMIT %d OFFSET %d",
384 + $per_page,
385 + $offset
386 + )
387 + );
887 388 }
888 -
889 - // Process message content
890 - $message_content = wp_kses(
891 - stripslashes($transcript->message),
892 - [
893 - 'b' => [], 'strong' => [], 'i' => [], 'em' => [], 'u' => [],
894 - 'br' => [], 'p' => [], 'ul' => [], 'ol' => [], 'li' => [],
895 - 'a' => ['href' => [], 'title' => []]
896 - ]
897 - );
898 - $message_content = nl2br($message_content);
899 -
900 - // Render message
901 - echo '<div class="mxchat-message ' . esc_attr($message_class) . '">';
902 - echo '<div class="mxchat-message-header">' . esc_html($display_role) . '</div>';
903 - echo '<div class="mxchat-message-content">' . $message_content . '</div>';
904 - echo '<div class="mxchat-timestamp">' . esc_html($formatted_timestamp) . '</div>';
905 - echo '</div>';
389 + wp_cache_set($cache_key_prompts, $prompts, 'mxchat_prompts', 3600); // Cache for 1 hour
906 390 }
907 391
908 - // Close session block
909 - echo '</div></div>';
910 - }
392 + ?>
911 393
912 - echo '</div>';
913 - $output = ob_get_clean();
914 - echo $output;
915 - wp_die();
916 -}
394 + <div class="wrap mxchat-admin">
395 + <div class="mxchat-grid-container">
917 396
397 + <!-- Submit Content -->
398 + <div class="mxchat-grid-item full-width">
399 + <h2>Submit Content</h2>
400 + <form method="post" action="<?php echo esc_url(admin_url('admin-post.php?action=mxchat_submit_content')); ?>">
401 + <?php wp_nonce_field('mxchat_submit_content_action', 'mxchat_submit_content_nonce'); ?>
402 + <div class="mxchat-form-group">
403 + <label for="article_content">Article Content:</label>
404 + <textarea name="article_content" id="article_content" required></textarea>
405 + <input type="submit" name="submit_content" value="Submit Content" class="button button-primary submit-content-button" />
406 + </div>
407 + </form>
408 + </div>
918 409
919 -
920 -public function mxchat_create_prompts_page() {
921 - global $wpdb;
922 - $table_name = $wpdb->prefix . 'mxchat_system_prompt_content';
923 -
924 - // Display success message if all prompts were deleted
925 - if (isset($_GET['all_deleted']) && $_GET['all_deleted'] === 'true') {
926 - echo '<div class="notice notice-success is-dismissible"><p>' . esc_html__('All knowledge has been deleted successfully.', 'mxchat') . '</p></div>';
927 - }
928 -
929 - // Set up pagination and search query
930 - $nonce = isset($_GET['_wpnonce']) ? sanitize_text_field($_GET['_wpnonce']) : '';
931 - $search_query = (!empty($nonce) && wp_verify_nonce($nonce, 'mxchat_prompts_search_nonce') && isset($_GET['search'])) ? sanitize_text_field($_GET['search']) : '';
932 - $current_page = isset($_GET['paged']) ? absint($_GET['paged']) : 1;
933 - $per_page = 10;
934 - $offset = ($current_page - 1) * $per_page;
935 -
936 - // Modify query to handle search input
937 - $sql_search = "";
938 - if ($search_query) {
939 - $sql_search = $wpdb->prepare("WHERE article_content LIKE %s", '%' . $wpdb->esc_like($search_query) . '%');
940 - }
941 -
942 - // Retrieve total number of prompts, considering search filter
943 - $total_prompts = $wpdb->get_var("SELECT COUNT(*) FROM {$table_name} {$sql_search}");
944 - $total_pages = ceil($total_prompts / $per_page);
945 -
946 - // Retrieve prompts from the database
947 - $prompts = $wpdb->get_results(
948 - $wpdb->prepare(
949 - "SELECT * FROM {$table_name} {$sql_search} ORDER BY timestamp DESC LIMIT %d OFFSET %d",
950 - $per_page,
951 - $offset
952 - )
953 - );
954 -
955 - // Add the pagination links generation here
956 - $page_links = paginate_links(array(
957 - 'base' => add_query_arg(array(
958 - 'paged' => '%#%',
959 - 'search' => urlencode($search_query),
960 - '_wpnonce' => wp_create_nonce('mxchat_prompts_search_nonce')
961 - ), admin_url('admin.php?page=mxchat-prompts')),
962 - 'format' => '',
963 - 'prev_text' => __('&laquo; Previous', 'mxchat'),
964 - 'next_text' => __('Next &raquo;', 'mxchat'),
965 - 'total' => $total_pages,
966 - 'current' => $current_page,
967 - ));
968 -
969 - // Retrieve processing statuses
970 - $pdf_url = get_transient('mxchat_last_pdf_url');
971 - $sitemap_url = get_transient('mxchat_last_sitemap_url');
972 - $pdf_status = $pdf_url ? $this->get_pdf_processing_status($pdf_url) : false;
973 - $sitemap_status = $sitemap_url ? $this->get_sitemap_processing_status($sitemap_url) : false;
974 -
975 - if ($pdf_status && $pdf_status['status'] === 'complete') {
976 - delete_transient('mxchat_last_pdf_url');
977 - $pdf_status = false;
978 - }
979 - if ($sitemap_status && $sitemap_status['status'] === 'complete') {
980 - delete_transient('mxchat_last_sitemap_url');
981 - $sitemap_status = false;
982 - }
983 -
984 - $is_processing = ($pdf_status && ($pdf_status['status'] === 'processing' || $pdf_status['status'] === 'error'))
985 - || ($sitemap_status && ($sitemap_status['status'] === 'processing' || $sitemap_status['status'] === 'error'));
986 - ?>
987 - <div class="wrap mxchat-wrapper">
988 - <!-- Hero Section -->
989 - <div class="mxchat-hero">
990 - <h1 class="mxchat-main-title">
991 - <span class="mxchat-gradient-text">Knowledge Base</span> Manager
992 - </h1>
993 - <p class="mxchat-hero-subtitle">
994 - <?php esc_html_e('Enhance your AI chatbot with custom knowledge. Import, manage, and organize your content to keep responses accurate and relevant.', 'mxchat'); ?>
995 - </p>
996 - </div>
997 -
998 - <div class="mxchat-content">
999 - <!-- Import Settings Card -->
1000 - <div class="mxchat-card">
1001 - <h2><?php esc_html_e('Knowledge Import Settings', 'mxchat'); ?></h2>
1002 - <p><?php esc_html_e('Using the free Pinecone DB Manager add-on is recommended for high performance and a knowledge database of more than 500.', 'mxchat'); ?></p>
1003 -
1004 - <!-- Tab Contents -->
1005 - <div class="mxchat-tab-contents">
1006 - <!-- Default Database Tab -->
1007 - <div id="default-db" class="mxchat-tab-content active">
1008 - <!-- Auto-Sync Settings -->
1009 - <div class="mxchat-settings-section">
1010 - <h3><?php esc_html_e('Auto-Sync Settings', 'mxchat'); ?></h3>
1011 - <p class="mxchat-description">
1012 - <?php esc_html_e('Note: Auto-sync works only for newly published content. Existing posts and pages must be imported manually below. Works with Pinecone if enabled', 'mxchat'); ?>
1013 - </p>
1014 - <div class="mxchat-autosave-section"> <!-- Add this wrapper -->
1015 - <div class="mxchat-toggle-group">
1016 - <div class="mxchat-toggle-container">
1017 - <label class="mxchat-toggle-switch">
1018 - <input type="checkbox"
1019 - name="mxchat_auto_sync_posts"
1020 - class="mxchat-autosave-field"
1021 - value="1"
1022 - data-nonce="<?php echo wp_create_nonce('mxchat_prompts_setting_nonce'); ?>"
1023 - <?php checked(get_option('mxchat_auto_sync_posts', '0'), '1'); ?>>
1024 - <span class="mxchat-toggle-slider"></span>
1025 - </label>
1026 - <span class="mxchat-toggle-label">
1027 - <?php esc_html_e('Auto-sync Posts', 'mxchat'); ?>
1028 - </span>
1029 - </div>
1030 - <div class="mxchat-toggle-container">
1031 - <label class="mxchat-toggle-switch">
1032 - <input type="checkbox"
1033 - name="mxchat_auto_sync_pages"
1034 - class="mxchat-autosave-field"
1035 - value="1"
1036 - data-nonce="<?php echo wp_create_nonce('mxchat_prompts_setting_nonce'); ?>"
1037 - <?php checked(get_option('mxchat_auto_sync_pages', '0'), '1'); ?>>
1038 - <span class="mxchat-toggle-slider"></span>
1039 - </label>
1040 - <span class="mxchat-toggle-label">
1041 - <?php esc_html_e('Auto-sync Pages', 'mxchat'); ?>
1042 - </span>
1043 - </div>
1044 - </div>
410 + <!-- Submit Sitemap -->
411 + <div class="mxchat-grid-item">
412 + <h2>Submit Sitemap</h2>
413 + <form id="mxchat-sitemap-form" method="post" class="mxchat-sitemap-form" action="<?php echo esc_url(admin_url('admin-post.php?action=mxchat_submit_sitemap')); ?>">
414 + <?php wp_nonce_field('mxchat_submit_sitemap_action', 'mxchat_submit_sitemap_nonce'); ?>
415 + <div class="mxchat-search-group">
416 + <input type="url" name="sitemap_url" id="sitemap_url" placeholder="Sitemap URL" required />
417 + <input type="submit" name="submit_sitemap" value="Submit Sitemap" class="button button-primary" />
1045 418 </div>
1046 - </div>
419 + </form>
420 + <div id="mxchat-sitemap-loading" class="mxchat-spinner" style="display: none;"></div>
421 + <div id="mxchat-loading-text" style="display: none; margin-top: 10px; color: #333;">Loading sitemap content into database, please wait...</div>
422 + </div>
1047 423
1048 - <!-- Import Methods -->
1049 - <div class="mxchat-import-methods">
1050 - <div class="mxchat-method-card">
1051 - <h4><?php esc_html_e('Sitemap Import', 'mxchat'); ?></h4>
1052 - <p><?php esc_html_e('Import all content from your sitemap automatically. Use a content-specific sub-sitemap, not the sitemap index.', 'mxchat'); ?></p>
1053 - </div>
1054 - <div class="mxchat-method-card">
1055 - <h4><?php esc_html_e('PDF Import', 'mxchat'); ?></h4>
1056 - <p><?php esc_html_e('Import knowledge directly from PDF documents.', 'mxchat'); ?></p>
1057 - </div>
1058 - <div class="mxchat-method-card">
1059 - <h4><?php esc_html_e('Direct URL', 'mxchat'); ?></h4>
1060 - <p><?php esc_html_e('Import content from any specific webpage.', 'mxchat'); ?></p>
1061 - </div>
1062 - <div class="mxchat-method-card">
1063 - <h4><?php esc_html_e('Direct Content', 'mxchat'); ?></h4>
1064 - <p><?php esc_html_e('Directly submit content to be vectorized.', 'mxchat'); ?></p>
1065 - </div>
424 + <!-- Search Knowledge -->
425 + <div class="mxchat-grid-item">
426 + <h2>Search Knowledge</h2>
427 + <form method="get" id="knowledge-search">
428 + <?php wp_nonce_field('mxchat_prompts_search_nonce'); ?>
429 + <input type="hidden" name="page" value="mxchat-prompts" />
430 + <div class="mxchat-search-group">
431 + <input type="text" name="search" placeholder="Search Knowledge" value="<?php echo esc_attr($search_query); ?>" />
432 + <input type="submit" value="Search" class="button button-primary" />
1066 433 </div>
1067 -
1068 - <!-- Import Form -->
1069 - <?php if (!$is_processing) : ?>
1070 - <div class="mxchat-import-form">
1071 - <form id="mxchat-sitemap-form" method="post"
1072 - action="<?php echo esc_url(admin_url('admin-post.php?action=mxchat_submit_sitemap')); ?>">
1073 - <?php wp_nonce_field('mxchat_submit_sitemap_action', 'mxchat_submit_sitemap_nonce'); ?>
1074 - <div class="mxchat-url-input-group">
1075 - <input type="url"
1076 - name="sitemap_url"
1077 - id="sitemap_url"
1078 - placeholder="<?php esc_attr_e('Enter Sitemap, PDF, or Webpage URL', 'mxchat'); ?>"
1079 - required />
1080 - <button type="submit"
1081 - name="submit_sitemap"
1082 - class="mxchat-button-primary">
1083 - <?php esc_html_e('Import', 'mxchat'); ?>
1084 - </button>
1085 - </div>
1086 - </form>
1087 - </div>
1088 - <?php endif; ?>
1089 -
1090 - <!-- Processing Status -->
1091 - <?php if ($pdf_status && $pdf_status['status'] !== 'complete') : ?>
1092 - <div class="mxchat-status-card">
1093 - <div class="mxchat-status-header">
1094 - <h4><?php esc_html_e('PDF Processing Status', 'mxchat'); ?></h4>
1095 - <?php if ($is_processing) : ?>
1096 - <form method="post" class="mxchat-stop-form"
1097 - action="<?php echo esc_url(admin_url('admin-post.php?action=mxchat_stop_processing')); ?>">
1098 - <?php wp_nonce_field('mxchat_stop_processing_action', 'mxchat_stop_processing_nonce'); ?>
1099 - <button type="submit" name="stop_processing" class="mxchat-button-secondary">
1100 - <?php esc_html_e('Stop Processing', 'mxchat'); ?>
1101 - </button>
1102 - </form>
1103 - <?php endif; ?>
1104 - </div>
1105 - <div class="mxchat-progress-bar">
1106 - <div class="mxchat-progress-fill" style="width: <?php echo esc_attr($pdf_status['percentage']); ?>%"></div>
1107 - </div>
1108 - <div class="mxchat-status-details">
1109 - <p><?php printf(
1110 - esc_html__('Progress: %1$d of %2$d pages (%3$d%%)', 'mxchat'),
1111 - absint($pdf_status['processed_pages']),
1112 - absint($pdf_status['total_pages']),
1113 - absint($pdf_status['percentage'])
1114 - ); ?></p>
1115 - <p><?php printf(
1116 - esc_html__('Status: %s', 'mxchat'),
1117 - esc_html(ucfirst($pdf_status['status']))
1118 - ); ?></p>
1119 - <p><?php printf(
1120 - esc_html__('Last update: %s', 'mxchat'),
1121 - esc_html($pdf_status['last_update'])
1122 - ); ?></p>
1123 - </div>
1124 - </div>
1125 - <?php endif; ?>
1126 -
1127 - <?php if ($sitemap_status && $sitemap_status['status'] !== 'complete') : ?>
1128 - <div class="mxchat-status-card">
1129 - <div class="mxchat-status-header">
1130 - <h4><?php esc_html_e('Sitemap Processing Status (Refresh for update)', 'mxchat'); ?></h4>
1131 - <?php if ($is_processing) : ?>
1132 - <form method="post" class="mxchat-stop-form"
1133 - action="<?php echo esc_url(admin_url('admin-post.php?action=mxchat_stop_processing')); ?>">
1134 - <?php wp_nonce_field('mxchat_stop_processing_action', 'mxchat_stop_processing_nonce'); ?>
1135 - <button type="submit" name="stop_processing" class="mxchat-button-secondary">
1136 - <?php esc_html_e('Stop Processing', 'mxchat'); ?>
1137 - </button>
1138 - </form>
1139 - <?php endif; ?>
1140 - </div>
1141 - <div class="mxchat-progress-bar">
1142 - <div class="mxchat-progress-fill" style="width: <?php echo esc_attr($sitemap_status['percentage']); ?>%"></div>
1143 - </div>
1144 - <div class="mxchat-status-details">
1145 - <p><?php printf(
1146 - esc_html__('Progress: %1$d of %2$d URLs (%3$d%%)', 'mxchat'),
1147 - absint($sitemap_status['processed_urls']),
1148 - absint($sitemap_status['total_urls']),
1149 - absint($sitemap_status['percentage'])
1150 - ); ?></p>
1151 - <?php if (!empty($sitemap_status['error']) || !empty($sitemap_status['last_error'])) : ?>
1152 - <div class="mxchat-error-notice">
1153 - <?php if (!empty($sitemap_status['error'])) : ?>
1154 - <p class="error"><?php echo esc_html($sitemap_status['error']); ?></p>
1155 - <?php endif; ?>
1156 - <?php if (!empty($sitemap_status['last_error'])) : ?>
1157 - <p class="last-error"><?php echo esc_html__('Last error:', 'mxchat') . ' ' . esc_html($sitemap_status['last_error']); ?></p>
1158 - <?php endif; ?>
1159 - </div>
1160 - <?php endif; ?>
1161 - </div>
1162 - </div>
1163 - <?php endif; ?>
1164 - </div>
1165 -
1166 -
434 + </form>
1167 435 </div>
1168 436 </div>
1169 437
1170 - <!-- Direct Content Submission Card -->
1171 -<div class="mxchat-card">
1172 - <div class="mxchat-card-header">
1173 - <h2><?php esc_html_e('Submit Direct Content', 'mxchat'); ?></h2>
1174 - </div>
1175 - <form id="mxchat-content-form" method="post"
1176 - action="<?php echo esc_url(admin_url('admin-post.php?action=mxchat_submit_content')); ?>">
1177 - <?php wp_nonce_field('mxchat_submit_content_action', 'mxchat_submit_content_nonce'); ?>
1178 - <div class="mxchat-form-group">
1179 - <label for="article_content"><?php esc_html_e('Content:', 'mxchat'); ?></label>
1180 - <textarea name="article_content" id="article_content" required
1181 - placeholder="<?php esc_attr_e('Enter your content here...', 'mxchat'); ?>"></textarea>
1182 - </div>
1183 - <div class="mxchat-form-group">
1184 - <label for="article_url"><?php esc_html_e('Source URL (Optional):', 'mxchat'); ?></label>
1185 - <input type="url" name="article_url" id="article_url"
1186 - placeholder="<?php esc_attr_e('Enter source URL', 'mxchat'); ?>">
1187 - </div>
1188 - <button type="submit" name="submit_content" class="mxchat-button-primary">
1189 - <?php esc_html_e('Submit Content', 'mxchat'); ?>
1190 - </button>
1191 - </form>
1192 -</div>
438 + <!-- Table below the forms -->
439 + <div class="tablenav">
440 + <div class="tablenav-pages">
441 + <span class="displaying-num"><?php echo esc_html($total_prompts); ?> items</span>
442 + <?php
443 + $page_links = paginate_links(array(
444 + 'base' => add_query_arg('paged', '%#%', admin_url('admin.php?page=mxchat-prompts')),
445 + 'format' => '',
446 + 'prev_text' => __('&laquo; Previous'),
447 + 'next_text' => __('Next &raquo;'),
448 + 'total' => $total_pages,
449 + 'current' => $current_page,
450 + 'add_args' => array(
451 + 'search' => $search_query,
452 + '_wpnonce' => wp_create_nonce('mxchat_prompts_search_nonce')
453 + ),
454 + ));
1193 455
1194 -<!-- Knowledge Base Table Card -->
1195 -<div class="mxchat-card">
1196 - <div class="mxchat-card-header">
1197 - <h2><?php esc_html_e('Knowledge Base', 'mxchat'); ?></h2>
1198 - <div class="mxchat-header-actions">
1199 - <!-- Search -->
1200 - <form method="get" id="knowledge-search" class="mxchat-search-form">
1201 - <?php wp_nonce_field('mxchat_prompts_search_nonce'); ?>
1202 - <input type="hidden" name="page" value="mxchat-prompts" />
1203 - <div class="mxchat-search-group">
1204 - <span class="dashicons dashicons-search"></span>
1205 - <input type="text"
1206 - name="search"
1207 - placeholder="<?php esc_attr_e('Search Knowledge', 'mxchat'); ?>"
1208 - value="<?php echo esc_attr($search_query); ?>" />
456 + if ($page_links) {
457 + echo '<div class="tablenav-pages">' . wp_kses_post($page_links) . '</div>';
458 + }
459 + ?>
1209 460 </div>
1210 - </form>
1211 -
1212 - <!-- Delete All -->
1213 - <form method="post"
1214 - action="<?php echo esc_url(admin_url('admin-post.php?action=mxchat_delete_all_prompts')); ?>"
1215 - class="mxchat-delete-form"
1216 - onsubmit="return confirm('<?php esc_attr_e('Are you sure you want to delete all knowledge? This action cannot be undone.', 'mxchat'); ?>');">
1217 - <?php wp_nonce_field('mxchat_delete_all_prompts_action', 'mxchat_delete_all_prompts_nonce'); ?>
1218 - <button type="submit" name="delete_all_prompts" class="mxchat-button-danger">
1219 - <span class="dashicons dashicons-trash"></span>
1220 - <?php esc_html_e('Delete All', 'mxchat'); ?>
1221 - </button>
1222 - </form>
1223 - </div>
1224 - </div>
1225 -
1226 - <!-- Table -->
1227 - <div class="mxchat-table-wrapper">
1228 - <table class="mxchat-records-table">
1229 - <thead>
1230 - <tr>
1231 - <th><?php esc_html_e('ID', 'mxchat'); ?></th>
1232 - <th><?php esc_html_e('Content', 'mxchat'); ?></th>
1233 - <th><?php esc_html_e('Source', 'mxchat'); ?></th>
1234 - <th><?php esc_html_e('Actions', 'mxchat'); ?></th>
1235 - </tr>
1236 - </thead>
1237 - <tbody>
1238 - <?php if ($prompts) : ?>
1239 - <?php foreach ($prompts as $prompt) : ?>
1240 - <tr id="prompt-<?php echo esc_attr($prompt->id); ?>">
1241 - <td><?php echo esc_html($prompt->id); ?></td>
1242 - <td class="mxchat-content-cell">
1243 - <div class="content-view">
1244 - <?php echo wp_kses_post(wpautop(esc_textarea($prompt->article_content))); ?>
1245 - </div>
1246 - <textarea class="content-edit" style="display:none;">
1247 - <?php echo esc_textarea($prompt->article_content); ?>
1248 - </textarea>
1249 - </td>
1250 - <td class="mxchat-url-cell">
1251 - <?php if (!empty($prompt->source_url)) : ?>
1252 - <a href="<?php echo esc_url($prompt->source_url); ?>" target="_blank">
1253 - <span class="dashicons dashicons-external"></span>
1254 - <?php esc_html_e('View Source', 'mxchat'); ?>
1255 - </a>
1256 - <?php else : ?>
1257 - <span class="mxchat-na"><?php esc_html_e('N/A', 'mxchat'); ?></span>
1258 - <?php endif; ?>
1259 - </td>
1260 - <td class="mxchat-actions-cell">
1261 - <button class="mxchat-button-icon edit-button"
1262 - data-id="<?php echo esc_attr($prompt->id); ?>">
1263 - <span class="dashicons dashicons-edit"></span>
1264 - </button>
1265 - <button class="mxchat-button-icon save-button"
1266 - data-id="<?php echo esc_attr($prompt->id); ?>"
1267 - style="display:none;"
1268 - data-nonce="<?php echo wp_create_nonce('mxchat_save_inline_nonce'); ?>">
1269 - <span class="dashicons dashicons-saved"></span>
1270 - </button>
1271 - <a href="<?php echo esc_url(admin_url(
1272 - 'admin-post.php?action=mxchat_delete_prompt&id=' . esc_attr($prompt->id)
1273 - . '&_wpnonce=' . wp_create_nonce('mxchat_delete_prompt_nonce')
1274 - )); ?>"
1275 - class="mxchat-button-icon delete-button"
1276 - onclick="return confirm('<?php esc_attr_e('Are you sure you want to delete this entry?', 'mxchat'); ?>');">
1277 - <span class="dashicons dashicons-trash"></span>
1278 - </a>
1279 - </td>
1280 - </tr>
1281 - <?php endforeach; ?>
1282 - <?php else : ?>
461 + </div>
462 + <table class="wp-list-table widefat fixed striped">
463 + <thead>
1283 464 <tr>
1284 - <td colspan="4" class="mxchat-no-records">
1285 - <?php esc_html_e('No knowledge base entries found.', 'mxchat'); ?>
1286 - </td>
465 + <th>ID</th>
466 + <th>Article Content</th>
467 + <th>URL</th>
468 + <th>Actions</th>
1287 469 </tr>
1288 - <?php endif; ?>
1289 - </tbody>
1290 - </table>
1291 - </div>
1292 -
1293 - <?php if ($page_links) : ?>
1294 - <div class="mxchat-pagination">
1295 - <?php echo wp_kses_post($page_links); ?>
470 + </thead>
471 + <tbody>
472 + <?php
473 + if ($prompts) {
474 + foreach ($prompts as $prompt) {
475 + ?>
476 + <tr>
477 + <td><?php echo esc_html($prompt->id); ?></td>
478 + <td class="mxchat_article_content_dashboard"><?php echo wp_kses_post(wpautop(esc_textarea($prompt->article_content))); ?></td>
479 + <td class="mxchat_article_url_dashboard">
480 + <?php if (!empty($prompt->source_url)): ?>
481 + <a href="<?php echo esc_url($prompt->source_url); ?>" target="_blank"><?php echo esc_html($prompt->source_url); ?></a>
482 + <?php else: ?>
483 + N/A
484 + <?php endif; ?>
485 + </td>
486 + <td>
487 + <a href="<?php echo esc_url(admin_url('admin-post.php?action=mxchat_delete_prompt&id=' . esc_attr($prompt->id) . '&_wpnonce=' . wp_create_nonce('mxchat_delete_prompt_nonce'))); ?>">Delete</a>
488 + </td>
489 + </tr>
490 + <?php
491 + }
492 + } else {
493 + ?>
494 + <tr>
495 + <td colspan="4">No prompts found.</td>
496 + </tr>
497 + <?php
498 + }
499 + ?>
500 + </tbody>
501 + </table>
1296 502 </div>
1297 - <?php endif; ?>
1298 -</div>
1299 -</div>
1300 -</div>
1301 -<?php
1302 -}
1303 503
1304 -
1305 -public function mxchat_handle_delete_all_prompts() {
1306 - // Verify nonce
1307 - if (!isset($_POST['mxchat_delete_all_prompts_nonce']) || !wp_verify_nonce($_POST['mxchat_delete_all_prompts_nonce'], 'mxchat_delete_all_prompts_action')) {
1308 - wp_die(__('Nonce verification failed.', 'mxchat'));
504 + <?php
1309 505 }
1310 506
1311 - // Check permissions
1312 - if (!current_user_can('manage_options')) {
1313 - wp_die(__('You do not have sufficient permissions to delete all prompts.', 'mxchat'));
1314 - }
1315 -
1316 - global $wpdb;
1317 - $table_name = $wpdb->prefix . 'mxchat_system_prompt_content';
1318 -
1319 - // Delete all prompts from the table
1320 - $wpdb->query("DELETE FROM {$table_name}");
1321 -
1322 - // Clear relevant cache
1323 - wp_cache_delete('all_prompts', 'mxchat_prompts');
1324 -
1325 - // Redirect back with a success message
1326 - $redirect_url = add_query_arg(array(
1327 - 'page' => 'mxchat-prompts',
1328 - 'all_deleted' => 'true'
1329 - ), admin_url('admin.php'));
1330 -
1331 - wp_safe_redirect($redirect_url);
1332 - exit;
1333 -}
1334 -public function mxchat_handle_delete_prompt() {
1335 - // Sanitize and validate nonce
1336 - $nonce = isset($_GET['_wpnonce']) ? sanitize_text_field(wp_unslash($_GET['_wpnonce'])) : '';
1337 - if (empty($nonce) || !wp_verify_nonce($nonce, 'mxchat_delete_prompt_nonce')) {
1338 - wp_die(esc_html__('Nonce verification failed.', 'mxchat'));
1339 - }
1340 -
1341 - // Check permissions
1342 - if (!current_user_can('manage_options')) {
1343 - wp_die(esc_html__('You do not have sufficient permissions to delete prompts.', 'mxchat'));
1344 - }
1345 -
1346 - // Validate and sanitize ID parameter
1347 - $id = isset($_GET['id']) ? intval($_GET['id']) : 0;
1348 - if ($id <= 0) {
1349 - wp_die(esc_html__('Invalid prompt ID.', 'mxchat'));
1350 - }
1351 -
1352 - global $wpdb;
1353 - $table_name = $wpdb->prefix . 'mxchat_system_prompt_content';
1354 -
1355 - // Clear cache and delete prompt
1356 - wp_cache_delete('prompt_' . $id, 'mxchat_prompts');
1357 - $wpdb->delete($table_name, array('id' => $id), array('%d'));
1358 -
1359 - wp_safe_redirect(add_query_arg(array('page' => 'mxchat-prompts', 'deleted' => 'true'), admin_url('admin.php')));
1360 - exit;
1361 -}
1362 -public function mxchat_generate_embedding($text) {
507 + public function mxchat_generate_embedding($text) {
1363 508 $options = get_option('mxchat_options');
1364 - $api_key = $options['api_key'] ?? esc_html__('default_api_key', 'mxchat');
509 + $api_key = $options['api_key'] ?? 'default_api_key';
1365 510
1366 511 $response = wp_remote_post('https://api.openai.com/v1/embeddings', array(
1367 512 'body' => wp_json_encode(array(
1368 - 'model' => esc_html__('text-embedding-ada-002', 'mxchat'),
513 + 'model' => 'text-embedding-ada-002',
1369 514 'input' => $text
1370 515 )),
1371 516 'headers' => array(
1372 517 'Authorization' => 'Bearer ' . $api_key,
1373 - 'Content-Type' => esc_html__('application/json', 'mxchat')
518 + 'Content-Type' => 'application/json'
1374 519 ),
1375 520 ));
1376 521
1377 522 if (is_wp_error($response)) {
@@ -1380,11 +525,12 @@
1380 525
1381 526 $response_data = json_decode(wp_remote_retrieve_body($response), true);
1382 527 return $response_data['data'][0]['embedding'] ?? null;
1383 528 }
1384 -public function mxchat_delete_chat_history() {
529 +
530 + public function mxchat_delete_chat_history() {
1385 531 if (!current_user_can('manage_options')) {
1386 - echo wp_json_encode(['error' => esc_html__('You do not have sufficient permissions.', 'mxchat')]);
532 + echo wp_json_encode(['error' => 'You do not have sufficient permissions.']);
1387 533 wp_die();
1388 534 }
1389 535
1390 536 check_ajax_referer('mxchat_delete_chat_history', 'security');
@@ -1406,1956 +552,124 @@
1406 552
1407 553 // Optionally, clear a general cache if you have one
1408 554 wp_cache_delete('all_chat_sessions', 'mxchat_chat_sessions');
1409 555
1410 - echo wp_json_encode(['success' => esc_html__('Selected chat sessions have been deleted.', 'mxchat')]);
556 + echo wp_json_encode(['success' => 'Selected chat sessions have been deleted.']);
1411 557 } else {
1412 - echo wp_json_encode(['error' => esc_html__('No chat sessions selected for deletion.', 'mxchat')]);
558 + echo wp_json_encode(['error' => 'No chat sessions selected for deletion.']);
1413 559 }
1414 560
1415 561 wp_die();
1416 562 }
1417 -
1418 -
1419 -public function mxchat_save_inline_prompt() {
1420 - // Check for nonce security
1421 - check_ajax_referer('mxchat_save_inline_nonce');
1422 -
1423 - // Verify permissions
1424 - if (!current_user_can('manage_options')) {
1425 - wp_send_json_error(esc_html__('Permission denied.', 'mxchat'));
1426 - return;
1427 - }
1428 -
1429 - global $wpdb;
1430 - $table_name = $wpdb->prefix . 'mxchat_system_prompt_content';
1431 -
1432 - // Validate and sanitize input data
1433 - $prompt_id = isset($_POST['id']) ? absint($_POST['id']) : 0;
1434 - $article_content = isset($_POST['article_content']) ? sanitize_textarea_field($_POST['article_content']) : '';
1435 - $article_url = isset($_POST['article_url']) ? esc_url_raw($_POST['article_url']) : '';
1436 -
1437 - if ($prompt_id > 0 && !empty($article_content)) {
1438 - // Re-generate the embedding vector for the updated content
1439 - $embedding_vector = $this->mxchat_generate_embedding($article_content);
1440 -
1441 - if (is_array($embedding_vector)) {
1442 - // Serialize the embedding vector before storing it
1443 - $embedding_vector_serialized = serialize($embedding_vector);
1444 -
1445 - // Update the prompt in the database
1446 - $updated = $wpdb->update(
1447 - $table_name,
1448 - array(
1449 - 'article_content' => $article_content,
1450 - 'embedding_vector' => $embedding_vector_serialized,
1451 - 'source_url' => $article_url,
1452 - ),
1453 - array('id' => $prompt_id),
1454 - array('%s', '%s', '%s'),
1455 - array('%d')
1456 - );
1457 -
1458 - if ($updated !== false) {
1459 - wp_send_json_success();
1460 - } else {
1461 - wp_send_json_error(esc_html__('Database update failed.', 'mxchat'));
563 +
564 +
565 +
566 + public function mxchat_fetch_chat_history() {
567 + global $wpdb;
568 + $table_name = $wpdb->prefix . 'mxchat_chat_transcripts';
569 +
570 + if (!current_user_can('manage_options')) {
571 + echo esc_html__('You do not have sufficient permissions to view this page.', 'mxchat');
572 + wp_die();
1462 573 }
1463 - } else {
1464 - wp_send_json_error(esc_html__('Embedding generation failed.', 'mxchat'));
1465 - }
1466 - } else {
1467 - wp_send_json_error(esc_html__('Invalid data.', 'mxchat'));
1468 - }
1469 -}
1470 -
1471 -
1472 -
1473 -// Add this method to handle post updates
1474 -public function handle_post_update($post_id, $post, $update) {
1475 - // Basic validation checks
1476 - if (defined('DOING_AUTOSAVE') && DOING_AUTOSAVE || wp_is_post_revision($post_id)) {
1477 - return;
1478 - }
1479 -
1480 - // Only process published content
1481 - if (!in_array($post->post_status, array('publish'))) {
1482 - return;
1483 - }
1484 -
1485 - // Check if sync is enabled for this post type
1486 - $post_type = $post->post_type;
1487 - if (!in_array($post_type, array('post', 'page'))) {
1488 - return;
1489 - }
1490 -
1491 - $sync_option = ($post_type === 'post') ? 'mxchat_auto_sync_posts' : 'mxchat_auto_sync_pages';
1492 - if (get_option($sync_option) != '1') {
1493 - return;
1494 - }
1495 -
1496 - // Prepare content and URL
1497 - $content = wp_strip_all_tags($post->post_content);
1498 - $url = get_permalink($post_id);
1499 -
1500 - // Generate embedding vector
1501 - $embedding_vector = $this->mxchat_generate_embedding($content);
1502 - if (!$embedding_vector) {
1503 - return;
1504 - }
1505 -
1506 - // Check for Pinecone addon and its settings
1507 - $pinecone_settings = get_option('mxchat_pinecone_addon_options');
1508 - $use_pinecone = false;
1509 -
1510 - if ($pinecone_settings && is_array($pinecone_settings)) {
1511 - // Check if Pinecone is enabled and all required settings are present
1512 - $use_pinecone = (
1513 - isset($pinecone_settings['mxchat_use_pinecone']) &&
1514 - $pinecone_settings['mxchat_use_pinecone'] === '1' &&
1515 - !empty($pinecone_settings['mxchat_pinecone_api_key']) &&
1516 - !empty($pinecone_settings['mxchat_pinecone_host']) &&
1517 - !empty($pinecone_settings['mxchat_pinecone_index']) &&
1518 - !empty($pinecone_settings['mxchat_pinecone_environment'])
1519 - );
1520 - }
1521 -
1522 - if ($use_pinecone) {
1523 - // Use Pinecone
1524 - $pinecone_result = $this->store_in_pinecone_main(
1525 - $embedding_vector,
1526 - $content,
1527 - $url,
1528 - $pinecone_settings['mxchat_pinecone_api_key'],
1529 - $pinecone_settings['mxchat_pinecone_environment'],
1530 - $pinecone_settings['mxchat_pinecone_index']
1531 - );
1532 -
1533 - if (!$pinecone_result['success']) {
1534 - //error_log('MXChat: Pinecone sync failed - falling back to WordPress DB');
1535 - $this->store_in_wordpress_db($content, $url, $embedding_vector);
1536 - }
1537 - } else {
1538 - // Fallback to WordPress DB storage
1539 - $this->store_in_wordpress_db($content, $url, $embedding_vector);
1540 - }
1541 -}
1542 -// Modified storage function to add type field
1543 -private function store_in_pinecone_main($embedding_vector, $content, $url, $api_key, $environment, $index_name, $vector_id = null) {
1544 - $vector_id = $vector_id ?: md5($url);
1545 - $options = get_option('mxchat_pinecone_addon_options');
1546 - $host = $options['mxchat_pinecone_host'] ?? '';
1547 -
1548 - if (empty($host)) {
1549 - return array(
1550 - 'success' => false,
1551 - 'message' => 'Pinecone host is not configured. Please set the host in your settings.'
1552 - );
1553 - }
1554 -
1555 - // Determine if this is a product URL
1556 - $is_product = (strpos($url, '/product/') !== false || strpos($url, '/shop/') !== false);
1557 -
1558 - $api_endpoint = "https://{$host}/vectors/upsert";
1559 - $request_body = array(
1560 - 'vectors' => array(
1561 - array(
1562 - 'id' => $vector_id,
1563 - 'values' => $embedding_vector,
1564 - 'metadata' => array(
1565 - 'text' => $content,
1566 - 'source_url' => $url,
1567 - 'type' => $is_product ? 'product' : 'content',
1568 - 'last_updated' => time()
1569 - )
1570 - )
1571 - )
1572 - );
1573 -
1574 - $response = wp_remote_post($api_endpoint, array(
1575 - 'headers' => array(
1576 - 'Api-Key' => $api_key,
1577 - 'accept' => 'application/json',
1578 - 'content-type' => 'application/json'
1579 - ),
1580 - 'body' => wp_json_encode($request_body),
1581 - 'timeout' => 30,
1582 - 'data_format' => 'body'
1583 - ));
1584 -
1585 - if (is_wp_error($response)) {
1586 - return array(
1587 - 'success' => false,
1588 - 'message' => $response->get_error_message()
1589 - );
1590 - }
1591 -
1592 - $response_code = wp_remote_retrieve_response_code($response);
1593 - if ($response_code !== 200) {
1594 - $body = wp_remote_retrieve_body($response);
1595 - return array(
1596 - 'success' => false,
1597 - 'message' => sprintf(
1598 - 'Pinecone API error (HTTP %d): %s',
1599 - $response_code,
1600 - $body
1601 - )
1602 - );
1603 - }
1604 -
1605 - return array(
1606 - 'success' => true,
1607 - 'message' => 'Successfully stored in Pinecone'
1608 - );
1609 -}
1610 -// Helper method for WordPress DB storage
1611 -private function store_in_wordpress_db($content, $url, $embedding_vector) {
1612 - global $wpdb;
1613 - $table_name = $wpdb->prefix . 'mxchat_system_prompt_content';
1614 -
1615 - $existing_entry = $wpdb->get_row(
1616 - $wpdb->prepare("SELECT id FROM $table_name WHERE source_url = %s", $url)
1617 - );
1618 -
1619 - if ($existing_entry) {
1620 - $wpdb->update(
1621 - $table_name,
1622 - array(
1623 - 'article_content' => $content,
1624 - 'embedding_vector' => serialize($embedding_vector),
1625 - 'timestamp' => current_time('mysql')
1626 - ),
1627 - array('id' => $existing_entry->id),
1628 - array('%s', '%s', '%s')
1629 - );
1630 - } else {
1631 - $wpdb->insert(
1632 - $table_name,
1633 - array(
1634 - 'article_content' => $content,
1635 - 'source_url' => $url,
1636 - 'embedding_vector' => serialize($embedding_vector),
1637 - 'timestamp' => current_time('mysql')
1638 - ),
1639 - array('%s', '%s', '%s', '%s')
1640 - );
1641 - }
1642 -}
1643 -/**
1644 - * Handle deletion of posts and pages from both Pinecone and WordPress DB
1645 - *
1646 - * @param int $post_id The ID of the post being deleted
1647 - * @return void
1648 - */
1649 -public function mxchat_handle_post_delete($post_id) {
1650 - // Get post data before it's deleted
1651 - $post = get_post($post_id);
1652 -
1653 - // Basic validation
1654 - if (!$post || wp_is_post_revision($post_id)) {
1655 - return;
1656 - }
1657 -
1658 - // Check post type
1659 - $post_type = $post->post_type;
1660 - if (!in_array($post_type, array('post', 'page'))) {
1661 - return;
1662 - }
1663 -
1664 - // Check if sync is enabled for this post type
1665 - $sync_option = ($post_type === 'post') ? 'mxchat_auto_sync_posts' : 'mxchat_auto_sync_pages';
1666 - if (get_option($sync_option) != '1') {
1667 - return;
1668 - }
1669 -
1670 - // Get the URL before post is deleted
1671 - $source_url = get_permalink($post_id);
1672 - if (!$source_url) {
1673 - //error_log('MXChat: Failed to get permalink for post ' . $post_id);
1674 - return;
1675 - }
1676 -
1677 - // Check for Pinecone addon and its settings
1678 - $pinecone_settings = get_option('mxchat_pinecone_addon_options');
1679 - $use_pinecone = false;
1680 - if ($pinecone_settings && is_array($pinecone_settings)) {
1681 - $use_pinecone = (
1682 - isset($pinecone_settings['mxchat_use_pinecone']) &&
1683 - $pinecone_settings['mxchat_use_pinecone'] === '1' &&
1684 - !empty($pinecone_settings['mxchat_pinecone_api_key']) &&
1685 - !empty($pinecone_settings['mxchat_pinecone_host']) &&
1686 - !empty($pinecone_settings['mxchat_pinecone_index']) &&
1687 - !empty($pinecone_settings['mxchat_pinecone_environment'])
1688 - );
1689 - }
1690 -
1691 - $deletion_successful = false;
1692 -
1693 - if ($use_pinecone) {
1694 - try {
1695 - $pinecone_result = $this->delete_from_pinecone(
1696 - array($source_url),
1697 - $pinecone_settings['mxchat_pinecone_api_key'],
1698 - $pinecone_settings['mxchat_pinecone_environment'],
1699 - $pinecone_settings['mxchat_pinecone_index']
1700 - );
1701 -
1702 - if (!$pinecone_result['success']) {
1703 - //error_log('MXChat: Pinecone deletion failed for URL: ' . $source_url . ' - ' . $pinecone_result['message']);
1704 - } else {
1705 - $deletion_successful = true;
574 +
575 + $chat_transcripts = $wpdb->get_results($wpdb->prepare("SELECT * FROM $table_name ORDER BY timestamp ASC"));
576 +
577 + if (empty($chat_transcripts)) {
578 + echo esc_html__('No chat history available.', 'mxchat');
579 + wp_die();
1706 580 }
1707 - } catch (Exception $e) {
1708 - //error_log('MXChat: Exception during Pinecone deletion - ' . $e->getMessage());
1709 - }
1710 - }
1711 -
1712 - // Always attempt WordPress DB deletion, regardless of Pinecone status
1713 - try {
1714 - global $wpdb;
1715 - $table_name = $wpdb->prefix . 'mxchat_system_prompt_content';
1716 -
1717 - $result = $wpdb->delete(
1718 - $table_name,
1719 - array('source_url' => $source_url),
1720 - array('%s')
1721 - );
1722 -
1723 - if ($result === false) {
1724 - //error_log('MXChat: WordPress DB deletion failed for URL: ' . $source_url);
1725 - } else {
1726 - $deletion_successful = true;
1727 - }
1728 - } catch (Exception $e) {
1729 - //error_log('MXChat: Exception during WordPress DB deletion - ' . $e->getMessage());
1730 - }
1731 -
1732 - if (!$deletion_successful) {
1733 - //error_log('MXChat: Complete deletion failure for post ID: ' . $post_id . ' URL: ' . $source_url);
1734 - }
1735 -}
1736 -
1737 -
1738 -public function mxchat_handle_content_submission() {
1739 - // Check if the form was submitted and the user has permission.
1740 - if (!isset($_POST['submit_content']) || !current_user_can('manage_options')) {
1741 - return;
1742 - }
1743 -
1744 - // Verify the nonce.
1745 - $nonce = isset($_POST['mxchat_submit_content_nonce']) ? sanitize_text_field(wp_unslash($_POST['mxchat_submit_content_nonce'])) : '';
1746 - if (!wp_verify_nonce($nonce, 'mxchat_submit_content_action')) {
1747 - wp_die(esc_html__('Nonce verification failed.', 'mxchat'));
1748 - }
1749 -
1750 - // Sanitize the inputs.
1751 - $article_content = sanitize_textarea_field($_POST['article_content']);
1752 - $article_url = isset($_POST['article_url']) ? esc_url_raw($_POST['article_url']) : '';
1753 -
1754 - // Generate the embedding vector.
1755 - $embedding_vector = $this->mxchat_generate_embedding($article_content);
1756 - if (!is_array($embedding_vector)) {
1757 - set_transient('mxchat_admin_notice_error',
1758 - esc_html__('Embedding generation failed. Please ensure your API key is correct and try again.', 'mxchat'),
1759 - 30
1760 - );
1761 - wp_safe_redirect(esc_url(admin_url('admin.php?page=mxchat-prompts')));
1762 - exit;
1763 - }
1764 -
1765 - // Store in the WordPress database.
1766 - global $wpdb;
1767 - $table_name = $wpdb->prefix . 'mxchat_system_prompt_content';
1768 -
1769 - // Ensure the source_url column exists.
1770 - if ($wpdb->get_var($wpdb->prepare("SHOW COLUMNS FROM {$table_name} LIKE %s", 'source_url')) != 'source_url') {
1771 - $wpdb->query($wpdb->prepare("ALTER TABLE {$table_name} ADD source_url VARCHAR(255) DEFAULT ''"));
1772 - }
1773 -
1774 - // Serialize and store the embedding vector.
1775 - $embedding_vector_serialized = serialize($embedding_vector);
1776 - $inserted = $wpdb->insert(
1777 - $table_name,
1778 - array(
1779 - 'article_content' => $article_content,
1780 - 'embedding_vector' => $embedding_vector_serialized,
1781 - 'source_url' => $article_url,
1782 - ),
1783 - array('%s', '%s', '%s')
1784 - );
1785 -
1786 - if ($inserted === false) {
1787 - set_transient('mxchat_admin_notice_error',
1788 - esc_html__('Error inserting content into the database. Please try again.', 'mxchat'),
1789 - 30
1790 - );
1791 - } else {
1792 - set_transient('mxchat_admin_notice_success',
1793 - esc_html__('Content successfully submitted!', 'mxchat'),
1794 - 30
1795 - );
1796 - }
1797 -
1798 - wp_safe_redirect(esc_url(admin_url('admin.php?page=mxchat-prompts')));
1799 - exit;
1800 -}
1801 -
1802 -private function is_pdf_url($url, $response) {
1803 - $content_type = wp_remote_retrieve_header($response, 'content-type');
1804 - $file_extension = strtolower(pathinfo($url, PATHINFO_EXTENSION));
1805 -
1806 - return strpos($content_type, 'pdf') !== false || $file_extension === 'pdf';
1807 -}
1808 -private function handle_pdf_for_knowledge_base($pdf_url, $response) {
1809 - if (!current_user_can('manage_options')) {
1810 - //error_log(esc_html__('Unauthorized PDF processing attempt', 'mxchat'));
1811 - return false;
1812 - }
1813 -
1814 - $pdf_url = esc_url_raw($pdf_url);
1815 - $upload_dir = wp_upload_dir();
1816 -
1817 - if (isset($upload_dir['error']) && $upload_dir['error'] !== false) {
1818 - //error_log(sprintf(esc_html__('Upload directory error: %s', 'mxchat'), esc_html($upload_dir['error'])));
1819 - return false;
1820 - }
1821 -
1822 - $pdf_filename = sanitize_file_name('mxchat_kb_' . time() . '.pdf');
1823 - $pdf_path = trailingslashit($upload_dir['path']) . $pdf_filename;
1824 -
1825 - $response_body = wp_remote_retrieve_body($response);
1826 - if (empty($response_body)) {
1827 - //error_log(esc_html__('Empty PDF response body', 'mxchat'));
1828 - return false;
1829 - }
1830 -
1831 - if (!wp_mkdir_p(dirname($pdf_path))) {
1832 - //error_log(sprintf(esc_html__('Failed to create directory for PDF: %s', 'mxchat'), esc_html($pdf_path)));
1833 - return false;
1834 - }
1835 -
1836 - try {
1837 - file_put_contents($pdf_path, $response_body);
1838 -
1839 - if (!file_exists($pdf_path)) {
1840 - throw new Exception(__('Failed to save PDF file', 'mxchat'));
1841 - }
1842 -
1843 - $parser = new \Smalot\PdfParser\Parser();
1844 - $pdf = $parser->parseFile($pdf_path);
1845 - $total_pages = absint(count($pdf->getPages()));
1846 -
1847 - if ($total_pages < 1) {
1848 - throw new Exception(__('Invalid PDF: no pages found', 'mxchat'));
1849 - }
1850 -
1851 - wp_schedule_single_event(time(), 'mxchat_process_pdf_pages', array(
1852 - 'pdf_path' => $pdf_path,
1853 - 'pdf_url' => $pdf_url,
1854 - 'total_pages' => $total_pages,
1855 - 'batch_size' => absint(15),
1856 - 'batch_pause' => absint(10)
1857 - ));
1858 -
1859 - $status_data = array(
1860 - 'total_pages' => $total_pages,
1861 - 'processed_pages' => 0,
1862 - 'status' => 'processing',
1863 - 'last_update' => time()
1864 - );
1865 -
1866 - set_transient(
1867 - sanitize_key('mxchat_pdf_status_' . md5($pdf_url)),
1868 - array_map('sanitize_text_field', $status_data),
1869 - DAY_IN_SECONDS
1870 - );
1871 -
1872 - return __('scheduled', 'mxchat');
1873 -
1874 - } catch (Exception $e) {
1875 - //error_log(sprintf(esc_html__('Error preparing PDF for processing: %s', 'mxchat'), esc_html($e->getMessage())));
1876 - if (file_exists($pdf_path)) {
1877 - wp_delete_file($pdf_path);
1878 - }
1879 - return false;
1880 - }
1881 -}
1882 -public static function process_pdf_pages_cron($pdf_path, $pdf_url, $total_pages, $batch_size, $batch_pause) {
1883 - // Validate inputs
1884 - $pdf_path = sanitize_text_field($pdf_path);
1885 - $pdf_url = esc_url_raw($pdf_url);
1886 - $total_pages = absint($total_pages);
1887 - $batch_size = absint($batch_size);
1888 - $batch_pause = absint($batch_pause);
1889 -
1890 - try {
1891 - if (!file_exists($pdf_path)) {
1892 - throw new Exception(sprintf('PDF file not found at path: %s', esc_html($pdf_path)));
1893 - }
1894 -
1895 - $parser = new \Smalot\PdfParser\Parser();
1896 - $pdf = $parser->parseFile($pdf_path);
1897 - $pages = $pdf->getPages();
1898 -
1899 - // Get current progress
1900 - $status_key = sanitize_key('mxchat_pdf_status_' . md5($pdf_url));
1901 - $status = get_transient($status_key);
1902 -
1903 - if (!$status || !is_array($status)) {
1904 - throw new Exception('Invalid status data retrieved from transient');
1905 - }
1906 -
1907 - $start_page = absint($status['processed_pages']);
1908 - $end_page = min($start_page + $batch_size, $total_pages);
1909 -
1910 - $instance = new self(); // Create an instance of the class
1911 -
1912 - for ($i = $start_page; $i < $end_page; $i++) {
1913 - $text = $pages[$i]->getText();
1914 - $sanitized_content = $instance->mxchat_sanitize_content_for_api($text); // Call via instance
1915 -
1916 - if (!empty($sanitized_content)) {
1917 - $embedding_vector = $instance->mxchat_generate_embedding($sanitized_content); // Call via instance
1918 - if (is_array($embedding_vector)) {
1919 - $metadata = array(
1920 - 'document_type' => 'pdf',
1921 - 'total_pages' => $total_pages,
1922 - 'current_page' => $i + 1,
1923 - 'prev_page' => $i > 0 ? $i : null,
1924 - 'next_page' => $i < ($total_pages - 1) ? $i + 2 : null,
1925 - 'source_url' => $pdf_url
1926 - );
1927 -
1928 - $content_with_metadata = wp_json_encode($metadata) . "\n---\n" . $sanitized_content;
1929 - $page_url = esc_url($pdf_url . "#page=" . ($i + 1));
1930 -
1931 - $options = get_option('mxchat_options');
1932 - MxChat_Utils::submit_content_to_db($content_with_metadata, $page_url, $options['api_key']);
1933 - }
1934 - }
1935 -
1936 - // Update progress with sanitized data
1937 - $status['processed_pages'] = absint($i + 1);
1938 - $status['last_update'] = time();
1939 - set_transient($status_key, array_map('sanitize_text_field', $status), DAY_IN_SECONDS);
1940 - }
1941 -
1942 - // Schedule next batch if needed
1943 - if ($end_page < $total_pages) {
1944 - wp_schedule_single_event(time() + $batch_pause, 'mxchat_process_pdf_pages', array(
1945 - 'pdf_path' => $pdf_path,
1946 - 'pdf_url' => $pdf_url,
1947 - 'total_pages' => $total_pages,
1948 - 'batch_size' => $batch_size,
1949 - 'batch_pause' => $batch_pause
1950 - ));
1951 - } else {
1952 - // Processing complete
1953 - $status['status'] = 'complete';
1954 - set_transient($status_key, array_map('sanitize_text_field', $status), DAY_IN_SECONDS);
1955 - if (file_exists($pdf_path)) {
1956 - wp_delete_file($pdf_path);
1957 - }
1958 - }
1959 -
1960 - } catch (\Exception $e) {
1961 - $status['status'] = 'error';
1962 - $status['error'] = sanitize_text_field($e->getMessage());
1963 - set_transient($status_key, array_map('sanitize_text_field', $status), DAY_IN_SECONDS);
1964 - if (file_exists($pdf_path)) {
1965 - wp_delete_file($pdf_path);
1966 - }
1967 - }
1968 -}
1969 -public function get_pdf_processing_status($pdf_url) {
1970 - $pdf_url = esc_url_raw($pdf_url);
1971 - $status = get_transient(sanitize_key('mxchat_pdf_status_' . md5($pdf_url)));
1972 -
1973 - if (!$status || !is_array($status)) {
1974 - return false;
1975 - }
1976 -
1977 - return array(
1978 - 'total_pages' => absint($status['total_pages']),
1979 - 'processed_pages' => absint($status['processed_pages']),
1980 - 'percentage' => ($status['total_pages'] > 0)
1981 - ? round((absint($status['processed_pages']) / absint($status['total_pages'])) * 100)
1982 - : 0,
1983 - 'status' => sanitize_text_field($status['status']),
1984 - 'last_update' => human_time_diff(absint($status['last_update']), time()) . ' ' . esc_html__('ago', 'mxchat')
1985 - );
1986 -}
1987 -public function mxchat_handle_sitemap_submission() {
1988 - // Check if the form was submitted and verify permissions
1989 - if (!isset($_POST['submit_sitemap']) || !current_user_can('manage_options')) {
1990 - wp_die(esc_html__('Unauthorized access', 'mxchat'));
1991 - }
1992 -
1993 - // Verify nonce
1994 - check_admin_referer('mxchat_submit_sitemap_action', 'mxchat_submit_sitemap_nonce');
1995 -
1996 - // Validate URL
1997 - if (!isset($_POST['sitemap_url']) || empty($_POST['sitemap_url'])) {
1998 - set_transient('mxchat_admin_notice_error',
1999 - esc_html__('Please provide a valid URL.', 'mxchat'),
2000 - 30
2001 - );
2002 - wp_safe_redirect(esc_url(admin_url('admin.php?page=mxchat-prompts')));
2003 - exit;
2004 - }
2005 -
2006 - $submitted_url = esc_url_raw($_POST['sitemap_url']);
2007 - $response = wp_remote_get($submitted_url, array('timeout' => 30));
2008 -
2009 - if (is_wp_error($response) || wp_remote_retrieve_response_code($response) !== 200) {
2010 - $error_message = is_wp_error($response) ? $response->get_error_message() : __('Failed to fetch URL', 'mxchat');
2011 - set_transient('mxchat_admin_notice_error',
2012 - sprintf(
2013 - esc_html__('Failed to fetch the URL: %s', 'mxchat'),
2014 - esc_html($error_message)
2015 - ),
2016 - 30
2017 - );
2018 - wp_safe_redirect(esc_url(admin_url('admin.php?page=mxchat-prompts')));
2019 - exit;
2020 - }
2021 -
2022 - $content_type = wp_remote_retrieve_header($response, 'content-type');
2023 - $body_content = wp_remote_retrieve_body($response);
2024 -
2025 - if (empty($body_content)) {
2026 - set_transient('mxchat_admin_notice_error',
2027 - esc_html__('Empty response received from URL.', 'mxchat'),
2028 - 30
2029 - );
2030 - wp_safe_redirect(esc_url(admin_url('admin.php?page=mxchat-prompts')));
2031 - exit;
2032 - }
2033 -
2034 - // Handle PDF URL
2035 - if ($this->is_pdf_url($submitted_url, $response)) {
2036 - $result = $this->handle_pdf_for_knowledge_base($submitted_url, $response);
2037 -
2038 - if ($result === 'scheduled') {
2039 - set_transient(
2040 - 'mxchat_last_pdf_url',
2041 - sanitize_text_field($submitted_url),
2042 - DAY_IN_SECONDS
2043 - );
2044 - set_transient('mxchat_admin_notice_info',
2045 - esc_html__('PDF processing has started in the background. You can check the progress in the Knowledge Base section.', 'mxchat'),
2046 - 30
2047 - );
2048 - } else {
2049 - set_transient('mxchat_admin_notice_error',
2050 - esc_html__('Failed to start PDF processing. Please try again.', 'mxchat'),
2051 - 30
2052 - );
2053 - }
2054 -
2055 - wp_safe_redirect(esc_url(admin_url('admin.php?page=mxchat-prompts')));
2056 - exit;
2057 - }
2058 -
2059 - // Handle Sitemap XML
2060 - if (strpos($content_type, 'xml') !== false || strpos($body_content, '<urlset') !== false) {
2061 - libxml_use_internal_errors(true);
2062 - $xml = simplexml_load_string($body_content);
2063 - $xml_errors = libxml_get_errors();
2064 - libxml_clear_errors();
2065 -
2066 - if ($xml === false || !empty($xml_errors)) {
2067 - set_transient('mxchat_admin_notice_error',
2068 - esc_html__('Invalid sitemap XML. Please provide a valid sitemap.', 'mxchat'),
2069 - 30
2070 - );
2071 - wp_safe_redirect(esc_url(admin_url('admin.php?page=mxchat-prompts')));
2072 - exit;
2073 - }
2074 -
2075 - $result = $this->handle_sitemap_for_knowledge_base($xml, $submitted_url);
2076 -
2077 - if ($result === 'scheduled') {
2078 - set_transient(
2079 - 'mxchat_last_sitemap_url',
2080 - sanitize_text_field($submitted_url),
2081 - DAY_IN_SECONDS
2082 - );
2083 - set_transient('mxchat_admin_notice_info',
2084 - esc_html__('Sitemap processing has started in the background. You can check the progress in the Knowledge Base section.', 'mxchat'),
2085 - 30
2086 - );
2087 - } else {
2088 - set_transient('mxchat_admin_notice_error',
2089 - esc_html__('Failed to start sitemap processing. Please try again.', 'mxchat'),
2090 - 30
2091 - );
2092 - }
2093 -
2094 - wp_safe_redirect(esc_url(admin_url('admin.php?page=mxchat-prompts')));
2095 - exit;
2096 - }
2097 -
2098 - // Handle Regular URL
2099 - $page_content = $this->mxchat_extract_main_content($body_content);
2100 - $sanitized_content = $this->mxchat_sanitize_content_for_api($page_content);
2101 -
2102 - if (empty($sanitized_content)) {
2103 - set_transient('mxchat_admin_notice_error',
2104 - esc_html__('No valid content found on the provided URL.', 'mxchat'),
2105 - 30
2106 - );
2107 - wp_safe_redirect(esc_url(admin_url('admin.php?page=mxchat-prompts')));
2108 - exit;
2109 - }
2110 -
2111 - $embedding_vector = $this->mxchat_generate_embedding($sanitized_content);
2112 - if (is_array($embedding_vector)) {
2113 - MxChat_Utils::submit_content_to_db(
2114 - $sanitized_content,
2115 - $submitted_url,
2116 - $this->options['api_key']
2117 - );
2118 - set_transient('mxchat_admin_notice_success',
2119 - esc_html__('URL content successfully submitted!', 'mxchat'),
2120 - 30
2121 - );
2122 - } else {
2123 - set_transient('mxchat_admin_notice_error',
2124 - esc_html__('Failed to generate embedding for the URL content. Please check your API key and try again.', 'mxchat'),
2125 - 30
2126 - );
2127 - }
2128 -
2129 - wp_safe_redirect(esc_url(admin_url('admin.php?page=mxchat-prompts')));
2130 - exit;
2131 -}
2132 -private function handle_sitemap_for_knowledge_base($xml, $sitemap_url) {
2133 - if (!current_user_can('manage_options')) {
2134 - //error_log(esc_html__('Unauthorized sitemap processing attempt', 'mxchat'));
2135 - return false;
2136 - }
2137 -
2138 - try {
2139 - $sitemap_url = esc_url_raw($sitemap_url);
2140 -
2141 - if (!$xml || !is_object($xml)) {
2142 - throw new Exception(__('Invalid XML object provided', 'mxchat'));
2143 - }
2144 -
2145 - $urls = [];
2146 - foreach ($xml->url as $url_element) {
2147 - $url = esc_url_raw((string)$url_element->loc);
2148 - if ($url) {
2149 - $urls[] = $url;
2150 - }
2151 - }
2152 -
2153 - $total_urls = absint(count($urls));
2154 -
2155 - if ($total_urls < 1) {
2156 - throw new Exception(__('No valid URLs found in sitemap', 'mxchat'));
2157 - }
2158 -
2159 - wp_schedule_single_event(time(), 'mxchat_process_sitemap_urls', array(
2160 - 'urls' => $urls,
2161 - 'sitemap_url' => $sitemap_url,
2162 - 'total_urls' => $total_urls,
2163 - 'batch_size' => absint(10),
2164 - 'batch_pause' => absint(5)
2165 - ));
2166 -
2167 - $status_data = array(
2168 - 'total_urls' => $total_urls,
2169 - 'processed_urls' => 0,
2170 - 'status' => 'processing',
2171 - 'last_update' => time()
2172 - );
2173 -
2174 - set_transient(
2175 - sanitize_key('mxchat_sitemap_status_' . md5($sitemap_url)),
2176 - array_map('sanitize_text_field', $status_data),
2177 - DAY_IN_SECONDS
2178 - );
2179 -
2180 - return __('scheduled', 'mxchat');
2181 -
2182 - } catch (\Exception $e) {
2183 - //error_log(sprintf(esc_html__('Error preparing sitemap for processing: %s', 'mxchat'), esc_html($e->getMessage())));
2184 - return false;
2185 - }
2186 -}
2187 -public static function process_sitemap_urls_cron($urls, $sitemap_url, $total_urls, $batch_size, $batch_pause) {
2188 - // Validate inputs
2189 - $sitemap_url = esc_url_raw($sitemap_url);
2190 - $total_urls = absint($total_urls);
2191 - $batch_size = absint($batch_size);
2192 - $batch_pause = absint($batch_pause);
2193 -
2194 - if (!is_array($urls) || empty($urls)) {
2195 - return;
2196 - }
2197 -
2198 - try {
2199 - $status_key = sanitize_key('mxchat_sitemap_status_' . md5($sitemap_url));
2200 - $status = get_transient($status_key);
2201 -
2202 - if (!$status || !is_array($status)) {
2203 - throw new Exception('Invalid status data retrieved from transient');
2204 - }
2205 -
2206 - $start_url = absint($status['processed_urls']);
2207 - $end_url = min($start_url + $batch_size, $total_urls);
2208 - $instance = new self();
2209 -
2210 - // Track failures in batch
2211 - $batch_stats = [
2212 - 'processed' => 0,
2213 - 'failed' => 0,
2214 - 'last_error' => ''
2215 - ];
2216 -
2217 - for ($i = $start_url; $i < $end_url; $i++) {
2218 - $page_url = esc_url_raw($urls[$i]);
2219 - $page_response = wp_remote_get($page_url);
2220 -
2221 - if (is_wp_error($page_response) || wp_remote_retrieve_response_code($page_response) !== 200) {
2222 - $batch_stats['failed']++;
2223 - continue;
2224 - }
2225 -
2226 - $page_html = wp_remote_retrieve_body($page_response);
2227 - $page_content = $instance->mxchat_extract_main_content($page_html);
2228 - $sanitized_content = $instance->mxchat_sanitize_content_for_api($page_content);
2229 -
2230 - if (!empty($sanitized_content)) {
2231 - $embedding_vector = $instance->mxchat_generate_embedding($sanitized_content);
2232 -
2233 - if (is_array($embedding_vector)) {
2234 - $options = get_option('mxchat_options');
2235 - $submission_result = MxChat_Utils::submit_content_to_db($sanitized_content, $page_url, $options['api_key']);
2236 -
2237 - if (is_wp_error($submission_result)) {
2238 - $batch_stats['failed']++;
2239 - $batch_stats['last_error'] = $submission_result->get_error_message();
2240 - continue;
581 +
582 + ob_start();
583 + $current_session_id = '';
584 + foreach ($chat_transcripts as $transcript) {
585 + if ($current_session_id !== $transcript->session_id) {
586 + if ($current_session_id !== '') {
587 + echo '</div>';
2241 588 }
2242 -
2243 - $batch_stats['processed']++;
2244 - } else {
2245 - $batch_stats['failed']++;
2246 - $batch_stats['last_error'] = 'Failed to generate embedding. Please check OpenAI API key.';
589 + $current_session_id = sanitize_text_field($transcript->session_id);
590 + echo '<div class="chat-session">';
591 + echo "<h4><input type='checkbox' name='delete_session_ids[]' value='" . esc_attr($transcript->session_id) . "'> " . esc_html__('Session ID:', 'mxchat') . " " . esc_html($transcript->session_id) . "</h4>";
2247 592 }
593 +
594 + $formatted_timestamp = date_i18n('F j, Y g:i a', strtotime($transcript->timestamp));
595 +
596 + echo '<div class="chat-message">';
597 + echo '<strong>' . esc_html($transcript->role) . ' (' . esc_html($formatted_timestamp) . '):</strong> ';
598 + echo wp_kses_post($transcript->message);
599 + echo '</div>';
2248 600 }
2249 -
2250 - $status['processed_urls'] = absint($i + 1);
2251 - $status['last_update'] = time();
2252 - $status['failed_urls'] = absint($status['failed_urls'] ?? 0) + $batch_stats['failed'];
2253 - $status['last_error'] = $batch_stats['last_error'];
2254 -
2255 - set_transient($status_key, array_map('sanitize_text_field', $status), DAY_IN_SECONDS);
601 + echo '</div>';
602 + $output = ob_get_clean();
603 +
604 + echo $output;
605 + wp_die();
2256 606 }
2257 607
2258 - // If all URLs in this batch failed, stop processing
2259 - if ($batch_stats['processed'] === 0 && $batch_stats['failed'] > 0) {
2260 - $status['status'] = 'error';
2261 - $status['error'] = sprintf(
2262 - 'Processing stopped: %d consecutive failures. Last error: %s',
2263 - $batch_stats['failed'],
2264 - $batch_stats['last_error']
2265 - );
2266 - set_transient($status_key, array_map('sanitize_text_field', $status), DAY_IN_SECONDS);
2267 - return;
2268 - }
2269 608
2270 - if ($end_url < $total_urls) {
2271 - wp_schedule_single_event(time() + $batch_pause, 'mxchat_process_sitemap_urls', array(
2272 - 'urls' => array_map('esc_url_raw', $urls),
2273 - 'sitemap_url' => $sitemap_url,
2274 - 'total_urls' => $total_urls,
2275 - 'batch_size' => $batch_size,
2276 - 'batch_pause' => $batch_pause,
2277 - ));
2278 - } else {
2279 - $status['status'] = 'complete';
2280 - set_transient($status_key, array_map('sanitize_text_field', $status), DAY_IN_SECONDS);
2281 - }
2282 - } catch (\Exception $e) {
2283 - $status['status'] = 'error';
2284 - $status['error'] = sanitize_text_field($e->getMessage());
2285 - set_transient($status_key, array_map('sanitize_text_field', $status), DAY_IN_SECONDS);
2286 - }
2287 -}
609 + public function mxchat_create_activation_page() {
610 + $license_status = get_option('mxchat_license_status', 'inactive');
611 + $license_error = get_option('mxchat_license_error', '');
2288 612
2289 -public function get_sitemap_processing_status($sitemap_url) {
2290 - $sitemap_url = esc_url_raw($sitemap_url);
2291 - $status = get_transient(sanitize_key('mxchat_sitemap_status_' . md5($sitemap_url)));
2292 -
2293 - if (!$status || !is_array($status)) {
2294 - return false;
2295 - }
2296 -
2297 - return array(
2298 - 'total_urls' => absint($status['total_urls']),
2299 - 'processed_urls' => absint($status['processed_urls']),
2300 - 'failed_urls' => absint($status['failed_urls'] ?? 0),
2301 - 'percentage' => ($status['total_urls'] > 0)
2302 - ? round((absint($status['processed_urls']) / absint($status['total_urls'])) * 100)
2303 - : 0,
2304 - 'status' => sanitize_text_field($status['status']),
2305 - 'last_update' => human_time_diff(absint($status['last_update']), time()) . ' ' . esc_html__('ago', 'mxchat'),
2306 - 'error' => isset($status['error']) ? sanitize_text_field($status['error']) : '',
2307 - 'last_error' => isset($status['last_error']) ? sanitize_text_field($status['last_error']) : ''
2308 - );
2309 -}
2310 -
2311 -public function mxchat_stop_processing() {
2312 - // Verify permissions
2313 - if (!current_user_can('manage_options')) {
2314 - wp_die(esc_html__('Unauthorized access', 'mxchat'));
2315 - }
2316 -
2317 - // Verify nonce
2318 - check_admin_referer('mxchat_stop_processing_action', 'mxchat_stop_processing_nonce');
2319 -
2320 - // Get the last sitemap URL and clear its transient
2321 - $sitemap_url = get_transient('mxchat_last_sitemap_url');
2322 - if ($sitemap_url) {
2323 - delete_transient('mxchat_sitemap_status_' . md5($sitemap_url));
2324 - delete_transient('mxchat_last_sitemap_url');
2325 - }
2326 -
2327 - // Get the last PDF URL and clear its transient
2328 - $pdf_url = get_transient('mxchat_last_pdf_url');
2329 - if ($pdf_url) {
2330 - delete_transient('mxchat_pdf_status_' . md5($pdf_url));
2331 - delete_transient('mxchat_last_pdf_url');
2332 - }
2333 -
2334 - // Unschedule any pending sitemap events
2335 - $timestamp = wp_next_scheduled('mxchat_process_sitemap_urls');
2336 - if ($timestamp) {
2337 - wp_unschedule_event($timestamp, 'mxchat_process_sitemap_urls');
2338 - }
2339 -
2340 - // Redirect back with a success message
2341 - set_transient('mxchat_admin_notice_success',
2342 - esc_html__('Processing has been stopped successfully.', 'mxchat'),
2343 - 30
2344 - );
2345 - wp_safe_redirect(admin_url('admin.php?page=mxchat-prompts'));
2346 - exit;
2347 -}
2348 -private function mxchat_sanitize_content_for_api($content) {
2349 - // Remove script, style tags, and HTML comments
2350 - $content = preg_replace('/<script\b[^>]*>(.*?)<\/script>/is', '', $content);
2351 - $content = preg_replace('/<style\b[^>]*>(.*?)<\/style>/is', '', $content);
2352 - $content = preg_replace('/<!--(.|\s)*?-->/', '', $content);
2353 -
2354 - // Remove all HTML tags and decode HTML entities
2355 - $content = wp_strip_all_tags($content);
2356 - $content = html_entity_decode($content, ENT_QUOTES | ENT_HTML5);
2357 -
2358 - // Trim and normalize whitespace
2359 - $content = trim(preg_replace('/\s+/', ' ', $content));
2360 -
2361 - return $content;
2362 -}
2363 -
2364 -
2365 -
2366 -
2367 -public function mxchat_handle_product_change($post_id, $post, $update) {
2368 - if ($post->post_type !== 'product') {
2369 - return;
2370 - }
2371 -
2372 - if ($post->post_status === 'publish') {
2373 - add_action('shutdown', function() use ($post_id) {
2374 - $product = wc_get_product($post_id);
2375 - if ($product) {
2376 - $this->mxchat_store_product_embedding($product);
2377 - }
2378 - });
2379 - }
2380 -}
2381 -
2382 -private function mxchat_store_product_embedding($product) {
2383 - if (!isset($this->options['enable_woocommerce_integration']) ||
2384 - !in_array($this->options['enable_woocommerce_integration'], ['1', 'on'])) {
2385 - return;
2386 - }
2387 -
2388 - $source_url = get_permalink($product->get_id());
2389 -
2390 - // Build description
2391 - $regular_price = $product->get_regular_price();
2392 - $sale_price = $product->get_sale_price();
2393 - $description = $product->get_description() . "\n\n" .
2394 - esc_html__('Short Description:', 'mxchat') . " " . $product->get_short_description() . "\n" .
2395 - esc_html__('Price:', 'mxchat') . " " . $regular_price . "\n" .
2396 - esc_html__('Sale Price:', 'mxchat') . " " . ($sale_price ?: esc_html__('N/A', 'mxchat')) . "\n" .
2397 - esc_html__('SKU:', 'mxchat') . " " . $product->get_sku();
2398 -
2399 - // Generate embedding vector
2400 - $embedding_vector = $this->mxchat_generate_embedding($description);
2401 - if (!is_array($embedding_vector)) {
2402 - return;
2403 - }
2404 -
2405 - // Check for Pinecone addon and its settings
2406 - $pinecone_settings = get_option('mxchat_pinecone_addon_options');
2407 - $use_pinecone = false;
2408 -
2409 - if ($pinecone_settings && is_array($pinecone_settings)) {
2410 - $use_pinecone = (
2411 - isset($pinecone_settings['mxchat_use_pinecone']) &&
2412 - $pinecone_settings['mxchat_use_pinecone'] === '1' &&
2413 - !empty($pinecone_settings['mxchat_pinecone_api_key']) &&
2414 - !empty($pinecone_settings['mxchat_pinecone_host']) &&
2415 - !empty($pinecone_settings['mxchat_pinecone_index']) &&
2416 - !empty($pinecone_settings['mxchat_pinecone_environment'])
2417 - );
2418 - }
2419 -
2420 - if ($use_pinecone) {
2421 - $result = $this->store_in_pinecone_main(
2422 - $embedding_vector,
2423 - $description,
2424 - $source_url,
2425 - $pinecone_settings['mxchat_pinecone_api_key'],
2426 - $pinecone_settings['mxchat_pinecone_environment'],
2427 - $pinecone_settings['mxchat_pinecone_index']
2428 - );
2429 -
2430 - if (!$result['success']) {
2431 - // Fallback to WordPress DB if Pinecone storage fails
2432 - $this->store_in_wordpress_db($description, $source_url, $embedding_vector);
2433 - }
2434 - } else {
2435 - // Use WordPress DB storage
2436 - $this->store_in_wordpress_db($description, $source_url, $embedding_vector);
2437 - }
2438 -}
2439 -
2440 -public function mxchat_handle_product_delete($post_id) {
2441 - if (get_post_type($post_id) !== 'product') {
2442 - return;
2443 - }
2444 -
2445 - $source_url = get_permalink($post_id);
2446 -
2447 - // Check for Pinecone addon and its settings
2448 - $pinecone_settings = get_option('mxchat_pinecone_addon_options');
2449 - $use_pinecone = false;
2450 -
2451 - if ($pinecone_settings && is_array($pinecone_settings)) {
2452 - $use_pinecone = (
2453 - isset($pinecone_settings['mxchat_use_pinecone']) &&
2454 - $pinecone_settings['mxchat_use_pinecone'] === '1' &&
2455 - !empty($pinecone_settings['mxchat_pinecone_api_key']) &&
2456 - !empty($pinecone_settings['mxchat_pinecone_host']) &&
2457 - !empty($pinecone_settings['mxchat_pinecone_index']) &&
2458 - !empty($pinecone_settings['mxchat_pinecone_environment'])
2459 - );
2460 - }
2461 -
2462 - if ($use_pinecone) {
2463 - $this->delete_from_pinecone(
2464 - array($source_url),
2465 - $pinecone_settings['mxchat_pinecone_api_key'],
2466 - $pinecone_settings['mxchat_pinecone_environment'],
2467 - $pinecone_settings['mxchat_pinecone_index']
2468 - );
2469 - } else {
2470 - // Fallback to WordPress DB deletion
2471 - global $wpdb;
2472 - $table_name = $wpdb->prefix . 'mxchat_system_prompt_content';
2473 - $wpdb->delete($table_name, array('source_url' => $source_url), array('%s'));
2474 - }
2475 -}
2476 -
2477 -
2478 -/**
2479 - * Delete vectors from Pinecone by source URL
2480 - *
2481 - * @param array $urls Array of source URLs to delete
2482 - * @param string $api_key Pinecone API key
2483 - * @param string $environment Pinecone environment
2484 - * @param string $index_name Pinecone index name
2485 - * @return array Associative array with 'success' boolean and 'message' string
2486 - */
2487 -private function delete_from_pinecone($urls, $api_key, $environment, $index_name) {
2488 - // Get the Pinecone host from options (matching your store_in_pinecone_main pattern)
2489 - $options = get_option('mxchat_pinecone_addon_options');
2490 - $host = $options['mxchat_pinecone_host'] ?? '';
2491 -
2492 - if (empty($host)) {
2493 - return array(
2494 - 'success' => false,
2495 - 'message' => 'Pinecone host is not configured. Please set the host in your settings.'
2496 - );
2497 - }
2498 -
2499 - // Build API endpoint using the configured host
2500 - $api_endpoint = "https://{$host}/vectors/delete";
2501 -
2502 - // Create vector IDs from URLs (matching your store method's ID generation)
2503 - $vector_ids = array_map('md5', $urls);
2504 -
2505 - // Prepare the delete request body
2506 - $request_body = array(
2507 - 'ids' => $vector_ids,
2508 - 'filter' => array(
2509 - 'source_url' => array(
2510 - '$in' => $urls
2511 - )
2512 - )
2513 - );
2514 -
2515 - // Make the deletion request
2516 - $response = wp_remote_post($api_endpoint, array(
2517 - 'headers' => array(
2518 - 'Api-Key' => $api_key,
2519 - 'accept' => 'application/json',
2520 - 'content-type' => 'application/json'
2521 - ),
2522 - 'body' => wp_json_encode($request_body),
2523 - 'timeout' => 30,
2524 - 'data_format' => 'body'
2525 - ));
2526 -
2527 - // Handle WordPress HTTP API errors
2528 - if (is_wp_error($response)) {
2529 - return array(
2530 - 'success' => false,
2531 - 'message' => $response->get_error_message()
2532 - );
2533 - }
2534 -
2535 - // Check response status
2536 - $response_code = wp_remote_retrieve_response_code($response);
2537 - if ($response_code !== 200) {
2538 - $body = wp_remote_retrieve_body($response);
2539 - return array(
2540 - 'success' => false,
2541 - 'message' => sprintf(
2542 - 'Pinecone API error (HTTP %d): %s',
2543 - $response_code,
2544 - $body
2545 - )
2546 - );
2547 - }
2548 -
2549 - // Parse response body
2550 - $body = wp_remote_retrieve_body($response);
2551 - $response_data = json_decode($body, true);
2552 -
2553 - // Final validation of the response
2554 - if (json_last_error() !== JSON_ERROR_NONE) {
2555 - return array(
2556 - 'success' => false,
2557 - 'message' => 'Failed to parse Pinecone response: ' . json_last_error_msg()
2558 - );
2559 - }
2560 -
2561 - return array(
2562 - 'success' => true,
2563 - 'message' => sprintf('Successfully deleted %d vectors from Pinecone', count($vector_ids))
2564 - );
2565 -}
2566 -
2567 -
2568 -
2569 -
2570 -
2571 -public function mxchat_create_activation_page() {
2572 - $license_status = get_option('mxchat_license_status', 'inactive');
2573 - $license_error = get_option('mxchat_license_error', '');
2574 - ?>
2575 - <div class="wrap mxchat-admin-activation">
2576 - <div class="mxchat-pro-hero">
2577 - <h1 class="pro-title">
2578 - <span class="pro-gradient-text">Activate</span> MxChat Pro
2579 - </h1>
2580 - <p class="pro-subtitle">
2581 - <?php esc_html_e('Enter your license key to unlock premium features, advanced AI capabilities, and priority support.', 'mxchat'); ?>
2582 - </p>
2583 - </div>
2584 -
2585 - <?php if ($license_status === 'inactive' && !empty($license_error)): ?>
2586 - <div class="error notice">
2587 - <p><?php echo esc_html($license_error); ?></p>
2588 - </div>
2589 - <?php endif; ?>
2590 -
2591 - <form id="mxchat-activation-form" class="mxchat-pro-form" style="<?php echo $license_status === 'active' ? 'display: none;' : ''; ?>">
2592 - <div class="mxchat-pro-form-container">
613 + ?>
614 + <div class="wrap mxchat-admin">
615 + <h2>MxChat Pro: Activation</h2>
616 + <?php if ($license_status === 'inactive' && !empty($license_error)): ?>
617 + <div class="error notice">
618 + <p><?php echo esc_html($license_error); ?></p>
619 + </div>
620 + <?php endif; ?>
621 + <form id="mxchat-activation-form">
2593 622 <table class="form-table">
2594 623 <tr valign="top">
2595 - <th scope="row"><?php esc_html_e('Email Address', 'mxchat'); ?></th>
624 + <th scope="row">Email Address</th>
2596 625 <td>
2597 - <input type="email" id="mxchat_pro_email" name="mxchat_pro_email" value="<?php echo esc_attr(get_option('mxchat_pro_email')); ?>" class="regular-text mxchat-pro-input" required />
626 + <input type="email" id="mxchat_pro_email" name="mxchat_pro_email" value="<?php echo esc_attr(get_option('mxchat_pro_email')); ?>" class="regular-text" />
2598 627 </td>
2599 628 </tr>
2600 629 <tr valign="top">
2601 - <th scope="row"><?php esc_html_e('Activation Key', 'mxchat'); ?></th>
630 + <th scope="row">Activation Key</th>
2602 631 <td>
2603 - <input type="text" id="mxchat_activation_key" name="mxchat_activation_key" value="<?php echo esc_attr(get_option('mxchat_activation_key')); ?>" class="regular-text mxchat-pro-input" required />
632 + <input type="text" id="mxchat_activation_key" name="mxchat_activation_key" value="<?php echo esc_attr(get_option('mxchat_activation_key')); ?>" class="regular-text" />
2604 633 </td>
2605 634 </tr>
2606 635 </table>
2607 - <?php if ($license_status !== 'active'): ?>
2608 - <div class="mxchat-pro-button-container">
2609 - <button type="submit" id="activate_license_button" class="button button-primary mxchat-pro-button"><?php esc_html_e('Activate License', 'mxchat'); ?></button>
2610 - <div id="mxchat-activation-spinner" class="mxchat-activation-spinner" style="display: none;"></div>
2611 - </div>
2612 - <?php endif; ?>
2613 - </div>
2614 - </form>
2615 - <!-- License Status Display -->
2616 - <div class="mxchat-pro-status">
2617 - <h3><?php esc_html_e('License Status:', 'mxchat'); ?>
2618 - <span id="mxchat-license-status" class="mxchat-status-badge <?php echo $license_status; ?>">
2619 - <?php echo $license_status === 'active' ? esc_html__('Active', 'mxchat') : esc_html__('Inactive', 'mxchat'); ?>
2620 - </span>
2621 - </h3>
636 + <?php submit_button('Activate License', 'primary', 'activate_license'); ?>
637 + </form>
638 + <h3>License Status: <span id="mxchat-license-status"><?php echo $license_status === 'active' ? 'Active' : 'Inactive'; ?></span></h3>
2622 639 </div>
2623 -
2624 - </div>
2625 - <?php
2626 -}
2627 -
2628 -public function mxchat_intents_page_html() {
2629 - if (!current_user_can('manage_options')) {
2630 - return;
640 + <?php
2631 641 }
2632 642
2633 - // Keep existing data fetching logic
2634 - global $wpdb;
2635 - $table_name = $wpdb->prefix . 'mxchat_intents';
2636 - $page = isset($_GET['paged']) ? max(1, intval($_GET['paged'])) : 1;
2637 - $per_page = 20;
2638 - $offset = ($page - 1) * $per_page;
2639 643
2640 - // Success message
2641 - if (isset($_GET['updated']) && $_GET['updated'] === 'true') {
2642 - echo '<div class="notice notice-success is-dismissible"><p>' .
2643 - esc_html__('Intent updated successfully.', 'mxchat') .
2644 - '</p></div>';
2645 - }
2646 -
2647 - // Filtering logic
2648 - $where = '1=1';
2649 - $search_term = isset($_GET['s']) ? trim($_GET['s']) : '';
2650 - $callback_filter = isset($_GET['callback_filter']) ? sanitize_text_field($_GET['callback_filter']) : '';
2651 -
2652 - if ($search_term) {
2653 - $search_term_like = '%' . $wpdb->esc_like($search_term) . '%';
2654 - $where .= $wpdb->prepare(' AND (intent_label LIKE %s OR phrases LIKE %s)',
2655 - $search_term_like, $search_term_like);
2656 - }
2657 -
2658 - if ($callback_filter) {
2659 - $where .= $wpdb->prepare(' AND callback_function = %s', $callback_filter);
2660 - }
2661 -
2662 - // Pagination
2663 - $total_intents = $wpdb->get_var("SELECT COUNT(*) FROM $table_name WHERE $where");
2664 - $total_pages = ceil($total_intents / $per_page);
2665 -
2666 - // Get intents
2667 - $intents = $wpdb->get_results($wpdb->prepare(
2668 - "SELECT * FROM $table_name WHERE $where LIMIT %d OFFSET %d",
2669 - $per_page, $offset
2670 - ));
2671 -
2672 - // Get callbacks
2673 - $available_callbacks = $this->mxchat_get_available_callbacks();
2674 -
2675 - ?>
2676 - <div class="wrap mxchat-wrapper">
2677 - <!-- Hero Section -->
2678 - <div class="mxchat-hero">
2679 - <h1 class="mxchat-main-title">
2680 - <span class="mxchat-gradient-text">Intent</span> Manager
2681 - </h1>
2682 - <p class="mxchat-hero-subtitle">
2683 - <?php esc_html_e('Create and manage custom intents to enhance your chatbots understanding and response capabilities.', 'mxchat'); ?>
2684 - </p>
2685 - </div>
2686 -
2687 - <div class="mxchat-content">
2688 - <!-- Add Intent Card -->
2689 - <div class="mxchat-card">
2690 - <div class="mxchat-card-header">
2691 - <h2><?php esc_html_e('Add New Intent', 'mxchat'); ?></h2>
2692 - </div>
2693 -
2694 - <div class="mxchat-intent-documentation">
2695 - <p>
2696 - <?php esc_html_e('We highly encourage users to quickly read our ', 'mxchat'); ?>
2697 - <a href="https://mxchat.ai/documentation/#intents" target="_blank" rel="noopener noreferrer">
2698 - <?php esc_html_e('documentation', 'mxchat'); ?>
2699 - </a>
2700 - <?php esc_html_e(' to better understand intents. Some intents require setup in the Integration tab. If your intent is not triggering lower similarity threshold test.', 'mxchat'); ?>
2701 - </p>
2702 - </div>
2703 -
2704 - <form id="mxchat-add-intent-form" method="post"
2705 - action="<?php echo esc_url(admin_url('admin-post.php')); ?>">
2706 - <input type="hidden" name="action" value="mxchat_add_intent">
2707 - <?php wp_nonce_field('mxchat_add_intent_nonce'); ?>
2708 -
2709 - <div class="mxchat-form-group">
2710 - <label for="intent_label">
2711 - <?php esc_html_e('Intent Label (For your reference only)', 'mxchat'); ?>
2712 - </label>
2713 - <input name="intent_label" type="text" id="intent_label" required
2714 - class="mxchat-intent-input"
2715 - placeholder="<?php esc_attr_e('Example Email Capture: Newsletter Signup', 'mxchat'); ?>">
2716 - </div>
2717 -
2718 - <div class="mxchat-form-group">
2719 - <label for="phrases">
2720 - <?php esc_html_e('Phrases (comma-separated)', 'mxchat'); ?>
2721 - </label>
2722 - <textarea name="phrases" id="phrases" rows="5" required
2723 - class="mxchat-intent-textarea"
2724 - placeholder="<?php esc_attr_e('Example Email Capture: sign me up, subscribe me, I want to join, add me to the newsletter, send me updates, keep me informed', 'mxchat'); ?>"></textarea>
2725 - </div>
2726 -
2727 - <div class="mxchat-form-group">
2728 - <label for="callback_function">
2729 - <?php esc_html_e('Callback Function', 'mxchat'); ?>
2730 - </label>
2731 - <select name="callback_function" id="callback_function"
2732 - class="mxchat-intent-select" required>
2733 - <option value="">
2734 - <?php esc_html_e('Select a Callback', 'mxchat'); ?>
2735 - </option>
2736 - <?php
2737 - $groups = $this->mxchat_get_available_callbacks(true);
2738 - foreach ($groups as $group_label => $group_callbacks) :
2739 - echo '<optgroup label="' . esc_attr($group_label) . '">';
2740 - foreach ($group_callbacks as $function => $data) :
2741 - $label = $data['label'];
2742 - $pro_only = $data['pro_only'];
2743 - $disabled = (!$this->is_activated && $pro_only) ? 'disabled' : '';
2744 - $label_suffix = (!$this->is_activated && $pro_only) ? ' (Pro Only)' : '';
2745 - ?>
2746 - <option value="<?php echo esc_attr($function); ?>"
2747 - <?php echo $disabled; ?>>
2748 - <?php echo esc_html($label . $label_suffix); ?>
2749 - </option>
2750 - <?php
2751 - endforeach;
2752 - echo '</optgroup>';
2753 - endforeach;
2754 - ?>
2755 - </select>
2756 - </div>
2757 -
2758 - <button type="submit" class="mxchat-button-primary">
2759 - <?php esc_html_e('Add Intent', 'mxchat'); ?>
2760 - </button>
2761 - </form>
2762 - </div>
2763 -
2764 - <!-- Manage Intents Card -->
2765 - <div class="mxchat-card">
2766 - <div class="mxchat-card-header">
2767 - <h2><?php esc_html_e('Manage Intents', 'mxchat'); ?></h2>
2768 - <div class="mxchat-header-actions">
2769 - <form method="get" class="mxchat-search-form">
2770 - <input type="hidden" name="page" value="mxchat-intents">
2771 - <div class="mxchat-search-group">
2772 - <span class="dashicons dashicons-search"></span>
2773 - <input type="text" name="s"
2774 - placeholder="<?php esc_attr_e('Search Intents', 'mxchat'); ?>"
2775 - value="<?php echo esc_attr($search_term); ?>">
2776 - <select name="callback_filter" class="mxchat-intent-filter">
2777 - <option value="">
2778 - <?php esc_html_e('All Callbacks', 'mxchat'); ?>
2779 - </option>
2780 - <?php foreach ($available_callbacks as $function => $callback_data) :
2781 - $label = $callback_data['label']; ?>
2782 - <option value="<?php echo esc_attr($function); ?>"
2783 - <?php selected($callback_filter, $function); ?>>
2784 - <?php echo esc_html($label); ?>
2785 - </option>
2786 - <?php endforeach; ?>
2787 - </select>
2788 - <button type="submit" class="mxchat-button-secondary">
2789 - <?php esc_html_e('Filter', 'mxchat'); ?>
2790 - </button>
2791 - </div>
2792 - </form>
2793 - </div>
2794 - </div>
2795 -
2796 - <div class="mxchat-table-wrapper">
2797 - <table class="mxchat-records-table">
2798 - <thead>
2799 - <tr>
2800 - <th><?php esc_html_e('Intent Label', 'mxchat'); ?></th>
2801 - <th><?php esc_html_e('Phrases', 'mxchat'); ?></th>
2802 - <th><?php esc_html_e('Callback Function', 'mxchat'); ?></th>
2803 - <th><?php esc_html_e('Similarity Threshold', 'mxchat'); ?></th>
2804 - <th><?php esc_html_e('Actions', 'mxchat'); ?></th>
2805 - </tr>
2806 - </thead>
2807 - <tbody>
2808 - <?php if ($intents) :
2809 - foreach ($intents as $intent) :
2810 - $callback_function = $intent->callback_function;
2811 - $callback_label = isset($available_callbacks[$callback_function]['label'])
2812 - ? $available_callbacks[$callback_function]['label']
2813 - : $callback_function;
2814 - $threshold_value = isset($intent->similarity_threshold)
2815 - ? round($intent->similarity_threshold * 100)
2816 - : 85;
2817 -
2818 - // Check if this is a form intent (its intent_label starts with "Form ")
2819 - $is_form_intent = strpos($intent->intent_label, 'Form ') === 0;
2820 - ?>
2821 - <tr<?php echo $is_form_intent ? ' class="mxchat-form-intent"' : ''; ?>>
2822 - <td>
2823 - <?php
2824 - if ($is_form_intent) {
2825 - // Attempt to extract the form ID from the intent_label.
2826 - preg_match('/Form (\d+)/', $intent->intent_label, $matches);
2827 - $form_id = isset($matches[1]) ? intval($matches[1]) : 0;
2828 - if ($form_id) {
2829 - global $wpdb;
2830 - $forms_table = $wpdb->prefix . 'mxchat_forms';
2831 - $form = $wpdb->get_row($wpdb->prepare("SELECT title FROM $forms_table WHERE id = %d", $form_id));
2832 - if ($form && !empty($form->title)) {
2833 - echo esc_html($form->title);
2834 - } else {
2835 - echo esc_html($intent->intent_label);
2836 - }
2837 - } else {
2838 - echo esc_html($intent->intent_label);
2839 - }
2840 - echo ' <span class="mxchat-badge">Form Intent</span>';
2841 - } else {
2842 - echo esc_html($intent->intent_label);
2843 - }
2844 - ?>
2845 - </td>
2846 - <td class="mxchat-content-cell">
2847 - <?php echo esc_html($intent->phrases); ?>
2848 - </td>
2849 - <td><?php echo esc_html($callback_label); ?></td>
2850 - <td>
2851 - <!-- Similarity threshold adjustment (shown for all intents) -->
2852 - <form method="post"
2853 - action="<?php echo esc_url(admin_url('admin-post.php')); ?>"
2854 - class="mxchat-threshold-form">
2855 - <?php wp_nonce_field('mxchat_update_intent_threshold_nonce'); ?>
2856 - <input type="hidden" name="action"
2857 - value="mxchat_update_intent_threshold">
2858 - <input type="hidden" name="intent_id"
2859 - value="<?php echo esc_attr($intent->id); ?>">
2860 - <div class="mxchat-slider-group">
2861 - <input type="range"
2862 - name="intent_threshold"
2863 - id="intent_threshold_<?php echo esc_attr($intent->id); ?>"
2864 - min="70"
2865 - max="95"
2866 - value="<?php echo esc_attr($threshold_value); ?>"
2867 - class="mxchat-intent-slider"
2868 - oninput="document.getElementById('threshold_output_<?php echo esc_attr($intent->id); ?>').value = this.value + '%'">
2869 - <output id="threshold_output_<?php echo esc_attr($intent->id); ?>"
2870 - class="mxchat-intent-output">
2871 - <?php echo esc_html($threshold_value); ?>%
2872 - </output>
2873 - </div>
2874 - <button type="submit" class="mxchat-button-icon">
2875 - <span class="dashicons dashicons-saved"></span>
2876 - </button>
2877 - </form>
2878 - </td>
2879 - <td class="mxchat-actions-cell">
2880 - <?php if (!$is_form_intent) : ?>
2881 - <!-- Standard intents: allow edit and delete -->
2882 - <button type="button"
2883 - class="mxchat-button-icon mxchat-edit-button"
2884 - data-intent-id="<?php echo esc_attr($intent->id); ?>"
2885 - data-phrases="<?php echo esc_attr($intent->phrases); ?>">
2886 - <span class="dashicons dashicons-edit"></span>
2887 - </button>
2888 - <form method="post"
2889 - action="<?php echo esc_url(admin_url('admin-post.php')); ?>"
2890 - class="mxchat-delete-form"
2891 - onsubmit="return confirm('<?php esc_attr_e('Are you sure you want to delete this intent?', 'mxchat'); ?>');">
2892 - <?php wp_nonce_field('mxchat_delete_intent_nonce'); ?>
2893 - <input type="hidden" name="action" value="mxchat_delete_intent">
2894 - <input type="hidden" name="intent_id"
2895 - value="<?php echo esc_attr($intent->id); ?>">
2896 - <button type="submit" class="mxchat-button-icon">
2897 - <span class="dashicons dashicons-trash"></span>
2898 - </button>
2899 - </form>
2900 - <?php else : ?>
2901 - <!-- Form intents: show manage in forms button -->
2902 - <?php
2903 - preg_match('/Form (\d+)/', $intent->intent_label, $matches);
2904 - $form_id = isset($matches[1]) ? $matches[1] : '';
2905 - ?>
2906 - <a href="<?php echo esc_url(admin_url('admin.php?page=mxchat-forms&action=edit&form_id=' . $form_id)); ?>"
2907 - class="mxchat-button-secondary">
2908 - <?php esc_html_e('Manage in Forms', 'mxchat'); ?>
2909 - </a>
2910 - <?php endif; ?>
2911 - </td>
2912 - </tr>
2913 - <?php endforeach;
2914 - else : ?>
2915 - <tr>
2916 - <td colspan="5" class="mxchat-no-records">
2917 - <?php esc_html_e('No intents found.', 'mxchat'); ?>
2918 - </td>
2919 - </tr>
2920 - <?php endif; ?>
2921 - </tbody>
2922 - </table>
2923 - </div>
2924 -
2925 - <?php if ($total_pages > 1) : ?>
2926 - <div class="mxchat-pagination">
2927 - <?php
2928 - echo paginate_links(array(
2929 - 'base' => add_query_arg('paged', '%#%'),
2930 - 'format' => '',
2931 - 'prev_text' => __('&laquo; Previous', 'mxchat'),
2932 - 'next_text' => __('Next &raquo;', 'mxchat'),
2933 - 'total' => $total_pages,
2934 - 'current' => $page
2935 - ));
2936 - ?>
2937 - </div>
2938 - <?php endif; ?>
2939 - </div>
2940 - </div>
2941 -
2942 - <!-- Edit Modal -->
2943 -<div id="mxchat-edit-modal" class="mxchat-modal" style="display: none;">
2944 - <div class="mxchat-modal-content">
2945 - <span class="mxchat-modal-close">&times;</span>
2946 - <div class="mxchat-card-header">
2947 - <h2><?php esc_html_e('Edit Intent Phrases', 'mxchat'); ?></h2>
2948 - </div>
2949 -
2950 - <form id="mxchat-edit-intent-form" method="post"
2951 - action="<?php echo esc_url(admin_url('admin-post.php')); ?>">
2952 - <?php wp_nonce_field('mxchat_edit_intent_nonce'); ?>
2953 - <input type="hidden" name="action" value="mxchat_edit_intent">
2954 - <input type="hidden" name="intent_id" id="edit_intent_id">
2955 -
2956 - <div class="mxchat-form-group">
2957 - <label for="edit_phrases">
2958 - <?php esc_html_e('Phrases (comma-separated)', 'mxchat'); ?>
2959 - </label>
2960 - <textarea name="phrases"
2961 - id="edit_phrases"
2962 - rows="5"
2963 - class="mxchat-intent-textarea"
2964 - required></textarea>
2965 - </div>
2966 -
2967 - <div class="mxchat-modal-actions">
2968 - <button type="submit" class="mxchat-button-primary">
2969 - <?php esc_html_e('Update Phrases', 'mxchat'); ?>
2970 - </button>
2971 - <button type="button" class="mxchat-button-secondary mxchat-modal-cancel">
2972 - <?php esc_html_e('Cancel', 'mxchat'); ?>
2973 - </button>
2974 - </div>
2975 - </form>
2976 - </div>
2977 -</div>
2978 -
2979 - </div><!-- .mxchat-content -->
2980 - </div><!-- .mxchat-wrapper -->
2981 -
2982 - <div id="mxchat-intent-loading" class="mxchat-intent-loading" style="display: none;">
2983 - <div class="mxchat-intent-loading-spinner"></div>
2984 - <div class="mxchat-intent-loading-text">
2985 - <?php esc_html_e('Saving intent, please wait...', 'mxchat'); ?>
2986 - </div>
2987 - </div>
2988 -<?php
2989 -}
2990 -
2991 -
2992 -
2993 -/**
2994 - * Handle editing of intent phrases
2995 - *
2996 - * @since 1.0.0
2997 - * @return void
2998 - */
2999 -public function handle_edit_intent() {
3000 - // Verify nonce and user capabilities
3001 - if (!isset($_POST['_wpnonce']) || !wp_verify_nonce($_POST['_wpnonce'], 'mxchat_edit_intent_nonce')) {
3002 - wp_die(esc_html__('Security check failed.', 'mxchat'));
3003 - }
3004 -
3005 - if (!current_user_can('manage_options')) {
3006 - wp_die(esc_html__('You do not have permission to perform this action.', 'mxchat'));
3007 - }
3008 -
3009 - // Validate and sanitize input
3010 - $intent_id = isset($_POST['intent_id']) ? absint($_POST['intent_id']) : 0;
3011 - if (!$intent_id) {
3012 - wp_die(esc_html__('Invalid intent ID.', 'mxchat'));
3013 - }
3014 -
3015 - $phrases_input = isset($_POST['phrases']) ? sanitize_textarea_field($_POST['phrases']) : '';
3016 - if (empty($phrases_input)) {
3017 - wp_die(esc_html__('Phrases cannot be empty.', 'mxchat'));
3018 - }
3019 -
3020 - // Process phrases the same way as in intent creation
3021 - $phrases_array = array_map('sanitize_text_field', array_filter(array_map('trim', explode(',', $phrases_input))));
3022 -
3023 - if (empty($phrases_array)) {
3024 - wp_die(esc_html__('Please enter at least one valid phrase.', 'mxchat'));
3025 - }
3026 -
3027 - // Generate embeddings and combine them
3028 - $vectors = [];
3029 - foreach ($phrases_array as $phrase) {
3030 - $embedding_vector = $this->mxchat_generate_embedding($phrase, $this->options['api_key']);
3031 - if (is_array($embedding_vector)) {
3032 - $vectors[] = $embedding_vector;
3033 - } else {
3034 - wp_die(esc_html__('Error generating embedding for phrase: ', 'mxchat') . esc_html($phrase));
3035 - }
3036 - }
3037 -
3038 - if (empty($vectors)) {
3039 - wp_die(esc_html__('No valid embeddings generated. Please check your phrases.', 'mxchat'));
3040 - }
3041 -
3042 - // Create combined vector just like in intent creation
3043 - $combined_vector = $this->mxchat_average_vectors($vectors);
3044 - $serialized_vector = maybe_serialize($combined_vector);
3045 -
3046 - global $wpdb;
3047 - $table_name = $wpdb->prefix . 'mxchat_intents';
3048 -
3049 - // Update the intent with both new phrases and the combined vector
3050 - $result = $wpdb->update(
3051 - $table_name,
3052 - array(
3053 - 'phrases' => implode(', ', $phrases_array),
3054 - 'embedding_vector' => $serialized_vector
3055 - ),
3056 - array('id' => $intent_id),
3057 - array('%s', '%s'),
3058 - array('%d')
3059 - );
3060 -
3061 - if (false === $result) {
3062 - wp_die(esc_html__('Failed to update intent.', 'mxchat'));
3063 - }
3064 -
3065 - // Redirect back to the intents page with a success message
3066 - $redirect_url = add_query_arg(
3067 - array(
3068 - 'page' => 'mxchat-intents',
3069 - 'updated' => 'true'
3070 - ),
3071 - admin_url('admin.php')
3072 - );
3073 -
3074 - wp_safe_redirect($redirect_url);
3075 - exit;
3076 -}
3077 -public function mxchat_handle_update_intent_threshold() {
3078 - if ( ! current_user_can( 'manage_options' ) ) {
3079 - wp_die( esc_html__('Unauthorized user', 'mxchat') );
3080 - }
3081 -
3082 - check_admin_referer('mxchat_update_intent_threshold_nonce');
3083 -
3084 - if (isset($_POST['intent_id'], $_POST['intent_threshold'])) {
3085 - global $wpdb;
3086 - $table_name = $wpdb->prefix . 'mxchat_intents';
3087 - $intent_id = intval($_POST['intent_id']);
3088 - $threshold_percentage = max(70, min(95, intval($_POST['intent_threshold'])));
3089 - $similarity_threshold = $threshold_percentage / 100;
3090 -
3091 - $wpdb->update(
3092 - $table_name,
3093 - ['similarity_threshold' => $similarity_threshold],
3094 - ['id' => $intent_id],
3095 - ['%f'],
3096 - ['%d']
3097 - );
3098 - }
3099 -
3100 - wp_safe_redirect(admin_url('admin.php?page=mxchat-intents'));
3101 - exit;
3102 -}
3103 -
3104 -public function mxchat_handle_add_intent() {
3105 - if ( ! current_user_can( 'manage_options' ) ) {
3106 - wp_die( esc_html__('Unauthorized user', 'mxchat') );
3107 - }
3108 -
3109 - check_admin_referer('mxchat_add_intent_nonce');
3110 -
3111 - global $wpdb;
3112 - $table_name = $wpdb->prefix . 'mxchat_intents';
3113 -
3114 - $intent_label = isset($_POST['intent_label']) ? sanitize_text_field($_POST['intent_label']) : '';
3115 - $phrases_input = isset($_POST['phrases']) ? sanitize_textarea_field($_POST['phrases']) : '';
3116 - $callback_function = isset($_POST['callback_function']) ? sanitize_text_field($_POST['callback_function']) : '';
3117 - $default_threshold = 0.85;
3118 -
3119 - if (empty($intent_label) || empty($callback_function) || empty($phrases_input)) {
3120 - wp_die( esc_html__('Invalid input. Please ensure all fields are filled out.', 'mxchat') );
3121 - }
3122 -
3123 - $available_callbacks = $this->mxchat_get_available_callbacks();
3124 -
3125 - if (!array_key_exists($callback_function, $available_callbacks)) {
3126 - wp_die( esc_html__('Invalid callback function selected.', 'mxchat') );
3127 - }
3128 -
3129 - $is_pro_only = $available_callbacks[$callback_function]['pro_only'];
3130 - if ($is_pro_only && !$this->is_activated) {
3131 - wp_die( esc_html__('This callback function is available in the Pro version only.', 'mxchat') );
3132 - }
3133 -
3134 - $phrases_array = array_map('sanitize_text_field', array_filter(array_map('trim', explode(',', $phrases_input))));
3135 -
3136 - if (empty($phrases_array)) {
3137 - wp_die( esc_html__('Please enter at least one valid phrase.', 'mxchat') );
3138 - }
3139 -
3140 - $vectors = [];
3141 - foreach ($phrases_array as $phrase) {
3142 - $embedding_vector = $this->mxchat_generate_embedding($phrase, $this->options['api_key']);
3143 - if (is_array($embedding_vector)) {
3144 - $vectors[] = $embedding_vector;
3145 - } else {
3146 - wp_die( esc_html__('Error generating embedding for phrase: ', 'mxchat') . esc_html($phrase) );
3147 - }
3148 - }
3149 -
3150 - if (!empty($vectors)) {
3151 - $combined_vector = $this->mxchat_average_vectors($vectors);
3152 - $serialized_vector = maybe_serialize($combined_vector);
3153 -
3154 - $result = $wpdb->insert($table_name, [
3155 - 'intent_label' => $intent_label,
3156 - 'phrases' => implode(', ', $phrases_array),
3157 - 'embedding_vector' => $serialized_vector,
3158 - 'callback_function' => $callback_function,
3159 - 'similarity_threshold' => $default_threshold,
3160 - ]);
3161 -
3162 - if ($result === false) {
3163 - wp_die( esc_html__('Database error: ', 'mxchat') . esc_html($wpdb->last_error) );
3164 - }
3165 - } else {
3166 - wp_die( esc_html__('No valid embeddings generated. Please check your phrases.', 'mxchat') );
3167 - }
3168 -
3169 - wp_safe_redirect(admin_url('admin.php?page=mxchat-intents'));
3170 - exit;
3171 -}
3172 -
3173 -
3174 -
3175 -
3176 -
3177 -
3178 -private function mxchat_get_available_callbacks($grouped = false) {
3179 - $callbacks = [
3180 - 'mxchat_handle_email_capture' => [
3181 - 'label' => __('Email Capture', 'mxchat'),
3182 - 'pro_only' => false,
3183 - 'group' => __('Customer Engagement', 'mxchat'),
3184 - ],
3185 - 'mxchat_generate_image' => [
3186 - 'label' => __('Generate Image', 'mxchat'),
3187 - 'pro_only' => true,
3188 - 'group' => __('Other Features', 'mxchat'),
3189 - ],
3190 - 'mxchat_handle_search_request' => [
3191 - 'label' => __('Brave Web Search', 'mxchat'),
3192 - 'pro_only' => false,
3193 - 'group' => __('Search Features', 'mxchat'),
3194 - ],
3195 - 'mxchat_handle_image_search_request' => [
3196 - 'label' => __('Brave Image Search', 'mxchat'),
3197 - 'pro_only' => false,
3198 - 'group' => __('Search Features', 'mxchat'),
3199 - ],
3200 - 'mxchat_handle_pdf_discussion' => [
3201 - 'label' => __('Chat with PDF', 'mxchat'),
3202 - 'pro_only' => true,
3203 - 'group' => __('Other Features', 'mxchat'),
3204 - ],
3205 - 'mxchat_live_agent_handover' => [
3206 - 'label' => __('Live Agent', 'mxchat'),
3207 - 'pro_only' => true,
3208 - 'group' => __('Customer Engagement', 'mxchat'),
3209 - ],
3210 - 'mxchat_handle_switch_to_chatbot_intent' => [
3211 - 'label' => __('Back to Chatbot', 'mxchat'),
3212 - 'pro_only' => true,
3213 - 'group' => __('Customer Engagement', 'mxchat'),
3214 - ],
3215 - ];
3216 -
3217 - // Allow other plugins to add their callbacks
3218 - $callbacks = apply_filters('mxchat_available_callbacks', $callbacks);
3219 -
3220 - // Return grouped structure if requested
3221 - if ($grouped) {
3222 - $grouped_callbacks = [];
3223 - foreach ($callbacks as $key => $data) {
3224 - $group_label = $data['group'] ?? __('Other Features', 'mxchat');
3225 - $grouped_callbacks[$group_label][$key] = [
3226 - 'label' => $data['label'],
3227 - 'pro_only' => $data['pro_only'],
3228 - ];
3229 - }
3230 - return $grouped_callbacks;
3231 - }
3232 - return $callbacks;
3233 -}
3234 -
3235 -
3236 -private function mxchat_average_vectors($vectors) {
3237 - $vector_length = count($vectors[0]);
3238 - $sum_vector = array_fill(0, $vector_length, 0);
3239 -
3240 - foreach ($vectors as $vector) {
3241 - for ($i = 0; $i < $vector_length; $i++) {
3242 - $sum_vector[$i] += $vector[$i];
3243 - }
3244 - }
3245 -
3246 - // Divide each component by the number of vectors to get the average
3247 - $num_vectors = count($vectors);
3248 - for ($i = 0; $i < $vector_length; $i++) {
3249 - $sum_vector[$i] /= $num_vectors;
3250 - }
3251 -
3252 - return $sum_vector;
3253 -}
3254 -
3255 -public function mxchat_handle_delete_intent() {
3256 - if ( ! current_user_can( 'manage_options' ) ) {
3257 - wp_die( esc_html__('Unauthorized user', 'mxchat') );
3258 - }
3259 -
3260 - check_admin_referer('mxchat_delete_intent_nonce');
3261 -
3262 - if (isset($_POST['intent_id'])) {
3263 - global $wpdb;
3264 - $table_name = $wpdb->prefix . 'mxchat_intents';
3265 - $intent_id = intval($_POST['intent_id']);
3266 -
3267 - $wpdb->delete($table_name, ['id' => $intent_id], ['%d']);
3268 - }
3269 -
3270 - wp_safe_redirect(admin_url('admin.php?page=mxchat-intents'));
3271 - exit;
3272 -}
3273 -
3274 -
3275 644 public function mxchat_page_init() {
3276 645 // Register settings
3277 646 register_setting(
3278 - 'mxchat_option_group',
3279 - 'mxchat_options',
3280 - array($this, 'mxchat_sanitize')
647 + 'mxchat_option_group',
648 + 'mxchat_options',
649 + array($this, 'mxchat_sanitize')
3281 650 );
3282 651
3283 - register_setting(
3284 - 'mxchat_option_group',
3285 - 'mxchat_similarity_threshold',
3286 - array(
3287 - 'type' => 'number',
3288 - 'sanitize_callback' => function($value) {
3289 - $value = absint($value); // Ensure it's an integer
3290 - return min(max($value, 70), 85); // Enforce range
3291 - },
3292 - 'default' => 80,
3293 - )
3294 - );
3295 -
3296 652 // Chatbot Settings Section
3297 653 add_settings_section(
3298 - 'mxchat_chatbot_section',
3299 - esc_html__('Chatbot Settings', 'mxchat'),
3300 - null,
3301 - 'mxchat-chatbot'
654 + 'mxchat_chatbot_section',
655 + 'Chatbot Settings',
656 + null,
657 + 'mxchat-chatbot'
3302 658 );
3303 659
3304 - // Similarity Threshold Slider
660 + // Registering fields for the Chatbot Settings section
3305 661 add_settings_field(
3306 - 'similarity_threshold', // Field ID
3307 - esc_html__('Similarity Threshold', 'mxchat'), // Field title
3308 - array($this, 'mxchat_similarity_threshold_callback'), // Callback function
3309 - 'mxchat-chatbot', // Page
3310 - 'mxchat_chatbot_section' // Section
662 + 'api_key',
663 + 'API Key',
664 + array($this, 'api_key_callback'),
665 + 'mxchat-chatbot',
666 + 'mxchat_chatbot_section'
3311 667 );
3312 668
3313 669 add_settings_field(
3314 - 'append_to_body',
3315 - esc_html__('Auto-Display Chatbot', 'mxchat'),
3316 - array($this, 'mxchat_append_to_body_callback'),
3317 - 'mxchat-chatbot',
3318 - 'mxchat_chatbot_section'
3319 - );
3320 -
3321 -
3322 - // Existing fields...
3323 - add_settings_field(
3324 - 'api_key',
3325 - esc_html__('OpenAI API Key', 'mxchat'),
3326 - array($this, 'api_key_callback'),
3327 - 'mxchat-chatbot',
3328 - 'mxchat_chatbot_section'
3329 - );
3330 -
3331 - add_settings_field(
3332 - 'xai_api_key',
3333 - esc_html__('X.AI API Key', 'mxchat'),
3334 - array($this, 'xai_api_key_callback'),
3335 - 'mxchat-chatbot',
3336 - 'mxchat_chatbot_section'
3337 - );
3338 -
3339 - add_settings_field(
3340 - 'claude_api_key',
3341 - esc_html__('Claude API Key', 'mxchat'),
3342 - array($this, 'claude_api_key_callback'),
3343 - 'mxchat-chatbot',
3344 - 'mxchat_chatbot_section'
3345 - );
3346 -
3347 - add_settings_field(
3348 - 'deepseek_api_key',
3349 - esc_html__('DeepSeek API Key', 'mxchat'),
3350 - array($this, 'deepseek_api_key_callback'),
3351 - 'mxchat-chatbot',
3352 - 'mxchat_chatbot_section'
3353 - );
3354 -
3355 - add_settings_field(
3356 670 'system_prompt_instructions',
3357 - esc_html__('AI Instructions (Behavior)', 'mxchat'),
671 + 'AI Instructions',
3358 672 array($this, 'system_prompt_instructions_callback'),
3359 673 'mxchat-chatbot',
3360 674 'mxchat_chatbot_section'
3361 675 );
@@ -3361,9 +675,9 @@
3361 675 );
3362 676
3363 677 add_settings_field(
3364 678 'model',
3365 - esc_html__('Model', 'mxchat'),
679 + 'Model',
3366 680 array($this, 'mxchat_model_callback'),
3367 681 'mxchat-chatbot',
3368 682 'mxchat_chatbot_section'
3369 683 );
@@ -3369,9 +683,9 @@
3369 683 );
3370 684
3371 685 add_settings_field(
3372 686 'top_bar_title',
3373 - esc_html__('Top Bar Title', 'mxchat'),
687 + 'Top Bar Title',
3374 688 array($this, 'mxchat_top_bar_title_callback'),
3375 689 'mxchat-chatbot',
3376 690 'mxchat_chatbot_section'
3377 691 );
@@ -3376,34 +690,10 @@
3376 690 'mxchat_chatbot_section'
3377 691 );
3378 692
3379 693 add_settings_field(
3380 - 'enable_email_block',
3381 - esc_html__('Require Email To Chat', 'mxchat'),
3382 - array($this, 'enable_email_block_callback'),
3383 - 'mxchat-chatbot',
3384 - 'mxchat_chatbot_section'
3385 - );
3386 -
3387 - add_settings_field(
3388 - 'email_blocker_header_content',
3389 - esc_html__('Require Email Chat Content', 'mxchat'),
3390 - array($this, 'email_blocker_header_content_callback'),
3391 - 'mxchat-chatbot',
3392 - 'mxchat_chatbot_section'
3393 - );
3394 -
3395 - add_settings_field(
3396 - 'email_blocker_button_text',
3397 - esc_html__('Require Email Chat Button Text', 'mxchat'),
3398 - [$this, 'email_blocker_button_text_callback'],
3399 - 'mxchat-chatbot',
3400 - 'mxchat_chatbot_section'
3401 - );
3402 -
3403 - add_settings_field(
3404 694 'intro_message',
3405 - esc_html__('Introductory Message', 'mxchat'),
695 + 'Introductory Message',
3406 696 array($this, 'mxchat_intro_message_callback'),
3407 697 'mxchat-chatbot',
3408 698 'mxchat_chatbot_section'
3409 699 );
@@ -3408,34 +698,18 @@
3408 698 'mxchat_chatbot_section'
3409 699 );
3410 700
3411 701 add_settings_field(
3412 - 'input_copy',
3413 - esc_html__('Input Copy', 'mxchat'),
3414 - array($this, 'mxchat_input_copy_callback'),
702 + 'rate_limit',
703 + 'Rate Limit',
704 + array($this, 'mxchat_rate_limit_callback'),
3415 705 'mxchat-chatbot',
3416 706 'mxchat_chatbot_section'
3417 707 );
3418 708
3419 709 add_settings_field(
3420 - 'rate_limit_logged_out',
3421 - __('Rate Limit for Logged-out Users', 'mxchat'),
3422 - array($this, 'mxchat_rate_limit_logged_out_callback'),
3423 - 'mxchat-chatbot',
3424 - 'mxchat_chatbot_section'
3425 - );
3426 -
3427 - add_settings_field(
3428 - 'rate_limit_roles',
3429 - __('Rate Limits by User Role', 'mxchat'),
3430 - array($this, 'mxchat_rate_limit_roles_callback'),
3431 - 'mxchat-chatbot',
3432 - 'mxchat_chatbot_section'
3433 - );
3434 -
3435 - add_settings_field(
3436 710 'rate_limit_message',
3437 - esc_html__('Rate Limit Message', 'mxchat'),
711 + 'Rate Limit Message',
3438 712 array($this, 'mxchat_rate_limit_message_callback'),
3439 713 'mxchat-chatbot',
3440 714 'mxchat_chatbot_section'
3441 715 );
@@ -3441,538 +715,266 @@
3441 715 );
3442 716
3443 717 add_settings_field(
3444 718 'pre_chat_message',
3445 - esc_html__('Chat Teaser Pop-up', 'mxchat'),
719 + 'Pre-Chat Message',
3446 720 array($this, 'mxchat_pre_chat_message_callback'),
3447 721 'mxchat-chatbot',
3448 722 'mxchat_chatbot_section'
3449 723 );
3450 -
3451 - add_settings_field(
3452 - 'privacy_toggle',
3453 - esc_html__('Toggle Privacy Notice', 'mxchat'),
3454 - array($this, 'mxchat_privacy_toggle_callback'),
724 +
725 + add_settings_field(
726 + 'append_to_body',
727 + 'Append Chat Widget to Body',
728 + array($this, 'mxchat_append_to_body_callback'),
3455 729 'mxchat-chatbot',
3456 730 'mxchat_chatbot_section'
3457 731 );
3458 732
3459 - add_settings_field(
3460 - 'complianz_toggle',
3461 - esc_html__('Enable Complianz', 'mxchat'),
3462 - array($this, 'mxchat_complianz_toggle_callback'),
3463 - 'mxchat-chatbot',
3464 - 'mxchat_chatbot_section'
3465 - );
3466 -
3467 - add_settings_field(
3468 - 'link_target_toggle',
3469 - esc_html__('Open Links in a New Tab', 'mxchat'),
3470 - array($this, 'mxchat_link_target_toggle_callback'),
3471 - 'mxchat-chatbot',
3472 - 'mxchat_chatbot_section'
3473 - );
3474 -
3475 - add_settings_field(
3476 - 'chat_persistence_toggle',
3477 - esc_html__('Enable Chat Persistence', 'mxchat'),
3478 - array($this, 'mxchat_chat_persistence_toggle_callback'),
3479 - 'mxchat-chatbot',
3480 - 'mxchat_chatbot_section'
3481 - );
3482 -
3483 - add_settings_field(
3484 - 'popular_question_1',
3485 - esc_html__('Quick Question 1', 'mxchat'),
3486 - array($this, 'mxchat_popular_question_1_callback'),
3487 - 'mxchat-chatbot',
3488 - 'mxchat_chatbot_section'
3489 - );
3490 -
3491 - add_settings_field(
3492 - 'popular_question_2',
3493 - esc_html__('Quick Question 2', 'mxchat'),
3494 - array($this, 'mxchat_popular_question_2_callback'),
3495 - 'mxchat-chatbot',
3496 - 'mxchat_chatbot_section'
3497 - );
3498 -
3499 - add_settings_field(
3500 - 'popular_question_3',
3501 - esc_html__('Quick Question 3', 'mxchat'),
3502 - array($this, 'mxchat_popular_question_3_callback'),
3503 - 'mxchat-chatbot',
3504 - 'mxchat_chatbot_section'
3505 - );
3506 -
3507 - add_settings_field(
3508 - 'additional_popular_questions',
3509 - esc_html__('Additional Quick Questions', 'mxchat'),
3510 - array($this, 'mxchat_additional_popular_questions_callback'),
3511 - 'mxchat-chatbot',
3512 - 'mxchat_chatbot_section'
3513 - );
3514 -
3515 -
3516 - // Loops Settings Section
733 + // Embed Settings Section
3517 734 add_settings_section(
3518 - 'mxchat_loops_section',
3519 - esc_html__('Loops Settings', 'mxchat'),
3520 - null,
735 + 'mxchat_embed_section',
736 + 'Embed Settings',
737 + null,
3521 738 'mxchat-embed'
3522 739 );
3523 740
3524 - // Loops Settings Fields
3525 741 add_settings_field(
3526 - 'loops_api_key',
3527 - esc_html__('Loops API Key', 'mxchat'),
3528 - array($this, 'mxchat_loops_api_key_callback'),
742 + 'enable_woocommerce_integration',
743 + 'Enable WooCommerce Integration',
744 + array($this, 'mxchat_enable_woocommerce_integration_callback'),
3529 745 'mxchat-embed',
3530 - 'mxchat_loops_section'
746 + 'mxchat_embed_section'
3531 747 );
3532 748
3533 749 add_settings_field(
3534 - 'loops_mailing_list',
3535 - esc_html__('Loops Mailing List', 'mxchat'),
3536 - array($this, 'mxchat_loops_mailing_list_callback'),
750 + 'woocommerce_consumer_key',
751 + 'WooCommerce Consumer Key',
752 + array($this, 'mxchat_woocommerce_consumer_key_callback'),
3537 753 'mxchat-embed',
3538 - 'mxchat_loops_section'
754 + 'mxchat_embed_section'
3539 755 );
3540 756
3541 757 add_settings_field(
3542 - 'triggered_phrase_response',
3543 - esc_html__('Triggered Phrase Response', 'mxchat'),
3544 - array($this, 'mxchat_triggered_phrase_response_callback'),
758 + 'woocommerce_consumer_secret',
759 + 'WooCommerce Consumer Secret',
760 + array($this, 'mxchat_woocommerce_consumer_secret_callback'),
3545 761 'mxchat-embed',
3546 - 'mxchat_loops_section'
762 + 'mxchat_embed_section'
3547 763 );
3548 764
3549 - add_settings_field(
3550 - 'email_capture_response',
3551 - esc_html__('Email Capture Response', 'mxchat'),
3552 - array($this, 'mxchat_email_capture_response_callback'),
3553 - 'mxchat-embed',
3554 - 'mxchat_loops_section'
3555 - );
3556 -
3557 - // Brave Search Settings Fields
765 + // Theme Settings Section
3558 766 add_settings_section(
3559 - 'mxchat_brave_section',
3560 - __('Brave Search Settings', 'mxchat'),
3561 - array($this, 'mxchat_brave_section_callback'),
3562 - 'mxchat-embed'
767 + 'mxchat_theme_section',
768 + 'Theme Settings',
769 + null,
770 + 'mxchat-theme'
3563 771 );
3564 772
3565 773 add_settings_field(
3566 - 'brave_api_key',
3567 - __('Brave API Key', 'mxchat'),
3568 - array($this, 'mxchat_brave_api_key_callback'),
3569 - 'mxchat-embed',
3570 - 'mxchat_brave_section'
774 + 'close_button_color',
775 + 'Close Button & Title Color',
776 + array($this, 'mxchat_close_button_color_callback'),
777 + 'mxchat-theme',
778 + 'mxchat_theme_section'
3571 779 );
3572 780
3573 781 add_settings_field(
3574 - 'brave_image_count',
3575 - __('Number of Images to Return', 'mxchat'),
3576 - array($this, 'mxchat_brave_image_count_callback'),
3577 - 'mxchat-embed',
3578 - 'mxchat_brave_section'
782 + 'chatbot_bg_color',
783 + 'Chatbot Background Color',
784 + array($this, 'mxchat_chatbot_bg_color_callback'),
785 + 'mxchat-theme',
786 + 'mxchat_theme_section'
3579 787 );
3580 788
3581 789 add_settings_field(
3582 - 'brave_safe_search',
3583 - __('Safe Search', 'mxchat'),
3584 - array($this, 'mxchat_brave_safe_search_callback'),
3585 - 'mxchat-embed',
3586 - 'mxchat_brave_section'
790 + 'user_message_bg_color',
791 + 'User Message Background Color',
792 + array($this, 'mxchat_user_message_bg_color_callback'),
793 + 'mxchat-theme',
794 + 'mxchat_theme_section'
3587 795 );
3588 796
3589 797 add_settings_field(
3590 - 'brave_news_count',
3591 - __('Number of News Articles', 'mxchat'),
3592 - array($this, 'mxchat_brave_news_count_callback'),
3593 - 'mxchat-embed',
3594 - 'mxchat_brave_section'
798 + 'user_message_font_color',
799 + 'User Message Font Color',
800 + array($this, 'mxchat_user_message_font_color_callback'),
801 + 'mxchat-theme',
802 + 'mxchat_theme_section'
3595 803 );
3596 804
3597 805 add_settings_field(
3598 - 'brave_country',
3599 - __('Country', 'mxchat'),
3600 - array($this, 'mxchat_brave_country_callback'),
3601 - 'mxchat-embed',
3602 - 'mxchat_brave_section'
806 + 'bot_message_bg_color',
807 + 'Bot Message Background Color',
808 + array($this, 'mxchat_bot_message_bg_color_callback'),
809 + 'mxchat-theme',
810 + 'mxchat_theme_section'
3603 811 );
3604 812
3605 813 add_settings_field(
3606 - 'brave_language',
3607 - __('Language', 'mxchat'),
3608 - array($this, 'mxchat_brave_language_callback'),
3609 - 'mxchat-embed',
3610 - 'mxchat_brave_section'
814 + 'bot_message_font_color',
815 + 'Bot Message Font Color',
816 + array($this, 'mxchat_bot_message_font_color_callback'),
817 + 'mxchat-theme',
818 + 'mxchat_theme_section'
3611 819 );
3612 820
3613 - // Chat with PDF Intent Settings Fields
3614 - add_settings_section(
3615 - 'mxchat_pdf_intent_section',
3616 - __('Toolbar Settings & Intents', 'mxchat'),
3617 - array($this, 'mxchat_pdf_intent_section_callback'),
3618 - 'mxchat-embed'
3619 - );
3620 -
3621 821 add_settings_field(
3622 - 'chat_toolbar_toggle',
3623 - __('Show Chat Toolbar', 'mxchat'),
3624 - array($this, 'mxchat_chat_toolbar_toggle_callback'),
3625 - 'mxchat-embed',
3626 - 'mxchat_pdf_intent_section'
822 + 'top_bar_bg_color',
823 + 'Top Bar Background Color',
824 + array($this, 'mxchat_top_bar_bg_color_callback'),
825 + 'mxchat-theme',
826 + 'mxchat_theme_section'
3627 827 );
3628 828
3629 829 add_settings_field(
3630 - 'pdf_intent_trigger_text',
3631 - __('Intent Trigger Text', 'mxchat'),
3632 - array($this, 'mxchat_pdf_intent_trigger_text_callback'),
3633 - 'mxchat-embed',
3634 - 'mxchat_pdf_intent_section'
830 + 'send_button_font_color',
831 + 'Send Button Color',
832 + array($this, 'mxchat_send_button_font_color_callback'),
833 + 'mxchat-theme',
834 + 'mxchat_theme_section'
3635 835 );
3636 836
3637 837 add_settings_field(
3638 - 'pdf_intent_success_text',
3639 - __('Success Text', 'mxchat'),
3640 - array($this, 'mxchat_pdf_intent_success_text_callback'),
3641 - 'mxchat-embed',
3642 - 'mxchat_pdf_intent_section'
838 + 'chat_input_font_color',
839 + 'Chat Input Font Color',
840 + array($this, 'mxchat_chat_input_font_color_callback'),
841 + 'mxchat-theme',
842 + 'mxchat_theme_section'
3643 843 );
3644 844
3645 845 add_settings_field(
3646 - 'pdf_intent_error_text',
3647 - __('Error Text', 'mxchat'),
3648 - array($this, 'mxchat_pdf_intent_error_text_callback'),
3649 - 'mxchat-embed',
3650 - 'mxchat_pdf_intent_section'
846 + 'chatbot_background_color',
847 + 'Floating Widget Background Color',
848 + array($this, 'mxchat_chatbot_background_color_callback'),
849 + 'mxchat-theme',
850 + 'mxchat_theme_section'
3651 851 );
3652 852
3653 - // Add PDF Maximum Pages Field
3654 853 add_settings_field(
3655 - 'pdf_max_pages',
3656 - __('Maximum Document Pages', 'mxchat'),
3657 - array($this, 'mxchat_pdf_max_pages_callback'),
3658 - 'mxchat-embed',
3659 - 'mxchat_pdf_intent_section'
854 + 'icon_color',
855 + 'Chatbot Icon Color',
856 + array($this, 'mxchat_icon_color_callback'),
857 + 'mxchat-theme',
858 + 'mxchat_theme_section'
3660 859 );
3661 860
3662 - // Live Agent Settings Fields
3663 - add_settings_section(
3664 - 'mxchat_live_agent_section',
3665 - __('Live Agent Settings', 'mxchat'),
3666 - array($this, 'mxchat_live_agent_section_callback'),
3667 - 'mxchat-embed'
3668 - );
3669 -
3670 - // Live Agent Status Fields (add at top of live agent settings)
3671 - add_settings_field(
3672 - 'live_agent_status',
3673 - __('Live Agent Status', 'mxchat'),
3674 - array($this, 'mxchat_live_agent_status_callback'),
3675 - 'mxchat-embed',
3676 - 'mxchat_live_agent_section'
3677 - );
3678 -
3679 - add_settings_field(
3680 - 'live_agent_notification_message',
3681 - __('Notification Message', 'mxchat'),
3682 - array($this, 'mxchat_live_agent_notification_message_callback'),
3683 - 'mxchat-embed',
3684 - 'mxchat_live_agent_section'
3685 - );
3686 -
3687 - add_settings_field(
3688 - 'live_agent_away_message',
3689 - __('Away Message', 'mxchat'),
3690 - array($this, 'mxchat_live_agent_away_message_callback'),
3691 - 'mxchat-embed',
3692 - 'mxchat_live_agent_section'
3693 - );
3694 -
3695 - add_settings_field(
3696 - 'live_agent_webhook_url',
3697 - __('Slack Webhook URL', 'mxchat'),
3698 - array($this, 'mxchat_live_agent_webhook_url_callback'),
3699 - 'mxchat-embed',
3700 - 'mxchat_live_agent_section'
3701 - );
3702 -
3703 - add_settings_field(
3704 - 'live_agent_secret_key',
3705 - __('Slack Secret Key', 'mxchat'),
3706 - array($this, 'mxchat_live_agent_secret_key_callback'),
3707 - 'mxchat-embed',
3708 - 'mxchat_live_agent_section'
3709 - );
3710 -
3711 - // Live Agent Integration Fields
3712 - add_settings_field(
3713 - 'live_agent_bot_token',
3714 - __('Slack Bot OAuth Token', 'mxchat'),
3715 - array($this, 'mxchat_live_agent_bot_token_callback'),
3716 - 'mxchat-embed',
3717 - 'mxchat_live_agent_section'
3718 - );
3719 -
3720 -
3721 -
3722 -
3723 861 // General Settings Section
3724 862 add_settings_section(
3725 - 'mxchat_general_section',
3726 - esc_html__('Frequently Asked Questions (FAQ)', 'mxchat'),
3727 - null,
863 + 'mxchat_general_section',
864 + 'General Information',
865 + null,
3728 866 'mxchat-general'
3729 867 );
3730 -}
3731 868
3732 -public function mxchat_prompts_page_init() {
3733 - // Register all settings as a single array
3734 - register_setting(
3735 - 'mxchat_prompts_options',
3736 - 'mxchat_prompts_options',
3737 - array(
3738 - 'type' => 'array',
3739 - 'description' => __('MXChat Knowledge Base Settings', 'mxchat'),
3740 - 'default' => array(
3741 - 'mxchat_auto_sync_posts' => 0,
3742 - 'mxchat_auto_sync_pages' => 0,
3743 - 'mxchat_use_pinecone' => 0,
3744 - 'mxchat_pinecone_api_key' => '',
3745 - 'mxchat_pinecone_environment' => '',
3746 - 'mxchat_pinecone_index' => '',
3747 - 'mxchat_pinecone_host' => '', // Add this line
3748 - ),
3749 - 'sanitize_callback' => array($this, 'sanitize_prompts_options'),
3750 - )
3751 - );
3752 869
3753 - // Add settings saved message
3754 - add_action('admin_notices', array($this, 'sync_settings_notice'));
3755 870 }
3756 871
3757 -/**
3758 - * Sanitize all prompts options
3759 - *
3760 - * @param array $input The unsanitized options array
3761 - * @return array The sanitized options array
3762 - */
3763 -public function sanitize_prompts_options($input) {
3764 - // Log the incoming input.
3765 - //error_log('Sanitizing inputs: ' . print_r($input, true));
3766 872
3767 - $sanitized = array();
3768 873
3769 - // Boolean options
3770 - $sanitized['mxchat_auto_sync_posts'] = isset($input['mxchat_auto_sync_posts']) ? 1 : 0;
3771 - $sanitized['mxchat_auto_sync_pages'] = isset($input['mxchat_auto_sync_pages']) ? 1 : 0;
3772 -$sanitized['mxchat_use_pinecone'] = !empty($input['mxchat_use_pinecone']) ? 1 : 0;
3773 874
3774 - // API Key: if less than 32 characters, flag as invalid.
3775 - $api_key = sanitize_text_field($input['mxchat_pinecone_api_key'] ?? '');
3776 - if (!empty($api_key) && strlen($api_key) < 32) {
3777 - add_settings_error(
3778 - 'mxchat_prompts_options',
3779 - 'invalid_api_key',
3780 - __('The Pinecone API key appears to be invalid. Please check your API key.', 'mxchat')
3781 - );
3782 - $existing_options = get_option('mxchat_prompts_options', array());
3783 - $sanitized['mxchat_pinecone_api_key'] = $existing_options['mxchat_pinecone_api_key'] ?? '';
3784 - } else {
3785 - $sanitized['mxchat_pinecone_api_key'] = $api_key;
3786 - }
875 + public function mxchat_handle_activate_license() {
876 + check_ajax_referer('mxchat_activate_license_nonce', 'security');
3787 877
3788 - // Environment and Index Name
3789 - $sanitized['mxchat_pinecone_environment'] = sanitize_text_field($input['mxchat_pinecone_environment'] ?? '');
3790 - $sanitized['mxchat_pinecone_index'] = sanitize_text_field($input['mxchat_pinecone_index'] ?? '');
878 + $license_key = isset($_POST['key']) ? sanitize_text_field($_POST['key']) : '';
879 + $customer_email = isset($_POST['email']) ? sanitize_email($_POST['email']) : '';
3791 880
3792 - // Host: Remove protocol and validate format.
3793 - $host = sanitize_text_field($input['mxchat_pinecone_host'] ?? '');
3794 - $host = preg_replace('#^https?://#', '', $host);
3795 - //error_log('Host after removing protocol: ' . $host);
3796 - if (!empty($host)) {
3797 - if (!preg_match('/^[\w-]+\.svc\.[\w-]+\.pinecone\.io$/', $host)) {
3798 - add_settings_error(
3799 - 'mxchat_prompts_options',
3800 - 'invalid_host',
3801 - __('The Pinecone host appears to be invalid. It should look like "mxchat-vectors-zrmsquq.svc.aped-4627-b74a.pinecone.io"', 'mxchat')
3802 - );
3803 - $existing_options = get_option('mxchat_prompts_options', array());
3804 - $sanitized['mxchat_pinecone_host'] = $existing_options['mxchat_pinecone_host'] ?? '';
3805 - } else {
3806 - $sanitized['mxchat_pinecone_host'] = $host;
881 + if (empty($license_key) || empty($customer_email)) {
882 + wp_send_json_error('Email or License Key is missing');
3807 883 }
3808 - } else {
3809 - $sanitized['mxchat_pinecone_host'] = '';
3810 - }
3811 884
3812 - //error_log('Final sanitized array: ' . print_r($sanitized, true));
885 + $product_id = 'MxChatPRO';
3813 886
3814 - return $sanitized;
3815 -}
887 + $response = wp_remote_get("http://mxchat.ai/?wc-api=software-api&request=activation&email={$customer_email}&license_key={$license_key}&product_id={$product_id}");
3816 888
889 + if (is_wp_error($response)) {
890 + wp_send_json_error('Activation failed due to a server error');
891 + }
3817 892
3818 -public function sync_settings_notice() {
3819 - // Only show notice on our plugin page
3820 - if (!isset($_GET['page']) || $_GET['page'] !== 'mxchat-prompts') {
3821 - return;
893 + $body = wp_remote_retrieve_body($response);
894 + $data = json_decode($body);
895 +
896 + if ($data && isset($data->activated) && $data->activated) {
897 + update_option('mxchat_license_status', 'active');
898 + wp_send_json_success();
899 + } else {
900 + $error_message = isset($data->error) ? $data->error : 'Activation failed';
901 + update_option('mxchat_license_status', 'inactive');
902 + update_option('mxchat_license_error', $error_message);
903 + wp_send_json_error($error_message);
904 + }
3822 905 }
3823 906
3824 - // Check if settings were updated
3825 - if (isset($_GET['settings-updated'])) {
3826 907
3827 - ?>
3828 - <div class="notice notice-success is-dismissible">
3829 - <p><?php esc_html_e('Sync settings updated successfully.', 'mxchat'); ?></p>
3830 - </div>
3831 - <?php
908 +public function mxchat_rate_limit_callback() {
909 + $rate_limits = array('5', '10', '15', '20', '100');
910 + $selected_rate_limit = isset($this->options['rate_limit']) ? $this->options['rate_limit'] : '100';
3832 911
3833 - }
3834 -}
3835 -// Add this sanitization function to your class
3836 -public function sanitize_sync_setting($input) {
3837 - return (bool)$input ? __('1', 'mxchat') : __('', 'mxchat');
3838 -}
912 + $disabled = $this->is_activated ? '' : 'disabled';
913 + $class = $this->is_activated ? 'pro-feature-wrapper active' : 'pro-feature-wrapper inactive';
3839 914
3840 -
3841 -
3842 -public function mxchat_handle_activate_license() {
3843 - // Check nonce
3844 - if (!check_ajax_referer('mxchat_activate_license_nonce', 'security', false)) {
3845 - wp_send_json_error(esc_html__('Invalid security token', 'mxchat'));
3846 - return;
915 + echo '<div class="' . esc_attr($class) . '">';
916 + echo '<select id="rate_limit" name="mxchat_options[rate_limit]" ' . $disabled . '>';
917 + foreach ($rate_limits as $limit) {
918 + echo '<option value="' . esc_attr($limit) . '" ' . selected($selected_rate_limit, $limit, false) . '>' . esc_html($limit) . '</option>';
3847 919 }
920 + echo '</select>';
3848 921
3849 - // Verify user capabilities
3850 - if (!current_user_can('manage_options')) {
3851 - wp_send_json_error(esc_html__('Unauthorized access', 'mxchat'));
3852 - return;
922 + if (!$this->is_activated) {
923 + echo '<div class="pro-feature-overlay">';
924 + echo '<a href="https://mxchat.ai/" target="_blank"><img src="' . plugin_dir_url(__FILE__) . '../images/pro-only-dark.png" alt="Pro Only" /></a>';
925 + echo '</div>';
3853 926 }
3854 927
3855 - $license_key = isset($_POST['mxchat_activation_key']) ? sanitize_text_field($_POST['mxchat_activation_key']) : '';
3856 - $customer_email = isset($_POST['mxchat_pro_email']) ? sanitize_email($_POST['mxchat_pro_email']) : '';
928 + echo '</div>';
929 +}
3857 930
3858 - if (empty($license_key) || empty($customer_email)) {
3859 - wp_send_json_error(esc_html__('Email or License Key is missing', 'mxchat'));
3860 - return;
3861 - }
931 +public function mxchat_rate_limit_message_callback() {
932 + $disabled = $this->is_activated ? '' : 'disabled';
933 + $class = $this->is_activated ? 'pro-feature-wrapper active' : 'pro-feature-wrapper inactive';
3862 934
3863 - $product_id = 'MxChatPRO';
3864 - $response = wp_remote_get(
3865 - add_query_arg(
3866 - array(
3867 - 'wc-api' => 'software-api',
3868 - 'request' => 'activation',
3869 - 'email' => $customer_email,
3870 - 'license_key' => $license_key,
3871 - 'product_id' => $product_id
3872 - ),
3873 - 'http://mxchat.ai/'
3874 - )
935 + echo '<div class="' . esc_attr($class) . '">';
936 + printf(
937 + '<textarea id="rate_limit_message" name="mxchat_options[rate_limit_message]" rows="3" cols="50" %s>%s</textarea>',
938 + esc_attr($disabled),
939 + isset($this->options['rate_limit_message']) ? esc_textarea($this->options['rate_limit_message']) : 'Rate limit exceeded. Please try again later.'
3875 940 );
3876 941
3877 - if (is_wp_error($response)) {
3878 - wp_send_json_error(esc_html__('Activation failed due to a server error: ', 'mxchat') . $response->get_error_message());
3879 - return;
942 + if (!$this->is_activated) {
943 + echo '<div class="pro-feature-overlay">';
944 + echo '<a href="https://mxchat.ai/" target="_blank"><img src="' . plugin_dir_url(__FILE__) . '../images/pro-only-dark.png" alt="Pro Only" /></a>';
945 + echo '</div>';
3880 946 }
3881 947
3882 - $body = wp_remote_retrieve_body($response);
3883 - $data = json_decode($body);
3884 -
3885 - if ($data && isset($data->activated) && $data->activated) {
3886 - update_option('mxchat_license_status', 'active');
3887 - update_option('mxchat_pro_email', $customer_email);
3888 - update_option('mxchat_activation_key', $license_key);
3889 - wp_send_json_success(array('message' => esc_html__('License activated successfully', 'mxchat')));
3890 - } else {
3891 - $error_message = isset($data->error) ? $data->error : esc_html__('Activation failed', 'mxchat');
3892 - update_option('mxchat_license_status', 'inactive');
3893 - update_option('mxchat_license_error', $error_message);
3894 - wp_send_json_error($error_message);
3895 - }
3896 -}
3897 -
3898 -
3899 -public function mxchat_rate_limit_logged_out_callback() {
3900 - // Load the entire 'mxchat_options' array
3901 - $all_options = get_option('mxchat_options', []);
3902 -
3903 - // Retrieve the saved rate limit or use the default value
3904 - $default_rate_limit = '10';
3905 - $selected_rate_limit = isset($all_options['rate_limit_logged_out']) ? $all_options['rate_limit_logged_out'] : $default_rate_limit;
3906 -
3907 - // Define available rate limits
3908 - $rate_limits = array('1', '3', '5', '10', '15', '20', '100', 'unlimited');
3909 -
3910 - // Output the dropdown
3911 - echo '<div class="pro-feature-wrapper active">';
3912 - echo '<select id="rate_limit_logged_out" name="rate_limit_logged_out">';
3913 - foreach ($rate_limits as $limit) {
3914 - echo '<option value="' . esc_attr($limit) . '" ' . selected($selected_rate_limit, $limit, false) . '>' . esc_html($limit) . '</option>';
3915 - }
3916 - echo '</select>';
3917 - echo '<p class="description">' . esc_html__('Set the maximum number of messages a logged-out user can send within a 24-hour period.', 'mxchat') . '</p>';
3918 948 echo '</div>';
3919 949 }
3920 950
3921 -// Add this new callback function
3922 -public function mxchat_rate_limit_roles_callback() {
3923 - $all_options = get_option('mxchat_options', []);
3924 - $roles = wp_roles()->get_names();
3925 - $rate_limits = array('1', '3', '5', '10', '15', '20', '100', 'unlimited');
3926 951
3927 - echo '<div class="pro-feature-wrapper active mxchat-autosave-section">';
952 +public function mxchat_enable_woocommerce_integration_callback() {
953 + $checked = isset($this->options['enable_woocommerce_integration']) && $this->options['enable_woocommerce_integration'] === '1' ? 'checked' : '';
954 + $disabled = $this->is_activated ? '' : 'disabled';
955 + $class = $this->is_activated ? 'pro-feature-wrapper active' : 'pro-feature-wrapper inactive';
3928 956
3929 - foreach ($roles as $role_id => $role_name) {
3930 - $default_rate_limit = '100';
3931 - $selected_rate_limit = isset($all_options['role_rate_limits'][$role_id])
3932 - ? $all_options['role_rate_limits'][$role_id]
3933 - : $default_rate_limit;
957 + echo '<div class="' . esc_attr($class) . '">';
958 + echo '<label class="toggle-switch">';
959 + echo '<input type="checkbox" id="enable_woocommerce_integration" name="mxchat_options[enable_woocommerce_integration]" value="1" ' . $checked . ' ' . $disabled . '>';
960 + echo '<span class="slider"></span>';
961 + echo '</label>';
3934 962
3935 - echo '<div style="margin-bottom: 10px;">';
3936 - echo '<label style="display: inline-block; width: 150px;">' . esc_html($role_name) . ':</label>';
3937 - echo '<select
3938 - id="role_rate_limits_' . esc_attr($role_id) . '"
3939 - name="mxchat_options[role_rate_limits][' . esc_attr($role_id) . ']"
3940 - class="mxchat-autosave-field">';
3941 - foreach ($rate_limits as $limit) {
3942 - echo '<option value="' . esc_attr($limit) . '" ' . selected($selected_rate_limit, $limit, false) . '>' . esc_html($limit) . '</option>';
3943 - }
3944 - echo '</select>';
963 + if (!$this->is_activated) {
964 + echo '<div class="pro-feature-overlay">';
965 + echo '<a href="https://mxchat.ai/" target="_blank"><img src="' . plugin_dir_url(__FILE__) . '../images/pro-only-dark.png" alt="Pro Only" /></a>';
3945 966 echo '</div>';
3946 967 }
3947 968
3948 - echo '<p class="description">' . esc_html__('Set the maximum number of messages users in each role can send within a 24-hour period.', 'mxchat') . '</p>';
3949 969 echo '</div>';
3950 970 }
3951 971
3952 -public function mxchat_rate_limit_message_callback() {
3953 - // Load the entire 'mxchat_options' array
3954 - $all_options = get_option('mxchat_options', []);
3955 972
3956 - // Retrieve the saved message or use the default value
3957 - $default_message = esc_html__('Rate limit exceeded. Please try again later.', 'mxchat');
3958 - $rate_limit_message = isset($all_options['rate_limit_message']) ? $all_options['rate_limit_message'] : $default_message;
3959 -
3960 - // Output the textarea
3961 - echo '<div class="pro-feature-wrapper active">';
3962 - printf(
3963 - '<textarea id="rate_limit_message" name="rate_limit_message" rows="3" cols="50">%s</textarea>',
3964 - esc_textarea($rate_limit_message)
3965 - );
3966 - echo '<p class="description">' . esc_html__('This message will be displayed when a user exceeds the rate limit.', 'mxchat') . '</p>';
3967 - echo '</div>';
3968 -}
3969 -
3970 -
3971 -private function mxchat_add_option_field($id, $title, $callback = '') {
973 + private function mxchat_add_option_field($id, $title, $callback = '') {
3972 974 add_settings_field(
3973 975 $id,
3974 - __($title, 'mxchat'),
976 + $title,
3975 977 $callback ? array($this, $callback) : array($this, $id . '_callback'),
3976 978 'mxchat-max',
3977 979 'mxchat_setting_section_id',
3978 980 $id === 'model' ? ['label_for' => 'model'] : []
@@ -3978,1505 +980,370 @@
3978 980 $id === 'model' ? ['label_for' => 'model'] : []
3979 981 );
3980 982 }
3981 983
3982 -public function api_key_callback() {
3983 - // Retrieve from your stored 'api_key' in the mxchat_options array
3984 - $apiKey = isset($this->options['api_key']) ? esc_attr($this->options['api_key']) : '';
984 + // Callback for API Key input
985 + public function api_key_callback() {
986 + printf(
987 + '<input type="text" id="api_key" name="mxchat_options[api_key]" value="%s" class="regular-text" />',
988 + isset($this->options['api_key']) ? esc_attr($this->options['api_key']) : ''
989 + );
990 + }
991 +
992 +
993 +
994 +public function mxchat_woocommerce_consumer_key_callback() {
995 + $disabled = $this->is_activated ? '' : 'disabled';
996 + $class = $this->is_activated ? 'pro-feature-wrapper active' : 'pro-feature-wrapper inactive';
3985 997
3986 - // Notice we changed the name to "api_key" (no array notation).
3987 - echo '<input type="password" id="api_key" name="api_key" value="' . $apiKey . '" class="regular-text" />';
3988 - echo '<button type="button" id="toggleApiKeyVisibility">' . esc_html__('Show', 'mxchat') . '</button>';
3989 - echo '<p class="description">' . wp_kses_post(__('The <strong>OpenAI API key is required even when using other models</strong> as it is used for vector embedding functionality. You must add credits to your OpenAI billing account before use.', 'mxchat')) . '</p>';
3990 -}
3991 -public function xai_api_key_callback() {
3992 - // Check if the feature is activated (paid feature)
3993 - $disabled = $this->is_activated ? '' : 'disabled'; // Disable input if not activated
3994 - $class = $this->is_activated ? 'pro-feature-wrapper active' : 'pro-feature-wrapper inactive'; // CSS class to style the wrapper based on activation status
3995 -
3996 - // Retrieve the X.AI API key value
3997 - $xaiApiKey = isset($this->options['xai_api_key']) ? esc_attr($this->options['xai_api_key']) : '';
3998 -
3999 - // Render the input field for the X.AI API key
4000 998 echo '<div class="' . esc_attr($class) . '">';
4001 999 printf(
4002 - '<input type="password" id="xai_api_key" name="xai_api_key" value="%s" class="regular-text" %s />',
4003 - $xaiApiKey,
1000 + '<input type="text" id="woocommerce_consumer_key" name="mxchat_options[woocommerce_consumer_key]" value="%s" class="regular-text" %s />',
1001 + isset($this->options['woocommerce_consumer_key']) ? esc_attr($this->options['woocommerce_consumer_key']) : '',
4004 1002 $disabled
4005 1003 );
4006 - echo '<button type="button" id="toggleXaiApiKeyVisibility">' . esc_html__('Show', 'mxchat') . '</button>';
4007 1004
4008 - // If the feature is not activated, show the overlay with a "Pro Only" message
4009 1005 if (!$this->is_activated) {
4010 1006 echo '<div class="pro-feature-overlay">';
4011 - echo '<a href="https://mxchat.ai/" target="_blank"><img src="' . plugin_dir_url(__FILE__) . '../images/pro-only-dark.png" alt="' . esc_attr__('Pro Only', 'mxchat') . '" /></a>';
1007 + echo '<a href="https://mxchat.ai/" target="_blank"><img src="' . plugin_dir_url(__FILE__) . '../images/pro-only-dark.png" alt="Pro Only" /></a>';
4012 1008 echo '</div>';
4013 1009 }
4014 1010
4015 1011 echo '</div>';
4016 1012 }
4017 -public function claude_api_key_callback() {
4018 - // Check if the feature is activated (paid feature)
1013 +
1014 +public function mxchat_woocommerce_consumer_secret_callback() {
4019 1015 $disabled = $this->is_activated ? '' : 'disabled';
4020 1016 $class = $this->is_activated ? 'pro-feature-wrapper active' : 'pro-feature-wrapper inactive';
4021 -
4022 - // Retrieve the Claude API key value directly like the others
4023 - $claudeApiKey = isset($this->options['claude_api_key']) ? esc_attr($this->options['claude_api_key']) : '';
4024 -
4025 - // Use direct name field like the other working API keys
1017 +
4026 1018 echo '<div class="' . esc_attr($class) . '">';
4027 1019 printf(
4028 - '<input type="password" id="claude_api_key" name="claude_api_key" value="%s" class="regular-text" %s />',
4029 - $claudeApiKey,
1020 + '<input type="text" id="woocommerce_consumer_secret" name="mxchat_options[woocommerce_consumer_secret]" value="%s" class="regular-text" %s />',
1021 + isset($this->options['woocommerce_consumer_secret']) ? esc_attr($this->options['woocommerce_consumer_secret']) : '',
4030 1022 $disabled
4031 1023 );
4032 - echo '<button type="button" id="toggleClaudeApiKeyVisibility">' . esc_html__('Show', 'mxchat') . '</button>';
4033 -
1024 +
4034 1025 if (!$this->is_activated) {
4035 1026 echo '<div class="pro-feature-overlay">';
4036 - echo '<a href="https://mxchat.ai/" target="_blank"><img src="' . plugin_dir_url(__FILE__) . '../images/pro-only-dark.png" alt="' . esc_attr__('Pro Only', 'mxchat') . '" /></a>';
1027 + echo '<a href="https://mxchat.ai/" target="_blank"><img src="' . plugin_dir_url(__FILE__) . '../images/pro-only-dark.png" alt="Pro Only" /></a>';
4037 1028 echo '</div>';
4038 1029 }
4039 - echo '</div>';
4040 -}
4041 -public function deepseek_api_key_callback() {
4042 - // Retrieve from your stored 'deepseek_api_key' in the mxchat_options array
4043 - $apiKey = isset($this->options['deepseek_api_key']) ? esc_attr($this->options['deepseek_api_key']) : '';
4044 1030
4045 - // Notice we changed the name to "deepseek_api_key" (no array notation).
4046 - echo '<input type="password" id="deepseek_api_key" name="deepseek_api_key" value="' . $apiKey . '" class="regular-text" />';
4047 - echo '<button type="button" id="toggleDeepSeekApiKeyVisibility">' . esc_html__('Show', 'mxchat') . '</button>';
4048 -}
4049 -
4050 -
4051 -
4052 -
4053 -
4054 -public function mxchat_loops_api_key_callback() {
4055 - // Support both old and new format
4056 - $loops_api_key = isset($this->options['loops_api_key']) ? esc_attr($this->options['loops_api_key']) : '';
4057 -
4058 - echo '<div class="api-key-wrapper">';
4059 - echo sprintf(
4060 - '<input type="password" id="loops_api_key" name="loops_api_key" value="%s" class="regular-text" />',
4061 - $loops_api_key
4062 - );
4063 - echo '<button type="button" id="toggleLoopsApiKeyVisibility">' . esc_html__('Show', 'mxchat') . '</button>';
4064 1031 echo '</div>';
4065 - echo '<p class="description">' . esc_html__('Enter your Loops API Key here. (See FAQ for details)', 'mxchat') . '</p>';
4066 1032 }
4067 1033
4068 -public function mxchat_loops_mailing_list_callback() {
4069 - // Add error handling and type checking
4070 - $loops_api_key = '';
4071 - $selected_list = '';
4072 -
4073 - // Safely get the API key
4074 - if (isset($this->options['loops_api_key']) && is_string($this->options['loops_api_key'])) {
4075 - $loops_api_key = $this->options['loops_api_key'];
1034 +
1035 + public function mxchat_pre_chat_message_callback() {
1036 + printf(
1037 + '<textarea id="pre_chat_message" name="mxchat_options[pre_chat_message]" rows="5" cols="50">%s</textarea>',
1038 + isset($this->options['pre_chat_message']) ? esc_textarea($this->options['pre_chat_message']) : ''
1039 + );
4076 1040 }
4077 1041
4078 - // Safely get the selected list
4079 - if (isset($this->options['loops_mailing_list']) && is_string($this->options['loops_mailing_list'])) {
4080 - $selected_list = $this->options['loops_mailing_list'];
1042 + // Callback for AI Instructions textarea
1043 + public function system_prompt_instructions_callback() {
1044 + printf(
1045 + '<textarea id="system_prompt_instructions" name="mxchat_options[system_prompt_instructions]" rows="5" cols="50">%s</textarea>',
1046 + isset($this->options['system_prompt_instructions']) ? esc_textarea($this->options['system_prompt_instructions']) : ''
1047 + );
4081 1048 }
4082 1049
4083 - if (!empty($loops_api_key)) {
4084 - $lists = $this->mxchat_fetch_loops_mailing_lists($loops_api_key);
4085 - if (is_array($lists) && !empty($lists)) {
4086 - echo '<select id="loops_mailing_list" name="loops_mailing_list">';
4087 - foreach ($lists as $list) {
4088 - if (is_array($list) && isset($list['id']) && isset($list['name'])) {
4089 - echo sprintf(
4090 - '<option value="%s" %s>%s</option>',
4091 - esc_attr($list['id']),
4092 - selected($selected_list, $list['id'], false),
4093 - esc_html($list['name'])
4094 - );
4095 - }
4096 - }
4097 - echo '</select>';
4098 - } else {
4099 - echo '<p class="description">' . esc_html__('No lists found. Please verify your API Key.', 'mxchat') . '</p>';
1050 + public function mxchat_model_callback() {
1051 + $models = array(
1052 + 'gpt-4o' => 'gpt-4o',
1053 + 'gpt-4o-mini' => 'gpt-4o-mini',
1054 + 'gpt-4-turbo' => 'gpt-4-turbo',
1055 + 'gpt-4' => 'gpt-4',
1056 + 'gpt-3.5-turbo' => 'gpt-3.5-turbo',
1057 + );
1058 +
1059 + $selected_model = isset($this->options['model']) ? $this->options['model'] : 'gpt-3.5-turbo';
1060 +
1061 + echo '<select id="model" name="mxchat_options[model]">';
1062 + foreach ($models as $model_value => $model_label) {
1063 + echo '<option value="' . esc_attr($model_value) . '" ' . selected($selected_model, $model_value, false) . '>' . esc_html($model_label) . '</option>';
4100 1064 }
4101 - } else {
4102 - echo '<p class="description">' . esc_html__('Enter a valid Loops API Key to load mailing lists.', 'mxchat') . '</p>';
1065 + echo '</select>';
4103 1066 }
4104 -}
4105 -public function mxchat_triggered_phrase_response_callback() {
4106 - $default_response = __('Would you like to join our mailing list? Please provide your email below.', 'mxchat');
4107 - $triggered_response = isset($this->options['triggered_phrase_response'])
4108 - ? $this->options['triggered_phrase_response']
4109 - : $default_response;
4110 1067
4111 - echo sprintf(
4112 - '<textarea id="triggered_phrase_response" name="triggered_phrase_response" rows="3" cols="50">%s</textarea>',
4113 - esc_textarea($triggered_response)
4114 - );
4115 - echo '<p class="description">' . esc_html__('Enter the chatbot response when a trigger keyword is detected, prompting the user to share their email.', 'mxchat') . '</p>';
4116 -}
1068 + public function mxchat_top_bar_title_callback() {
1069 + printf(
1070 + '<input type="text" id="top_bar_title" name="mxchat_options[top_bar_title]" value="%s" />',
1071 + isset($this->options['top_bar_title']) ? esc_attr($this->options['top_bar_title']) : ''
1072 + );
1073 + }
4117 1074
4118 -public function mxchat_email_capture_response_callback() {
4119 - $default_response = __('Thank you for providing your email! You\'ve been added to our list.', 'mxchat');
4120 - $email_capture_response = isset($this->options['email_capture_response'])
4121 - ? $this->options['email_capture_response']
4122 - : $default_response;
4123 -
4124 - echo sprintf(
4125 - '<textarea id="email_capture_response" name="email_capture_response" rows="3" cols="50">%s</textarea>',
4126 - esc_textarea($email_capture_response)
4127 - );
4128 - echo '<p class="description">' . esc_html__('Enter the message to send when a user provides their email.', 'mxchat') . '</p>';
4129 -}
4130 -
4131 -public function mxchat_pre_chat_message_callback() {
4132 - // Load the entire 'mxchat_options' array
4133 - $all_options = get_option('mxchat_options', []);
4134 -
4135 - // Retrieve the saved message or use the default value
4136 - $default_message = __('Hey there! Ask me anything!', 'mxchat');
4137 - $pre_chat_message = isset($all_options['pre_chat_message']) ? $all_options['pre_chat_message'] : $default_message;
4138 -
4139 - // Output the textarea
4140 - printf(
4141 - '<textarea id="pre_chat_message" name="pre_chat_message" rows="5" cols="50">%s</textarea>',
4142 - esc_textarea($pre_chat_message)
4143 - );
4144 - echo '<p class="description">' . esc_html__('Set the message displayed to users before they start a chat. Use this to provide a friendly greeting or instructions.', 'mxchat') . '</p>';
4145 -}
4146 -
4147 -
4148 -
4149 -// Callback for AI Instructions textarea
4150 -public function system_prompt_instructions_callback() {
4151 - // Retrieve the current value of the system prompt instructions
4152 - $instructions = isset($this->options['system_prompt_instructions']) ? esc_textarea($this->options['system_prompt_instructions']) : '';
4153 -
4154 - // Render the textarea field
4155 - printf(
4156 - '<textarea id="system_prompt_instructions" name="system_prompt_instructions" rows="5" cols="50">%s</textarea>',
4157 - $instructions
4158 - );
4159 -
4160 - // Provide a helpful description
4161 - echo '<p class="description">' . esc_html__('Provide system-level instructions for the AI to guide its behavior. Be clear and concise for better results.', 'mxchat') . '</p>';
4162 -}
4163 -
4164 -
4165 -public function mxchat_model_callback() {
4166 - // Define available models grouped by provider
4167 - $models = array(
4168 - esc_html__('X.AI Models', 'mxchat') => array(
4169 - 'grok-beta' => esc_html__('grok-beta (Early Beta)', 'mxchat'),
4170 - 'grok-2' => esc_html__('Grok 2', 'mxchat')
4171 - ),
4172 - esc_html__('DeepSeek Models', 'mxchat') => array(
4173 - 'deepseek-chat' => esc_html__('DeepSeek-V3', 'mxchat'),
4174 - ),
4175 - esc_html__('Claude Models', 'mxchat') => array(
4176 - 'claude-3-5-sonnet-20241022' => esc_html__('Claude 3.5 Sonnet (Most Intelligent)', 'mxchat'),
4177 - 'claude-3-opus-20240229' => esc_html__('Claude 3 Opus (Highly Complex Tasks)', 'mxchat'),
4178 - 'claude-3-sonnet-20240229' => esc_html__('Claude 3 Sonnet (Balanced)', 'mxchat'),
4179 - 'claude-3-haiku-20240307' => esc_html__('Claude 3 Haiku (Fastest)', 'mxchat')
4180 - ),
4181 - esc_html__('OpenAI Models', 'mxchat') => array(
4182 - 'gpt-4o' => esc_html__('GPT-4o (Recommended)', 'mxchat'),
4183 - 'gpt-4o-mini' => esc_html__('GPT-4o Mini (Fast and Lightweight)', 'mxchat'),
4184 - 'gpt-4-turbo' => esc_html__('GPT-4 Turbo (High-Performance)', 'mxchat'),
4185 - 'gpt-4' => esc_html__('GPT-4 (High Intelligence)', 'mxchat'),
4186 - 'gpt-3.5-turbo' => esc_html__('GPT-3.5 Turbo (Affordable and Fast)', 'mxchat')
4187 - )
4188 - );
4189 -
4190 - // Retrieve the currently selected model from saved options
4191 - $selected_model = isset($this->options['model']) ? esc_attr($this->options['model']) : 'gpt-4o';
4192 -
4193 - // Begin the select dropdown
4194 - echo '<select id="model" name="model">'; // No array notation in name attribute
4195 -
4196 - // Iterate over groups of models
4197 - foreach ($models as $group_label => $group_models) {
4198 - echo '<optgroup label="' . esc_attr($group_label) . '">';
4199 -
4200 - foreach ($group_models as $model_value => $model_label) {
4201 - // Disable Pro-only models for non-activated users
4202 - $disabled = (!$this->is_activated && ($group_label === esc_html__('X.AI Models', 'mxchat') || $group_label === esc_html__('Claude Models', 'mxchat'))) ? 'disabled' : '';
4203 - $label_suffix = (!$this->is_activated && ($group_label === esc_html__('X.AI Models', 'mxchat') || $group_label === esc_html__('Claude Models', 'mxchat'))) ? esc_html__(' (Pro Only)', 'mxchat') : '';
4204 -
4205 - // Output the option element
4206 - echo '<option value="' . esc_attr($model_value) . '" ' . selected($selected_model, $model_value, false) . ' ' . $disabled . '>' . esc_html($model_label . $label_suffix) . '</option>';
4207 - }
4208 -
4209 - echo '</optgroup>';
1075 + public function mxchat_intro_message_callback() {
1076 + printf(
1077 + '<textarea id="intro_message" name="mxchat_options[intro_message]" rows="5" cols="50">%s</textarea>',
1078 + isset($this->options['intro_message']) ? esc_textarea($this->options['intro_message']) : 'Hello! How can I assist you today?'
1079 + );
4210 1080 }
4211 1081
4212 - // Close the select dropdown
4213 - echo '</select>';
4214 1082
4215 - // Add a description below the dropdown
4216 - echo '<p class="description">' . esc_html__('Select the AI model to use for your chatbot. Pro-only models are marked accordingly.', 'mxchat') . '</p>';
4217 -}
4218 1083
4219 1084
4220 1085
4221 -public function mxchat_top_bar_title_callback() {
4222 - // Retrieve the current value of the top bar title from saved options
4223 - $top_bar_title = isset($this->options['top_bar_title']) ? esc_attr($this->options['top_bar_title']) : '';
1086 + public function mxchat_close_button_color_callback() {
1087 + $disabled = $this->is_activated ? '' : 'disabled';
4224 1088
4225 - // Render the input field
4226 - echo '<input type="text" id="top_bar_title" name="top_bar_title" value="' . $top_bar_title . '" />';
4227 -
4228 - // Add a description
4229 - echo '<p class="description">' . esc_html__('Enter the title text that will appear on the top bar of the chatbot.', 'mxchat') . '</p>';
4230 -}
4231 -
4232 -public function enable_email_block_callback() {
4233 - // Load full plugin options array
4234 - $all_options = get_option('mxchat_options', []);
4235 -
4236 - // Get the value, default to 'off'
4237 - $enable_email_block = isset($all_options['enable_email_block']) ? $all_options['enable_email_block'] : 'off';
4238 -
4239 - // Check if it's 'on'
4240 - $checked = ($enable_email_block === 'on') ? 'checked' : '';
4241 -
4242 - echo '<label class="toggle-switch">';
4243 - echo sprintf(
4244 - '<input type="checkbox" id="enable_email_block" name="enable_email_block" value="on" %s />',
4245 - esc_attr($checked)
4246 - );
4247 - echo '<span class="slider"></span>';
4248 - echo '</label>';
4249 - echo '<p class="description">' . esc_html__('Their email will appear at the top of the transcript. Email form will show for users who are not logged in or have not provided an email within 24h.', 'mxchat') . '</p>';
4250 -}
4251 -
4252 -
4253 -
4254 -public function email_blocker_header_content_callback() {
4255 - // Load the entire 'mxchat_options' array
4256 - $all_options = get_option('mxchat_options', []);
4257 -
4258 - // Retrieve the saved content or default to empty
4259 - $content = isset($all_options['email_blocker_header_content'])
4260 - ? $all_options['email_blocker_header_content']
4261 - : '';
4262 -
4263 - // Render the textarea
4264 - echo '<textarea
4265 - id="email_blocker_header_content"
4266 - name="email_blocker_header_content"
4267 - rows="5"
4268 - cols="70"
4269 - >' . esc_textarea($content) . '</textarea>';
4270 -
4271 - echo '<p class="description">';
4272 - echo esc_html__('You may enter HTML here, such as &lt;h2&gt;Welcome&lt;/h2&gt; or &lt;p&gt;Let\'s get started&lt;/p&gt;.', 'mxchat');
4273 - echo '</p>';
4274 -}
4275 -
4276 -
4277 -public function email_blocker_button_text_callback() {
4278 - // Load the entire 'mxchat_options' array
4279 - $all_options = get_option('mxchat_options', []);
4280 -
4281 - // Retrieve the saved button text or default to empty
4282 - $button_text = isset($all_options['email_blocker_button_text'])
4283 - ? $all_options['email_blocker_button_text']
4284 - : '';
4285 -
4286 - // Use esc_attr to safely render the existing text
4287 - echo '<input type="text" id="email_blocker_button_text" name="email_blocker_button_text" value="' . esc_attr($button_text) . '" style="width: 300px;" />';
4288 -
4289 - echo '<p class="description">';
4290 - echo esc_html__('Enter the text you want on the submit button, e.g. "Start Chat".', 'mxchat');
4291 - echo '</p>';
4292 -}
4293 -
4294 -
4295 -
4296 -public function mxchat_intro_message_callback() {
4297 - // Load the entire 'mxchat_options' array
4298 - $all_options = get_option('mxchat_options', []);
4299 -
4300 - // Retrieve the saved intro message or use the default
4301 - $default_message = __('Hello! How can I assist you today?', 'mxchat');
4302 - $saved_message = isset($all_options['intro_message']) ? $all_options['intro_message'] : $default_message;
4303 -
4304 - // Output the textarea with the saved value
4305 - ?>
4306 - <textarea id="intro_message" name="intro_message" rows="5" cols="50"><?php echo esc_textarea($saved_message); ?></textarea>
4307 - <p class="description">
4308 - <?php esc_html_e('Enter your message. Line breaks will be preserved.', 'mxchat'); ?>
4309 - </p>
4310 - <?php
4311 -}
4312 -
4313 -
4314 -public function mxchat_input_copy_callback() {
4315 - // Load the entire 'mxchat_options' array
4316 - $all_options = get_option('mxchat_options', []);
4317 -
4318 - // Retrieve the saved input copy or use the default value
4319 - $default_copy = __('How can I assist?', 'mxchat');
4320 - $input_copy = isset($all_options['input_copy']) ? $all_options['input_copy'] : $default_copy;
4321 -
4322 - // Output the input field with the saved value
1089 + echo '<div class="pro-feature-wrapper">';
4323 1090 printf(
4324 - '<input type="text" id="input_copy" name="input_copy" value="%s" placeholder="%s" />',
4325 - esc_attr($input_copy),
4326 - esc_attr__('How can I assist?', 'mxchat')
4327 - );
4328 -
4329 - // Output the description
4330 - echo '<p class="description">' . esc_html__('This is the placeholder text for the chat input field.', 'mxchat') . '</p>';
4331 -}
4332 -
4333 -
4334 -
4335 -public function mxchat_user_message_font_color_callback() {
4336 - $disabled = $this->is_activated ? '' : 'disabled';
4337 - $class = $this->is_activated ? 'pro-feature-wrapper active' : 'pro-feature-wrapper inactive';
4338 -
4339 - echo '<div class="' . esc_attr($class) . '">';
4340 - echo sprintf(
4341 - '<input type="text"
4342 - id="user_message_font_color"
4343 - name="user_message_font_color"
4344 - value="%s"
4345 - class="my-color-field"
4346 - data-default-color="#ffffff"
4347 - %s />',
4348 - isset($this->options['user_message_font_color']) ? esc_attr($this->options['user_message_font_color']) : '#ffffff',
1091 + '<input type="text" id="close_button_color" name="mxchat_options[close_button_color]" value="%s" class="my-color-field" data-default-color="#4a4a4a" %s />',
1092 + isset($this->options['close_button_color']) ? esc_attr($this->options['close_button_color']) : '',
4349 1093 esc_attr($disabled)
4350 1094 );
4351 1095
4352 1096 if (!$this->is_activated) {
4353 1097 echo '<div class="pro-feature-overlay">';
4354 - echo '<a href="https://mxchat.ai/" target="_blank">';
4355 - echo '<img src="' . esc_url(plugin_dir_url(__FILE__) . '../images/pro-only-dark.png') . '" alt="' . esc_attr__('Pro Only', 'mxchat') . '" />';
4356 - echo '</a>';
1098 + echo '<a href="https://mxchat.ai/" target="_blank"><img src="' . plugin_dir_url(__FILE__) . '../images/pro-only-dark.png" alt="Pro Only" /></a>';
4357 1099 echo '</div>';
4358 1100 }
4359 - echo '</div>';
4360 -}
4361 1101
4362 -public function mxchat_bot_message_bg_color_callback() {
4363 - $disabled = $this->is_activated ? '' : 'disabled';
4364 - $class = $this->is_activated ? 'pro-feature-wrapper active' : 'pro-feature-wrapper inactive';
4365 -
4366 - echo '<div class="' . esc_attr($class) . '">';
4367 - echo sprintf(
4368 - '<input type="text"
4369 - id="bot_message_bg_color"
4370 - name="bot_message_bg_color"
4371 - value="%s"
4372 - class="my-color-field"
4373 - data-default-color="#e1e1e1"
4374 - %s />',
4375 - isset($this->options['bot_message_bg_color']) ? esc_attr($this->options['bot_message_bg_color']) : '#e1e1e1',
4376 - esc_attr($disabled)
4377 - );
4378 -
4379 - if (!$this->is_activated) {
4380 - echo '<div class="pro-feature-overlay">';
4381 - echo '<a href="https://mxchat.ai/" target="_blank">';
4382 - echo '<img src="' . esc_url(plugin_dir_url(__FILE__) . '../images/pro-only-dark.png') . '" alt="' . esc_attr__('Pro Only', 'mxchat') . '" />';
4383 - echo '</a>';
4384 - echo '</div>';
4385 - }
4386 1102 echo '</div>';
4387 -}
4388 -
4389 -public function mxchat_bot_message_font_color_callback() {
4390 - $disabled = $this->is_activated ? '' : 'disabled';
4391 - $class = $this->is_activated ? 'pro-feature-wrapper active' : 'pro-feature-wrapper inactive';
4392 -
4393 - echo '<div class="' . esc_attr($class) . '">';
4394 - echo sprintf(
4395 - '<input type="text"
4396 - id="bot_message_font_color"
4397 - name="bot_message_font_color"
4398 - value="%s"
4399 - class="my-color-field"
4400 - data-default-color="#333333"
4401 - %s />',
4402 - isset($this->options['bot_message_font_color']) ? esc_attr($this->options['bot_message_font_color']) : '#333333',
4403 - esc_attr($disabled)
4404 - );
4405 -
4406 - if (!$this->is_activated) {
4407 - echo '<div class="pro-feature-overlay">';
4408 - echo '<a href="https://mxchat.ai/" target="_blank">';
4409 - echo '<img src="' . esc_url(plugin_dir_url(__FILE__) . '../images/pro-only-dark.png') . '" alt="' . esc_attr__('Pro Only', 'mxchat') . '" />';
4410 - echo '</a>';
4411 - echo '</div>';
4412 1103 }
4413 - echo '</div>';
4414 -}
4415 1104
4416 -public function mxchat_live_agent_message_bg_color_callback() {
4417 - $disabled = $this->is_activated ? '' : 'disabled';
4418 - $class = $this->is_activated ? 'pro-feature-wrapper active' : 'pro-feature-wrapper inactive';
1105 + public function mxchat_chatbot_bg_color_callback() {
1106 + $disabled = $this->is_activated ? '' : 'disabled';
4419 1107
4420 - echo '<div class="' . esc_attr($class) . '">';
4421 - echo sprintf(
4422 - '<input type="text"
4423 - id="live_agent_message_bg_color"
4424 - name="live_agent_message_bg_color"
4425 - value="%s"
4426 - class="my-color-field"
4427 - data-default-color="#ffffff"
4428 - %s />',
4429 - isset($this->options['live_agent_message_bg_color']) ? esc_attr($this->options['live_agent_message_bg_color']) : '#ffffff',
4430 - esc_attr($disabled)
4431 - );
1108 + echo '<div class="pro-feature-wrapper">';
1109 + printf(
1110 + '<input type="text" id="chatbot_bg_color" name="mxchat_options[chatbot_bg_color]" value="%s" class="my-color-field" data-default-color="#f9f9f9" %s />',
1111 + isset($this->options['chatbot_bg_color']) ? esc_attr($this->options['chatbot_bg_color']) : '',
1112 + esc_attr($disabled)
1113 + );
4432 1114
4433 - if (!$this->is_activated) {
4434 - echo '<div class="pro-feature-overlay">';
4435 - echo '<a href="https://mxchat.ai/" target="_blank">';
4436 - echo '<img src="' . esc_url(plugin_dir_url(__FILE__) . '../images/pro-only-dark.png') . '" alt="' . esc_attr__('Pro Only', 'mxchat') . '" />';
4437 - echo '</a>';
4438 - echo '</div>';
4439 - }
4440 - echo '</div>';
4441 -}
1115 + if (!$this->is_activated) {
1116 + echo '<div class="pro-feature-overlay">';
1117 + echo '<a href="https://mxchat.ai/" target="_blank"><img src="' . plugin_dir_url(__FILE__) . '../images/pro-only-dark.png" alt="Pro Only" /></a>';
1118 + echo '</div>';
1119 + }
4442 1120
4443 -public function mxchat_live_agent_message_font_color_callback() {
4444 - $disabled = $this->is_activated ? '' : 'disabled';
4445 - $class = $this->is_activated ? 'pro-feature-wrapper active' : 'pro-feature-wrapper inactive';
4446 -
4447 - echo '<div class="' . esc_attr($class) . '">';
4448 - echo sprintf(
4449 - '<input type="text"
4450 - id="live_agent_message_font_color"
4451 - name="live_agent_message_font_color"
4452 - value="%s"
4453 - class="my-color-field"
4454 - data-default-color="#333333"
4455 - %s />',
4456 - isset($this->options['live_agent_message_font_color']) ? esc_attr($this->options['live_agent_message_font_color']) : '#333333',
4457 - esc_attr($disabled)
4458 - );
4459 -
4460 - if (!$this->is_activated) {
4461 - echo '<div class="pro-feature-overlay">';
4462 - echo '<a href="https://mxchat.ai/" target="_blank">';
4463 - echo '<img src="' . esc_url(plugin_dir_url(__FILE__) . '../images/pro-only-dark.png') . '" alt="' . esc_attr__('Pro Only', 'mxchat') . '" />';
4464 - echo '</a>';
4465 1121 echo '</div>';
4466 1122 }
4467 - echo '</div>';
4468 -}
4469 1123
4470 -public function mxchat_mode_indicator_bg_color_callback() {
4471 - $disabled = $this->is_activated ? '' : 'disabled';
4472 - $class = $this->is_activated ? 'pro-feature-wrapper active' : 'pro-feature-wrapper inactive';
1124 + public function mxchat_user_message_bg_color_callback() {
1125 + $disabled = $this->is_activated ? '' : 'disabled';
4473 1126
4474 - echo '<div class="' . esc_attr($class) . '">';
4475 - echo sprintf(
4476 - '<input type="text"
4477 - id="mode_indicator_bg_color"
4478 - name="mode_indicator_bg_color"
4479 - value="%s"
4480 - class="my-color-field"
4481 - data-default-color="#767676"
4482 - %s />',
4483 - isset($this->options['mode_indicator_bg_color']) ? esc_attr($this->options['mode_indicator_bg_color']) : '#767676',
4484 - esc_attr($disabled)
4485 - );
1127 + echo '<div class="pro-feature-wrapper">';
1128 + printf(
1129 + '<input type="text" id="user_message_bg_color" name="mxchat_options[user_message_bg_color]" value="%s" class="my-color-field" data-default-color="#0078d7" %s />',
1130 + isset($this->options['user_message_bg_color']) ? esc_attr($this->options['user_message_bg_color']) : '',
1131 + esc_attr($disabled)
1132 + );
4486 1133
4487 - if (!$this->is_activated) {
4488 - echo '<div class="pro-feature-overlay">';
4489 - echo '<a href="https://mxchat.ai/" target="_blank">';
4490 - echo '<img src="' . esc_url(plugin_dir_url(__FILE__) . '../images/pro-only-dark.png') . '" alt="' . esc_attr__('Pro Only', 'mxchat') . '" />';
4491 - echo '</a>';
4492 - echo '</div>';
4493 - }
4494 - echo '</div>';
4495 -}
1134 + if (!$this->is_activated) {
1135 + echo '<div class="pro-feature-overlay">';
1136 + echo '<a href="https://mxchat.ai/" target="_blank"><img src="' . plugin_dir_url(__FILE__) . '../images/pro-only-dark.png" alt="Pro Only" /></a>';
1137 + echo '</div>';
1138 + }
4496 1139
4497 -public function mxchat_mode_indicator_font_color_callback() {
4498 - $disabled = $this->is_activated ? '' : 'disabled';
4499 - $class = $this->is_activated ? 'pro-feature-wrapper active' : 'pro-feature-wrapper inactive';
4500 -
4501 - echo '<div class="' . esc_attr($class) . '">';
4502 - echo sprintf(
4503 - '<input type="text"
4504 - id="mode_indicator_font_color"
4505 - name="mode_indicator_font_color"
4506 - value="%s"
4507 - class="my-color-field"
4508 - data-default-color="#ffffff"
4509 - %s />',
4510 - isset($this->options['mode_indicator_font_color']) ? esc_attr($this->options['mode_indicator_font_color']) : '#ffffff',
4511 - esc_attr($disabled)
4512 - );
4513 -
4514 - if (!$this->is_activated) {
4515 - echo '<div class="pro-feature-overlay">';
4516 - echo '<a href="https://mxchat.ai/" target="_blank">';
4517 - echo '<img src="' . esc_url(plugin_dir_url(__FILE__) . '../images/pro-only-dark.png') . '" alt="' . esc_attr__('Pro Only', 'mxchat') . '" />';
4518 - echo '</a>';
4519 1140 echo '</div>';
4520 1141 }
4521 - echo '</div>';
4522 -}
4523 1142
4524 -public function mxchat_toolbar_icon_color_callback() {
4525 - $disabled = $this->is_activated ? '' : 'disabled';
4526 - $class = $this->is_activated ? 'pro-feature-wrapper active' : 'pro-feature-wrapper inactive';
1143 + public function mxchat_user_message_font_color_callback() {
1144 + $disabled = $this->is_activated ? '' : 'disabled';
4527 1145
4528 - echo '<div class="' . esc_attr($class) . '">';
4529 - echo sprintf(
4530 - '<input type="text"
4531 - id="toolbar_icon_color"
4532 - name="toolbar_icon_color"
4533 - value="%s"
4534 - class="my-color-field"
4535 - data-default-color="#212121"
4536 - %s />',
4537 - isset($this->options['toolbar_icon_color']) ? esc_attr($this->options['toolbar_icon_color']) : '#212121',
4538 - esc_attr($disabled)
4539 - );
1146 + echo '<div class="pro-feature-wrapper">';
1147 + printf(
1148 + '<input type="text" id="user_message_font_color" name="mxchat_options[user_message_font_color]" value="%s" class="my-color-field" data-default-color="#ffffff" %s />',
1149 + isset($this->options['user_message_font_color']) ? esc_attr($this->options['user_message_font_color']) : '',
1150 + esc_attr($disabled)
1151 + );
4540 1152
4541 - if (!$this->is_activated) {
4542 - echo '<div class="pro-feature-overlay">';
4543 - echo '<a href="https://mxchat.ai/" target="_blank">';
4544 - echo '<img src="' . esc_url(plugin_dir_url(__FILE__) . '../images/pro-only-dark.png') . '" alt="' . esc_attr__('Pro Only', 'mxchat') . '" />';
4545 - echo '</a>';
4546 - echo '</div>';
4547 - }
4548 - echo '</div>';
4549 -}
1153 + if (!$this->is_activated) {
1154 + echo '<div class="pro-feature-overlay">';
1155 + echo '<a href="https://mxchat.ai/" target="_blank"><img src="' . plugin_dir_url(__FILE__) . '../images/pro-only-dark.png" alt="Pro Only" /></a>';
1156 + echo '</div>';
1157 + }
4550 1158
4551 -public function mxchat_top_bar_bg_color_callback() {
4552 - $disabled = $this->is_activated ? '' : 'disabled';
4553 - $class = $this->is_activated ? 'pro-feature-wrapper active' : 'pro-feature-wrapper inactive';
4554 -
4555 - echo '<div class="' . esc_attr($class) . '">';
4556 - echo sprintf(
4557 - '<input type="text"
4558 - id="top_bar_bg_color"
4559 - name="top_bar_bg_color"
4560 - value="%s"
4561 - class="my-color-field"
4562 - data-default-color="#00b294"
4563 - %s />',
4564 - isset($this->options['top_bar_bg_color']) ? esc_attr($this->options['top_bar_bg_color']) : '#00b294',
4565 - esc_attr($disabled)
4566 - );
4567 -
4568 - if (!$this->is_activated) {
4569 - echo '<div class="pro-feature-overlay">';
4570 - echo '<a href="https://mxchat.ai/" target="_blank">';
4571 - echo '<img src="' . esc_url(plugin_dir_url(__FILE__) . '../images/pro-only-dark.png') . '" alt="' . esc_attr__('Pro Only', 'mxchat') . '" />';
4572 - echo '</a>';
4573 1159 echo '</div>';
4574 1160 }
4575 - echo '</div>';
4576 -}
4577 1161
4578 -public function mxchat_send_button_font_color_callback() {
4579 - $disabled = $this->is_activated ? '' : 'disabled';
4580 - $class = $this->is_activated ? 'pro-feature-wrapper active' : 'pro-feature-wrapper inactive';
1162 + public function mxchat_bot_message_bg_color_callback() {
1163 + $disabled = $this->is_activated ? '' : 'disabled';
4581 1164
4582 - echo '<div class="' . esc_attr($class) . '">';
4583 - echo sprintf(
4584 - '<input type="text"
4585 - id="send_button_font_color"
4586 - name="send_button_font_color"
4587 - value="%s"
4588 - class="my-color-field"
4589 - data-default-color="#ffffff"
4590 - %s />',
4591 - isset($this->options['send_button_font_color']) ? esc_attr($this->options['send_button_font_color']) : '#ffffff',
4592 - esc_attr($disabled)
4593 - );
1165 + echo '<div class="pro-feature-wrapper">';
1166 + printf(
1167 + '<input type="text" id="bot_message_bg_color" name="mxchat_options[bot_message_bg_color]" value="%s" class="my-color-field" data-default-color="#e1e1e1" %s />',
1168 + isset($this->options['bot_message_bg_color']) ? esc_attr($this->options['bot_message_bg_color']) : '',
1169 + esc_attr($disabled)
1170 + );
4594 1171
4595 - if (!$this->is_activated) {
4596 - echo '<div class="pro-feature-overlay">';
4597 - echo '<a href="https://mxchat.ai/" target="_blank">';
4598 - echo '<img src="' . esc_url(plugin_dir_url(__FILE__) . '../images/pro-only-dark.png') . '" alt="' . esc_attr__('Pro Only', 'mxchat') . '" />';
4599 - echo '</a>';
4600 - echo '</div>';
4601 - }
4602 - echo '</div>';
4603 -}
1172 + if (!$this->is_activated) {
1173 + echo '<div class="pro-feature-overlay">';
1174 + echo '<a href="https://mxchat.ai/" target="_blank"><img src="' . plugin_dir_url(__FILE__) . '../images/pro-only-dark.png" alt="Pro Only" /></a>';
1175 + echo '</div>';
1176 + }
4604 1177
4605 -public function mxchat_chatbot_background_color_callback() {
4606 - $disabled = $this->is_activated ? '' : 'disabled';
4607 - $class = $this->is_activated ? 'pro-feature-wrapper active' : 'pro-feature-wrapper inactive';
4608 -
4609 - echo '<div class="' . esc_attr($class) . '">';
4610 - echo sprintf(
4611 - '<input type="text"
4612 - id="chatbot_background_color"
4613 - name="chatbot_background_color"
4614 - value="%s"
4615 - class="my-color-field"
4616 - data-default-color="#000000"
4617 - %s />',
4618 - isset($this->options['chatbot_background_color']) ? esc_attr($this->options['chatbot_background_color']) : '#000000',
4619 - esc_attr($disabled)
4620 - );
4621 -
4622 - if (!$this->is_activated) {
4623 - echo '<div class="pro-feature-overlay">';
4624 - echo '<a href="https://mxchat.ai/" target="_blank">';
4625 - echo '<img src="' . esc_url(plugin_dir_url(__FILE__) . '../images/pro-only-dark.png') . '" alt="' . esc_attr__('Pro Only', 'mxchat') . '" />';
4626 - echo '</a>';
4627 1178 echo '</div>';
4628 1179 }
4629 - echo '</div>';
4630 -}
4631 1180
4632 -public function mxchat_icon_color_callback() {
4633 - $disabled = $this->is_activated ? '' : 'disabled';
4634 - $class = $this->is_activated ? 'pro-feature-wrapper active' : 'pro-feature-wrapper inactive';
1181 + public function mxchat_bot_message_font_color_callback() {
1182 + $disabled = $this->is_activated ? '' : 'disabled';
4635 1183
4636 - echo '<div class="' . esc_attr($class) . '">';
4637 - echo sprintf(
4638 - '<input type="text"
4639 - id="icon_color"
4640 - name="icon_color"
4641 - value="%s"
4642 - class="my-color-field"
4643 - data-default-color="#ffffff"
4644 - %s />',
4645 - isset($this->options['icon_color']) ? esc_attr($this->options['icon_color']) : '#ffffff',
4646 - esc_attr($disabled)
4647 - );
4648 -
4649 - if (!$this->is_activated) {
4650 - echo '<div class="pro-feature-overlay">';
4651 - echo '<a href="https://mxchat.ai/" target="_blank">';
4652 - echo '<img src="' . esc_url(plugin_dir_url(__FILE__) . '../images/pro-only-dark.png') . '" alt="' . esc_attr__('Pro Only', 'mxchat') . '" />';
4653 - echo '</a>';
4654 - echo '</div>';
4655 - }
4656 - echo '</div>';
4657 -}
4658 -
4659 -public function mxchat_custom_icon_callback() {
4660 - $disabled = $this->is_activated ? '' : 'disabled';
4661 - $class = $this->is_activated ? 'pro-feature-wrapper active' : 'pro-feature-wrapper inactive';
4662 - $custom_icon_url = isset($this->options['custom_icon']) ? esc_url($this->options['custom_icon']) : '';
4663 -
4664 - echo '<div class="' . esc_attr($class) . '">';
4665 - echo sprintf(
4666 - '<input type="url"
4667 - id="custom_icon"
4668 - name="custom_icon"
4669 - value="%s"
4670 - placeholder="%s"
4671 - class="regular-text"
4672 - %s />',
4673 - $custom_icon_url,
4674 - esc_attr__('Enter PNG URL', 'mxchat'),
4675 - esc_attr($disabled)
4676 - );
4677 -
4678 - // Preview container for the icon
4679 - if (!empty($custom_icon_url)) {
4680 - echo '<div class="icon-preview" style="margin-top: 10px;">';
4681 - echo '<img src="' . esc_url($custom_icon_url) . '" alt="' . esc_attr__('Custom Icon Preview', 'mxchat') . '" style="max-width: 48px; height: auto;" />';
4682 - echo '</div>';
4683 - }
4684 -
4685 - echo '<p class="description">' . esc_html__('Upload your PNG icon and paste the URL here. Recommended size: 48x48 pixels.', 'mxchat') . '</p>';
4686 -
4687 - if (!$this->is_activated) {
4688 - echo '<div class="pro-feature-overlay">';
4689 - echo '<a href="https://mxchat.ai/" target="_blank">';
4690 - echo '<img src="' . esc_url(plugin_dir_url(__FILE__) . '../images/pro-only-dark.png') . '" alt="' . esc_attr__('Pro Only', 'mxchat') . '" />';
4691 - echo '</a>';
4692 - echo '</div>';
4693 - }
4694 - echo '</div>';
4695 -}
4696 -
4697 -public function mxchat_title_icon_callback() {
4698 - $disabled = $this->is_activated ? '' : 'disabled';
4699 - $class = $this->is_activated ? 'pro-feature-wrapper active' : 'pro-feature-wrapper inactive';
4700 - // Fixed the variable reference - it was using custom_icon instead of title_icon
4701 - $title_icon_url = isset($this->options['title_icon']) ? esc_url($this->options['title_icon']) : '';
4702 -
4703 - echo '<div class="' . esc_attr($class) . '">';
4704 - echo sprintf(
4705 - '<input type="url"
4706 - id="title_icon"
4707 - name="title_icon"
4708 - value="%s"
4709 - placeholder="%s"
4710 - class="regular-text"
4711 - %s />',
4712 - $title_icon_url,
4713 - esc_attr__('Enter PNG URL', 'mxchat'),
4714 - esc_attr($disabled)
4715 - );
4716 -
4717 - // Preview container for the icon
4718 - if (!empty($title_icon_url)) {
4719 - echo '<div class="icon-preview" style="margin-top: 10px;">';
4720 - echo '<img src="' . esc_url($title_icon_url) . '" alt="' . esc_attr__('Title Icon Preview', 'mxchat') . '" style="max-width: 48px; height: auto;" />';
4721 - echo '</div>';
4722 - }
4723 -
4724 - echo '<p class="description">' . esc_html__('Upload your PNG icon and paste the URL here. Recommended size: 48x48 pixels.', 'mxchat') . '</p>';
4725 -
4726 - if (!$this->is_activated) {
4727 - echo '<div class="pro-feature-overlay">';
4728 - echo '<a href="https://mxchat.ai/" target="_blank">';
4729 - echo '<img src="' . esc_url(plugin_dir_url(__FILE__) . '../images/pro-only-dark.png') . '" alt="' . esc_attr__('Pro Only', 'mxchat') . '" />';
4730 - echo '</a>';
4731 - echo '</div>';
4732 - }
4733 - echo '</div>';
4734 -}
4735 -
4736 -public function mxchat_chat_input_font_color_callback() {
4737 - $disabled = $this->is_activated ? '' : 'disabled';
4738 - $class = $this->is_activated ? 'pro-feature-wrapper active' : 'pro-feature-wrapper inactive';
4739 -
4740 - echo '<div class="' . esc_attr($class) . '">';
4741 - echo sprintf(
4742 - '<input type="text"
4743 - id="chat_input_font_color"
4744 - name="chat_input_font_color"
4745 - value="%s"
4746 - class="my-color-field"
4747 - data-default-color="#555555"
4748 - %s />',
4749 - isset($this->options['chat_input_font_color']) ? esc_attr($this->options['chat_input_font_color']) : '#555555',
4750 - esc_attr($disabled)
4751 - );
4752 -
4753 - if (!$this->is_activated) {
4754 - echo '<div class="pro-feature-overlay">';
4755 - echo '<a href="https://mxchat.ai/" target="_blank">';
4756 - echo '<img src="' . esc_url(plugin_dir_url(__FILE__) . '../images/pro-only-dark.png') . '" alt="' . esc_attr__('Pro Only', 'mxchat') . '" />';
4757 - echo '</a>';
4758 - echo '</div>';
4759 - }
4760 - echo '</div>';
4761 -}
4762 -
4763 -public function mxchat_append_to_body_callback() {
4764 - // Get value from options array, default to 'off'
4765 - $append_to_body = isset($this->options['append_to_body']) ? $this->options['append_to_body'] : 'off';
4766 - $checked = ($append_to_body === 'on') ? 'checked' : '';
4767 -
4768 - echo '<label class="toggle-switch">';
4769 - echo sprintf(
4770 - '<input type="checkbox" id="append_to_body" name="append_to_body" value="on" %s />',
4771 - esc_attr($checked)
4772 - );
4773 - echo '<span class="slider"></span>';
4774 - echo '</label>';
4775 - echo '<p class="description">' .
4776 - esc_html__('Show chatbot automatically on all pages. When disabled, you can place the chatbot manually using shortcode [mxchat_chatbot floating="yes"].', 'mxchat') .
4777 - '</p>';
4778 -
4779 -}
4780 -
4781 -
4782 -
4783 -public function mxchat_privacy_toggle_callback() {
4784 - // Load from mxchat_options array
4785 - $options = get_option('mxchat_options', []);
4786 -
4787 - // Get privacy toggle value with fallback
4788 - $privacy_toggle = isset($options['privacy_toggle']) ? $options['privacy_toggle'] : 'off';
4789 - $checked = ($privacy_toggle === 'on') ? 'checked' : '';
4790 -
4791 - // Get privacy text with fallback
4792 - $privacy_text = isset($options['privacy_text'])
4793 - ? $options['privacy_text']
4794 - : __('By chatting, you agree to our <a href="https://example.com/privacy-policy" target="_blank">privacy policy</a>.', 'mxchat');
4795 -
4796 - // Output the toggle switch
4797 - echo '<label class="toggle-switch">';
4798 - echo sprintf(
4799 - '<input type="checkbox" id="privacy_toggle" name="privacy_toggle" value="on" %s />',
4800 - esc_attr($checked)
4801 - );
4802 - echo '<span class="slider"></span>';
4803 - echo '</label>';
4804 - echo '<p class="description">' . esc_html__('Enable this option to display a privacy notice below the chat widget.', 'mxchat') . '</p>';
4805 -
4806 - // Output the custom text input field
4807 - echo sprintf(
4808 - '<textarea id="privacy_text" name="privacy_text" rows="5" cols="50" class="regular-text">%s</textarea>',
4809 - esc_textarea($privacy_text)
4810 - );
4811 - echo '<p class="description">' . esc_html__('Enter the privacy policy text. You can include HTML links.', 'mxchat') . '</p>';
4812 -}
4813 -
4814 -
4815 -public function mxchat_complianz_toggle_callback() {
4816 - // Load from mxchat_options array
4817 - $options = get_option('mxchat_options', []);
4818 -
4819 - // Get complianz toggle value with fallback
4820 - $complianz_toggle = isset($options['complianz_toggle']) ? $options['complianz_toggle'] : 'off';
4821 - $checked = ($complianz_toggle === 'on') ? 'checked' : '';
4822 -
4823 - // Output the toggle switch
4824 - echo '<label class="toggle-switch">';
4825 - echo sprintf(
4826 - '<input type="checkbox" id="complianz_toggle" name="complianz_toggle" value="on" %s />',
4827 - esc_attr($checked)
4828 - );
4829 - echo '<span class="slider"></span>';
4830 - echo '</label>';
4831 -
4832 - echo '<p class="description">' . esc_html__('Enable this option to apply Complianz consent logic to the chatbot (must have Complianz Plugin).', 'mxchat') . '</p>';
4833 -}
4834 -
4835 -public function mxchat_link_target_toggle_callback() {
4836 - // Load from mxchat_options array
4837 - $options = get_option('mxchat_options', []);
4838 -
4839 - // Get link target toggle value with fallback
4840 - $link_target_toggle = isset($options['link_target_toggle']) ? $options['link_target_toggle'] : 'off';
4841 - $checked = ($link_target_toggle === 'on') ? 'checked' : '';
4842 -
4843 - // Output the toggle switch
4844 - echo '<label class="toggle-switch">';
4845 - echo sprintf(
4846 - '<input type="checkbox" id="link_target_toggle" name="link_target_toggle" value="on" %s />',
4847 - esc_attr($checked)
4848 - );
4849 - echo '<span class="slider"></span>';
4850 - echo '</label>';
4851 - echo '<p class="description">' . esc_html__('Enable to open links in a new tab (default is to open in the same tab).', 'mxchat') . '</p>';
4852 -}
4853 -
4854 -public function mxchat_chat_persistence_toggle_callback() {
4855 - // Load from mxchat_options array
4856 - $options = get_option('mxchat_options', []);
4857 -
4858 - // Get chat persistence toggle value with fallback
4859 - $chat_persistence_toggle = isset($options['chat_persistence_toggle']) ? $options['chat_persistence_toggle'] : 'off';
4860 - $checked = ($chat_persistence_toggle === 'on') ? 'checked' : '';
4861 -
4862 - // Output the toggle switch
4863 - echo '<label class="toggle-switch">';
4864 - echo sprintf(
4865 - '<input type="checkbox" id="chat_persistence_toggle" name="chat_persistence_toggle" value="on" %s />',
4866 - esc_attr($checked)
4867 - );
4868 - echo '<span class="slider"></span>';
4869 - echo '</label>';
4870 -
4871 - echo '<p class="description">' . esc_html__('Enable to keep chat history when users navigate tabs or return to the site within 24 hours.', 'mxchat') . '</p>';
4872 -}
4873 -
4874 -public function mxchat_popular_question_1_callback() {
4875 - // Load the full plugin options array
4876 - $all_options = get_option('mxchat_options', []);
4877 -
4878 - // Retrieve the specific option for popular_question_1
4879 - $popular_question_1 = isset($all_options['popular_question_1']) ? $all_options['popular_question_1'] : '';
4880 -
4881 - // Render the input field
4882 - printf(
4883 - '<input type="text" id="popular_question_1" name="popular_question_1" value="%s" placeholder="%s" class="regular-text" />',
4884 - esc_attr($popular_question_1),
4885 - esc_attr__('Enter Quick Question 1', 'mxchat')
4886 - );
4887 -
4888 - // Add a description for the field
4889 - echo '<p class="description">' . esc_html__('This will be the first Quick Question in the chatbot, displayed above the input field.', 'mxchat') . '</p>';
4890 -}
4891 -
4892 -
4893 -public function mxchat_popular_question_2_callback() {
4894 - // Load the full plugin options array
4895 - $all_options = get_option('mxchat_options', []);
4896 -
4897 - // Retrieve the specific option for popular_question_2
4898 - $popular_question_2 = isset($all_options['popular_question_2']) ? $all_options['popular_question_2'] : '';
4899 -
4900 - // Render the input field
4901 - printf(
4902 - '<input type="text" id="popular_question_2" name="popular_question_2" value="%s" placeholder="%s" class="regular-text" />',
4903 - esc_attr($popular_question_2),
4904 - esc_attr__('Enter Quick Question 2', 'mxchat')
4905 - );
4906 -
4907 - // Add a description for the field
4908 - echo '<p class="description">' . esc_html__('This will be the second Quick Question in the chatbot.', 'mxchat') . '</p>';
4909 -}
4910 -
4911 -
4912 -public function mxchat_popular_question_3_callback() {
4913 - // Load the full plugin options array
4914 - $all_options = get_option('mxchat_options', []);
4915 -
4916 - // Retrieve the specific option for popular_question_3
4917 - $popular_question_3 = isset($all_options['popular_question_3']) ? $all_options['popular_question_3'] : '';
4918 -
4919 - // Render the input field
4920 - printf(
4921 - '<input type="text" id="popular_question_3" name="popular_question_3" value="%s" placeholder="%s" class="regular-text" />',
4922 - esc_attr($popular_question_3),
4923 - esc_attr(__('Enter Quick Question 3', 'mxchat'))
4924 - );
4925 -
4926 - // Add a description for the field
4927 - echo '<p class="description">' . esc_html__('This will be the third Quick Question in the chatbot.', 'mxchat') . '</p>';
4928 -}
4929 -
4930 -public function mxchat_additional_popular_questions_callback() {
4931 - $options = get_option('mxchat_options', []);
4932 - $additional_questions = isset($options['additional_popular_questions'])
4933 - ? $options['additional_popular_questions']
4934 - : get_option('additional_popular_questions', array());
4935 -
4936 - echo '<div id="mxchat-additional-questions-container">';
4937 - if (!empty($additional_questions)) {
4938 - foreach ($additional_questions as $index => $question) {
4939 - printf(
4940 - '<div class="mxchat-question-row">
4941 - <input type="text" name="additional_popular_questions[]"
4942 - value="%s"
4943 - placeholder="%s"
4944 - class="regular-text mxchat-question-input"
4945 - data-question-index="%d" />
4946 - <button type="button" class="button mxchat-remove-question"
4947 - aria-label="%s">%s</button>
4948 - </div>',
4949 - esc_attr($question),
4950 - esc_attr(sprintf(__('Enter Additional Quick Question %d', 'mxchat'), $index + 4)),
4951 - $index,
4952 - esc_attr(__('Remove question', 'mxchat')),
4953 - esc_html__('Remove', 'mxchat')
4954 - );
4955 - }
4956 - } else {
1184 + echo '<div class="pro-feature-wrapper">';
4957 1185 printf(
4958 - '<div class="mxchat-question-row">
4959 - <input type="text" name="additional_popular_questions[]"
4960 - value=""
4961 - placeholder="%s"
4962 - class="regular-text mxchat-question-input"
4963 - data-question-index="0" />
4964 - <button type="button" class="button mxchat-remove-question"
4965 - aria-label="%s">%s</button>
4966 - </div>',
4967 - esc_attr(__('Enter Additional Quick Question 4', 'mxchat')),
4968 - esc_attr(__('Remove question', 'mxchat')),
4969 - esc_html__('Remove', 'mxchat')
1186 + '<input type="text" id="bot_message_font_color" name="mxchat_options[bot_message_font_color]" value="%s" class="my-color-field" data-default-color="#333333" %s />',
1187 + isset($this->options['bot_message_font_color']) ? esc_attr($this->options['bot_message_font_color']) : '',
1188 + esc_attr($disabled)
4970 1189 );
4971 - }
4972 - echo '</div>';
4973 - printf(
4974 - '<button type="button" class="button mxchat-add-question" aria-label="%s">%s</button>',
4975 - esc_attr(__('Add question', 'mxchat')),
4976 - esc_html__('Add Question', 'mxchat')
4977 - );
4978 - echo '<p class="description">' . esc_html__('Add as many Quick Questions as you need.', 'mxchat') . '</p>';
4979 - echo '</div>';
4980 -}
4981 1190
4982 -public function mxchat_brave_api_key_callback() {
4983 - $brave_api_key = isset($this->options['brave_api_key']) ? esc_attr($this->options['brave_api_key']) : '';
1191 + if (!$this->is_activated) {
1192 + echo '<div class="pro-feature-overlay">';
1193 + echo '<a href="https://mxchat.ai/" target="_blank"><img src="' . plugin_dir_url(__FILE__) . '../images/pro-only-dark.png" alt="Pro Only" /></a>';
1194 + echo '</div>';
1195 + }
4984 1196
4985 - echo '<div class="api-key-wrapper">';
4986 - echo sprintf(
4987 - '<input type="password" id="brave_api_key" name="brave_api_key" value="%s" class="regular-text" />',
4988 - $brave_api_key
4989 - );
4990 - echo '<button type="button" id="toggleBraveApiKeyVisibility">' . esc_html__('Show', 'mxchat') . '</button>';
4991 - echo '</div>';
4992 - echo '<p class="description">' . __('Enter your Brave Search API Key here. (See FAQ for details)', 'mxchat') . '</p>';
4993 -}
4994 -
4995 -public function mxchat_brave_image_count_callback() {
4996 - $brave_image_count = isset($this->options['brave_image_count'])
4997 - ? intval($this->options['brave_image_count'])
4998 - : 4;
4999 -
5000 - echo sprintf(
5001 - '<input type="number" id="brave_image_count" name="brave_image_count"
5002 - value="%d" min="1" max="6" class="small-text" />',
5003 - $brave_image_count
5004 - );
5005 - echo '<p class="description">' . __('Select the number of images to return (1-6).', 'mxchat') . '</p>';
5006 -}
5007 -
5008 -public function mxchat_brave_safe_search_callback() {
5009 - $brave_safe_search = isset($this->options['brave_safe_search'])
5010 - ? esc_attr($this->options['brave_safe_search'])
5011 - : 'strict';
5012 -
5013 - echo '<select id="brave_safe_search" name="brave_safe_search">';
5014 - echo sprintf(
5015 - '<option value="strict" %s>%s</option>',
5016 - selected($brave_safe_search, 'strict', false),
5017 - __('Strict', 'mxchat')
5018 - );
5019 - echo sprintf(
5020 - '<option value="off" %s>%s</option>',
5021 - selected($brave_safe_search, 'off', false),
5022 - __('Off', 'mxchat')
5023 - );
5024 - echo '</select>';
5025 - echo '<p class="description">' .
5026 - esc_html__('Set the Safe Search level for image searches. Brave Search only supports "Strict" and "Off" options.', 'mxchat') .
5027 - '</p>';
5028 -}
5029 -
5030 -public function mxchat_brave_news_count_callback() {
5031 - $brave_news_count = isset($this->options['brave_news_count'])
5032 - ? intval($this->options['brave_news_count'])
5033 - : 3;
5034 -
5035 - echo sprintf(
5036 - '<input type="number" id="brave_news_count" name="brave_news_count"
5037 - value="%d" min="1" max="10" class="small-text" />',
5038 - $brave_news_count
5039 - );
5040 - echo '<p class="description">' . esc_html__('Select the number of news articles to retrieve (1-10).', 'mxchat') . '</p>';
5041 -}
5042 -
5043 -public function mxchat_brave_country_callback() {
5044 - $brave_country = isset($this->options['brave_country'])
5045 - ? esc_attr($this->options['brave_country'])
5046 - : 'us';
5047 -
5048 - echo sprintf(
5049 - '<input type="text" id="brave_country" name="brave_country"
5050 - value="%s" maxlength="2" class="small-text" />',
5051 - $brave_country
5052 - );
5053 - echo '<p class="description">' . esc_html__('Enter the country code (e.g., "us" for United States).', 'mxchat') . '</p>';
5054 -}
5055 -
5056 -public function mxchat_brave_language_callback() {
5057 - $brave_language = isset($this->options['brave_language'])
5058 - ? esc_attr($this->options['brave_language'])
5059 - : 'en';
5060 -
5061 - echo sprintf(
5062 - '<input type="text" id="brave_language" name="brave_language"
5063 - value="%s" maxlength="2" class="small-text" />',
5064 - $brave_language
5065 - );
5066 - echo '<p class="description">' . esc_html__('Enter the language code (e.g., "en" for English).', 'mxchat') . '</p>';
5067 -}
5068 -
5069 -
5070 -
5071 -
5072 -
5073 -// Section Callback
5074 -public function mxchat_pdf_intent_section_callback() {
5075 - echo '<p>' . esc_html__('Configure the intent settings for the Chat with PDF feature.', 'mxchat') . '</p>';
5076 -}
5077 -
5078 -public function mxchat_chat_toolbar_toggle_callback() {
5079 - // Get chat toolbar toggle value with fallback
5080 - $chat_toolbar_toggle = isset($this->options['chat_toolbar_toggle']) ? $this->options['chat_toolbar_toggle'] : 'off';
5081 - $checked = ($chat_toolbar_toggle === 'on') ? 'checked' : '';
5082 -
5083 - // Check if the plugin is activated (paid feature)
5084 - $disabled = $this->is_activated ? '' : 'disabled';
5085 - $class = $this->is_activated ? 'pro-feature-wrapper active' : 'pro-feature-wrapper inactive';
5086 -
5087 - echo '<div class="' . esc_attr($class) . '">';
5088 -
5089 - // Output the toggle switch
5090 - echo '<label class="toggle-switch">';
5091 - echo sprintf(
5092 - '<input type="checkbox" id="chat_toolbar_toggle" name="chat_toolbar_toggle" value="on" %s %s />',
5093 - esc_attr($checked),
5094 - esc_attr($disabled)
5095 - );
5096 - echo '<span class="slider"></span>';
5097 - echo '</label>';
5098 -
5099 - // Pro feature overlay
5100 - if (!$this->is_activated) {
5101 - echo '<div class="pro-feature-overlay">';
5102 - echo '<a href="https://mxchat.ai/" target="_blank">';
5103 - echo '<img src="' . esc_url(plugin_dir_url(__FILE__) . '../images/pro-only-dark.png') . '" alt="' . esc_attr__('Pro Only', 'mxchat') . '" />';
5104 - echo '</a>';
5105 - echo '</div>';
5106 - }
5107 -
5108 - echo '</div>';
5109 - echo '<p class="description">' . esc_html__('Enable to display the chat toolbar, adding two icons below the chatbot input field for uploading PDF and Word documents (default is hidden).', 'mxchat') . '</p>';
5110 -}
5111 -
5112 -
5113 -public function mxchat_pdf_intent_trigger_text_callback() {
5114 - $disabled = $this->is_activated ? '' : 'disabled';
5115 - $class = $this->is_activated ? 'pro-feature-wrapper active' : 'pro-feature-wrapper inactive';
5116 - $default_text = __("Please provide the URL to the PDF you'd like to discuss.", 'mxchat');
5117 -
5118 - echo '<div class="' . esc_attr($class) . '">';
5119 - echo sprintf(
5120 - '<textarea id="pdf_intent_trigger_text"
5121 - name="pdf_intent_trigger_text"
5122 - rows="3"
5123 - cols="50"
5124 - placeholder="%s"
5125 - %s>%s</textarea>',
5126 - esc_attr__('Enter trigger text', 'mxchat'),
5127 - esc_attr($disabled),
5128 - isset($this->options['pdf_intent_trigger_text'])
5129 - ? esc_textarea($this->options['pdf_intent_trigger_text'])
5130 - : esc_textarea($default_text)
5131 - );
5132 - echo '<p class="description">' . esc_html__('Text displayed when the intent is triggered.', 'mxchat') . '</p>';
5133 -
5134 - if (!$this->is_activated) {
5135 - echo '<div class="pro-feature-overlay">';
5136 - echo '<a href="https://mxchat.ai/" target="_blank">';
5137 - echo '<img src="' . esc_url(plugin_dir_url(__FILE__) . '../images/pro-only-dark.png') . '" alt="' . esc_attr__('Pro Only', 'mxchat') . '" />';
5138 - echo '</a>';
5139 1197 echo '</div>';
5140 1198 }
5141 - echo '</div>';
5142 -}
5143 1199
5144 -public function mxchat_pdf_intent_success_text_callback() {
5145 - $disabled = $this->is_activated ? '' : 'disabled';
5146 - $class = $this->is_activated ? 'pro-feature-wrapper active' : 'pro-feature-wrapper inactive';
5147 - $default_text = __("I've processed the PDF. What questions do you have about it?", 'mxchat');
1200 + public function mxchat_top_bar_bg_color_callback() {
1201 + $disabled = $this->is_activated ? '' : 'disabled';
5148 1202
5149 - echo '<div class="' . esc_attr($class) . '">';
5150 - echo sprintf(
5151 - '<textarea id="pdf_intent_success_text"
5152 - name="pdf_intent_success_text"
5153 - rows="3"
5154 - cols="50"
5155 - placeholder="%s"
5156 - %s>%s</textarea>',
5157 - esc_attr__('Enter success text', 'mxchat'),
5158 - esc_attr($disabled),
5159 - isset($this->options['pdf_intent_success_text'])
5160 - ? esc_textarea($this->options['pdf_intent_success_text'])
5161 - : esc_textarea($default_text)
5162 - );
5163 - echo '<p class="description">' . esc_html__('Text displayed when the intent is successful.', 'mxchat') . '</p>';
1203 + echo '<div class="pro-feature-wrapper">';
1204 + printf(
1205 + '<input type="text" id="top_bar_bg_color" name="mxchat_options[top_bar_bg_color]" value="%s" class="my-color-field" data-default-color="#00b294" %s />',
1206 + isset($this->options['top_bar_bg_color']) ? esc_attr($this->options['top_bar_bg_color']) : '',
1207 + esc_attr($disabled)
1208 + );
5164 1209
5165 - if (!$this->is_activated) {
5166 - echo '<div class="pro-feature-overlay">';
5167 - echo '<a href="https://mxchat.ai/" target="_blank">';
5168 - echo '<img src="' . esc_url(plugin_dir_url(__FILE__) . '../images/pro-only-dark.png') . '" alt="' . esc_attr__('Pro Only', 'mxchat') . '" />';
5169 - echo '</a>';
5170 - echo '</div>';
5171 - }
5172 - echo '</div>';
5173 -}
1210 + if (!$this->is_activated) {
1211 + echo '<div class="pro-feature-overlay">';
1212 + echo '<a href="https://mxchat.ai/" target="_blank"><img src="' . plugin_dir_url(__FILE__) . '../images/pro-only-dark.png" alt="Pro Only" /></a>';
1213 + echo '</div>';
1214 + }
5174 1215
5175 -public function mxchat_pdf_intent_error_text_callback() {
5176 - $disabled = $this->is_activated ? '' : 'disabled';
5177 - $class = $this->is_activated ? 'pro-feature-wrapper active' : 'pro-feature-wrapper inactive';
5178 - $default_text = __("Sorry, I couldn't process the PDF. Please ensure it's a valid file.", 'mxchat');
5179 -
5180 - echo '<div class="' . esc_attr($class) . '">';
5181 - echo sprintf(
5182 - '<textarea id="pdf_intent_error_text"
5183 - name="pdf_intent_error_text"
5184 - rows="3"
5185 - cols="50"
5186 - placeholder="%s"
5187 - %s>%s</textarea>',
5188 - esc_attr__('Enter error text', 'mxchat'),
5189 - esc_attr($disabled),
5190 - isset($this->options['pdf_intent_error_text'])
5191 - ? esc_textarea($this->options['pdf_intent_error_text'])
5192 - : esc_textarea($default_text)
5193 - );
5194 - echo '<p class="description">' . esc_html__('Text displayed when an error occurs during the intent.', 'mxchat') . '</p>';
5195 -
5196 - if (!$this->is_activated) {
5197 - echo '<div class="pro-feature-overlay">';
5198 - echo '<a href="https://mxchat.ai/" target="_blank">';
5199 - echo '<img src="' . esc_url(plugin_dir_url(__FILE__) . '../images/pro-only-dark.png') . '" alt="' . esc_attr__('Pro Only', 'mxchat') . '" />';
5200 - echo '</a>';
5201 1216 echo '</div>';
5202 1217 }
5203 - echo '</div>';
5204 -}
5205 1218
5206 -public function mxchat_pdf_max_pages_callback() {
5207 - $disabled = $this->is_activated ? '' : 'disabled';
5208 - $class = $this->is_activated ? 'pro-feature-wrapper active' : 'pro-feature-wrapper inactive';
5209 - $max_pages = isset($this->options['pdf_max_pages']) ? intval($this->options['pdf_max_pages']) : 69;
1219 + public function mxchat_send_button_font_color_callback() {
1220 + $disabled = $this->is_activated ? '' : 'disabled';
5210 1221
5211 - echo '<div class="' . esc_attr($class) . '">';
5212 - echo sprintf(
5213 - '<input type="range"
5214 - id="pdf_max_pages"
5215 - name="pdf_max_pages"
5216 - min="1"
5217 - max="69"
5218 - value="%d"
5219 - %s
5220 - class="range-slider" />',
5221 - esc_attr($max_pages),
5222 - esc_attr($disabled)
5223 - );
5224 - echo '<span id="pdf_max_pages_output">' . esc_html($max_pages) . '</span>';
5225 - echo '<p class="description">' . esc_html__('Set the maximum number of document pages users can upload for processing. (1-69 pages)', 'mxchat') . '</p>';
1222 + echo '<div class="pro-feature-wrapper">';
1223 + printf(
1224 + '<input type="text" id="send_button_font_color" name="mxchat_options[send_button_font_color]" value="%s" class="my-color-field" data-default-color="#ffffff" %s />',
1225 + isset($this->options['send_button_font_color']) ? esc_attr($this->options['send_button_font_color']) : '',
1226 + esc_attr($disabled)
1227 + );
5226 1228
5227 - if (!$this->is_activated) {
5228 - echo '<div class="pro-feature-overlay">';
5229 - echo '<a href="https://mxchat.ai/" target="_blank">';
5230 - echo '<img src="' . esc_url(plugin_dir_url(__FILE__) . '../images/pro-only-dark.png') . '" alt="' . esc_attr__('Pro Only', 'mxchat') . '" />';
5231 - echo '</a>';
5232 - echo '</div>';
5233 - }
5234 - echo '</div>';
5235 -}
1229 + if (!$this->is_activated) {
1230 + echo '<div class="pro-feature-overlay">';
1231 + echo '<a href="https://mxchat.ai/" target="_blank"><img src="' . plugin_dir_url(__FILE__) . '../images/pro-only-dark.png" alt="Pro Only" /></a>';
1232 + echo '</div>';
1233 + }
5236 1234
5237 -public function mxchat_live_agent_status_callback() {
5238 - $disabled = $this->is_activated ? '' : 'disabled';
5239 - $class = $this->is_activated ? 'pro-feature-wrapper active' : 'pro-feature-wrapper inactive';
5240 - $status = isset($this->options['live_agent_status']) ? $this->options['live_agent_status'] : 'off';
5241 -
5242 - echo '<div class="' . esc_attr($class) . '">';
5243 - echo '<label class="toggle-switch">';
5244 - echo sprintf(
5245 - '<input type="checkbox" id="live_agent_status" name="live_agent_status" value="on" %s %s />',
5246 - checked($status, 'on', false),
5247 - esc_attr($disabled)
5248 - );
5249 - echo '<span class="slider"></span>';
5250 - echo '</label>';
5251 - echo '<label for="live_agent_status" class="mxchat-status-label">';
5252 - echo '<span class="status-text">' . ($status === 'on' ? esc_html__('Online', 'mxchat') : esc_html__('Offline', 'mxchat')) . '</span>';
5253 - echo '</label>';
5254 -
5255 - if (!$this->is_activated) {
5256 - echo '<div class="pro-feature-overlay">';
5257 - echo '<a href="https://mxchat.ai/" target="_blank"><img src="' . plugin_dir_url(__FILE__) . '../images/pro-only-dark.png" alt="' . esc_attr__('Pro Only', 'mxchat') . '" /></a>';
5258 1235 echo '</div>';
5259 1236 }
5260 - echo '</div>';
5261 -}
5262 1237
1238 + public function mxchat_chatbot_background_color_callback() {
1239 + $disabled = $this->is_activated ? '' : 'disabled';
5263 1240
5264 -// Away Message Callback
5265 -public function mxchat_live_agent_away_message_callback() {
5266 - $disabled = $this->is_activated ? '' : 'disabled';
5267 - $class = $this->is_activated ? 'pro-feature-wrapper active' : 'pro-feature-wrapper inactive';
5268 - $message = isset($this->options['live_agent_away_message'])
5269 - ? $this->options['live_agent_away_message']
5270 - : __('Sorry, live agents are currently unavailable. I can continue helping you as an AI assistant.', 'mxchat');
1241 + echo '<div class="pro-feature-wrapper">';
1242 + printf(
1243 + '<input type="text" id="chatbot_background_color" name="mxchat_options[chatbot_background_color]" value="%s" class="my-color-field" data-default-color="#000000" %s />',
1244 + isset($this->options['chatbot_background_color']) ? esc_attr($this->options['chatbot_background_color']) : '',
1245 + esc_attr($disabled)
1246 + );
5271 1247
5272 - echo '<div class="' . esc_attr($class) . '">';
5273 - printf(
5274 - '<textarea id="live_agent_away_message" name="live_agent_away_message" rows="3" cols="50" %s>%s</textarea>',
5275 - esc_attr($disabled),
5276 - esc_textarea($message)
5277 - );
5278 - echo '<p class="description">' . esc_html__('Message shown when live agents are offline.', 'mxchat') . '</p>';
1248 + if (!$this->is_activated) {
1249 + echo '<div class="pro-feature-overlay">';
1250 + echo '<a href="https://mxchat.ai/" target="_blank"><img src="' . plugin_dir_url(__FILE__) . '../images/pro-only-dark.png" alt="Pro Only" /></a>';
1251 + echo '</div>';
1252 + }
5279 1253
5280 - if (!$this->is_activated) {
5281 - echo '<div class="pro-feature-overlay">';
5282 - echo '<a href="https://mxchat.ai/" target="_blank"><img src="' . plugin_dir_url(__FILE__) . '../images/pro-only-dark.png" alt="' . esc_attr__('Pro Only', 'mxchat') . '" /></a>';
5283 1254 echo '</div>';
5284 1255 }
5285 - echo '</div>';
5286 -}
5287 1256
5288 -public function mxchat_live_agent_notification_message_callback() {
5289 - $disabled = $this->is_activated ? '' : 'disabled';
5290 - $class = $this->is_activated ? 'pro-feature-wrapper active' : 'pro-feature-wrapper inactive';
5291 - $message = isset($this->options['live_agent_notification_message'])
5292 - ? $this->options['live_agent_notification_message']
5293 - : __('Live agent has been notified.', 'mxchat');
1257 + public function mxchat_icon_color_callback() {
1258 + $disabled = $this->is_activated ? '' : 'disabled';
5294 1259
5295 - echo '<div class="' . esc_attr($class) . '">';
5296 - printf(
5297 - '<textarea id="live_agent_notification_message" name="live_agent_notification_message" rows="3" cols="50" %s>%s</textarea>',
5298 - esc_attr($disabled),
5299 - esc_textarea($message)
5300 - );
5301 - echo '<p class="description">' . esc_html__('Message shown when live transfer activated.', 'mxchat') . '</p>';
1260 + echo '<div class="pro-feature-wrapper">';
1261 + printf(
1262 + '<input type="text" id="icon_color" name="mxchat_options[icon_color]" value="%s" class="my-color-field" data-default-color="#ffffff" %s />',
1263 + isset($this->options['icon_color']) ? esc_attr($this->options['icon_color']) : '',
1264 + esc_attr($disabled)
1265 + );
5302 1266
5303 - if (!$this->is_activated) {
5304 - echo '<div class="pro-feature-overlay">';
5305 - echo '<a href="https://mxchat.ai/" target="_blank"><img src="' . plugin_dir_url(__FILE__) . '../images/pro-only-dark.png" alt="' . esc_attr__('Pro Only', 'mxchat') . '" /></a>';
5306 - echo '</div>';
5307 - }
5308 - echo '</div>';
5309 -}
1267 + if (!$this->is_activated) {
1268 + echo '<div class="pro-feature-overlay">';
1269 + echo '<a href="https://mxchat.ai/" target="_blank"><img src="' . plugin_dir_url(__FILE__) . '../images/pro-only-dark.png" alt="Pro Only" /></a>';
1270 + echo '</div>';
1271 + }
5310 1272
5311 -public function mxchat_live_agent_webhook_url_callback() {
5312 - $disabled = $this->is_activated ? '' : 'disabled';
5313 - $class = $this->is_activated ? 'pro-feature-wrapper active' : 'pro-feature-wrapper inactive';
5314 - $webhook_url = isset($this->options['live_agent_webhook_url'])
5315 - ? esc_url($this->options['live_agent_webhook_url'])
5316 - : esc_url(get_option('live_agent_webhook_url', ''));
5317 -
5318 - echo '<div class="' . esc_attr($class) . '">';
5319 - printf(
5320 - '<input type="password" id="live_agent_webhook_url" name="live_agent_webhook_url" value="%s" class="regular-text" %s />',
5321 - $webhook_url,
5322 - esc_attr($disabled)
5323 - );
5324 - echo '<button type="button" id="toggleWebhookUrlVisibility">' . esc_html__('Show', 'mxchat') . '</button>';
5325 - echo '<p class="description">' . esc_html__('Enter your Slack webhook URL for live agent notifications.', 'mxchat') . '</p>';
5326 -
5327 - if (!$this->is_activated) {
5328 - echo '<div class="pro-feature-overlay">';
5329 - echo '<a href="https://mxchat.ai/" target="_blank"><img src="' . plugin_dir_url(__FILE__) . '../images/pro-only-dark.png" alt="' . esc_attr__('Pro Only', 'mxchat') . '" /></a>';
5330 1273 echo '</div>';
5331 1274 }
5332 - echo '</div>';
5333 -}
5334 1275
1276 + public function mxchat_chat_input_font_color_callback() {
1277 + $disabled = $this->is_activated ? '' : 'disabled';
5335 1278
5336 -public function mxchat_similarity_threshold_callback() {
5337 - // Load from mxchat_options array
5338 - $options = get_option('mxchat_options', []);
1279 + echo '<div class="pro-feature-wrapper">';
1280 + printf(
1281 + '<input type="text" id="chat_input_font_color" name="mxchat_options[chat_input_font_color]" value="%s" class="my-color-field" data-default-color="#555555" %s />',
1282 + isset($this->options['chat_input_font_color']) ? esc_attr($this->options['chat_input_font_color']) : '',
1283 + esc_attr($disabled)
1284 + );
5339 1285
5340 - // Get value with backwards compatibility
5341 - $threshold = isset($options['similarity_threshold'])
5342 - ? $options['similarity_threshold']
5343 - : get_option('mxchat_similarity_threshold', 80);
1286 + if (!$this->is_activated) {
1287 + echo '<div class="pro-feature-overlay">';
1288 + echo '<a href="https://mxchat.ai/" target="_blank"><img src="' . plugin_dir_url(__FILE__) . '../images/pro-only-dark.png" alt="Pro Only" /></a>';
1289 + echo '</div>';
1290 + }
5344 1291
5345 - echo '<div class="slider-container">';
5346 - echo sprintf(
5347 - '<input type="range"
5348 - id="similarity_threshold"
5349 - name="similarity_threshold"
5350 - min="70"
5351 - max="85"
5352 - step="1"
5353 - value="%s"
5354 - class="range-slider" />',
5355 - esc_attr($threshold)
5356 - );
5357 - echo sprintf(
5358 - '<span id="threshold_value" class="range-value">%s</span>',
5359 - esc_html($threshold)
5360 - );
5361 - echo '</div>';
5362 -
5363 - echo '<p class="description">';
5364 - echo esc_html__('Set the similarity threshold (recommended: 75) to balance accuracy; too high might limit your bot\'s ability to find relevant knowledge.', 'mxchat');
5365 - echo '</p>';
5366 -}
5367 -
5368 -
5369 -
5370 -public function mxchat_live_agent_secret_key_callback() {
5371 - $disabled = $this->is_activated ? '' : 'disabled';
5372 - $class = $this->is_activated ? 'pro-feature-wrapper active' : 'pro-feature-wrapper inactive';
5373 -
5374 - echo '<div class="' . esc_attr($class) . '">';
5375 - printf(
5376 - '<input type="password" id="live_agent_secret_key" name="live_agent_secret_key" value="%s" class="regular-text" %s />',
5377 - isset($this->options['live_agent_secret_key']) ? esc_attr($this->options['live_agent_secret_key']) : '',
5378 - esc_attr($disabled)
5379 - );
5380 - echo '<button type="button" id="toggleSecretKeyVisibility">' . esc_html__('Show', 'mxchat') . '</button>';
5381 - echo '<p class="description">' . esc_html__('Secret key for validating Slack requests. Keep this secure.', 'mxchat') . '</p>';
5382 -
5383 - if (!$this->is_activated) {
5384 - echo '<div class="pro-feature-overlay">';
5385 - echo '<a href="https://mxchat.ai/" target="_blank"><img src="' . plugin_dir_url(__FILE__) . '../images/pro-only-dark.png" alt="' . esc_attr__('Pro Only', 'mxchat') . '" /></a>';
5386 1292 echo '</div>';
5387 1293 }
5388 - echo '</div>';
5389 -}
5390 1294
5391 -public function mxchat_live_agent_bot_token_callback() {
5392 - $disabled = $this->is_activated ? '' : 'disabled';
5393 - $class = $this->is_activated ? 'pro-feature-wrapper active' : 'pro-feature-wrapper inactive';
5394 1295
5395 - echo '<div class="' . esc_attr($class) . '">';
1296 +public function mxchat_append_to_body_callback() {
1297 + $append_to_body_checked = isset($this->options['append_to_body']) && $this->options['append_to_body'] === 'on' ? 'checked' : '';
1298 + echo '<label class="toggle-switch-label" for="append_to_body">Append Chat Widget to Body:</label>';
1299 + echo '<label class="toggle-switch">';
5396 1300 printf(
5397 - '<input type="password" id="live_agent_bot_token" name="live_agent_bot_token" value="%s" class="regular-text" %s />',
5398 - isset($this->options['live_agent_bot_token']) ? esc_attr($this->options['live_agent_bot_token']) : '',
5399 - esc_attr($disabled)
1301 + '<input type="checkbox" id="append_to_body" name="mxchat_options[append_to_body]" %s />',
1302 + esc_attr($append_to_body_checked)
5400 1303 );
5401 - echo '<button type="button" id="toggleBotTokenVisibility">' . esc_html__('Show', 'mxchat') . '</button>';
5402 - echo '<p class="description">' . esc_html__('Your Slack Bot OAuth Token (starts with xoxb-). Keep this secure.', 'mxchat') . '</p>';
1304 + echo '<span class="slider"></span>';
1305 + echo '</label>';
1306 + echo '<p class="description">Enable to append the chat widget directly to the body element or use shortcode: [mxchat_chatbot floating="yes"]</p>';
1307 +}
5403 1308
5404 - if (!$this->is_activated) {
5405 - echo '<div class="pro-feature-overlay">';
5406 - echo '<a href="https://mxchat.ai/" target="_blank"><img src="' . plugin_dir_url(__FILE__) . '../images/pro-only-dark.png" alt="' . esc_attr__('Pro Only', 'mxchat') . '" /></a>';
5407 - echo '</div>';
5408 - }
5409 - echo '</div>';
5410 -}
5411 1309
5412 -public function mxchat_enqueue_admin_assets() {
5413 - wp_enqueue_style('wp-color-picker');
5414 1310
5415 - // Get the plugin version or file modification time for cache busting
5416 - $plugin_version = '2.0.5'; // Replace this with your plugin's version
5417 1311
5418 - // File paths
5419 - $color_picker_js_path = plugin_dir_path(__FILE__) . '../js/my-color-picker.js';
5420 - $embedding_check_js_path = plugin_dir_path(__FILE__) . '../js/embedding-check.js';
5421 - $admin_css_path = plugin_dir_path(__FILE__) . '../css/admin-style.css';
5422 - $knowledge_css_path = plugin_dir_path(__FILE__) . '../css/knowledge-style.css';
5423 - $intent_css_path = plugin_dir_path(__FILE__) . '../css/intent-style.css';
5424 1312
5425 - // Check if files exist and get modification times
5426 - $color_picker_version = file_exists($color_picker_js_path) ? filemtime($color_picker_js_path) : $plugin_version;
5427 - $embedding_check_version = file_exists($embedding_check_js_path) ? filemtime($embedding_check_js_path) : $plugin_version;
5428 - $admin_css_version = file_exists($admin_css_path) ? filemtime($admin_css_path) : $plugin_version;
5429 - $knowledge_css_version = file_exists($knowledge_css_path) ? filemtime($knowledge_css_path) : $plugin_version;
5430 - $intent_css_version = file_exists($intent_css_path) ? filemtime($intent_css_path) : $plugin_version;
1313 + public function mxchat_enqueue_admin_assets() {
1314 + wp_enqueue_style('wp-color-picker');
5431 1315
5432 - // Enqueue scripts and styles with corrected paths
5433 - wp_enqueue_script(
5434 - 'mxchat-color-picker',
5435 - plugin_dir_url(__FILE__) . '../js/my-color-picker.js',
5436 - array('wp-color-picker'),
5437 - $color_picker_version,
5438 - true
5439 - );
1316 + // Get the plugin version or file modification time for cache busting
1317 + $plugin_version = '1.0.6'; // Replace this with your plugin's version
5440 1318
5441 - wp_enqueue_script(
5442 - 'mxchat-embedding-check',
5443 - plugin_dir_url(__FILE__) . '../js/embedding-check.js',
5444 - array(),
5445 - $embedding_check_version,
5446 - true
5447 - );
1319 + // File paths
1320 + $color_picker_js_path = plugin_dir_path(__FILE__) . '../js/my-color-picker.js';
1321 + $embedding_check_js_path = plugin_dir_path(__FILE__) . '../js/embedding-check.js';
1322 + $admin_css_path = plugin_dir_path(__FILE__) . '../css/admin-style.css';
1323 + $transcripts_js_path = plugin_dir_path(__FILE__) . '../js/mxchat_transcripts.js';
5448 1324
5449 - wp_enqueue_script(
5450 - 'mxchat-admin-js',
5451 - plugin_dir_url(__FILE__) . '../js/mxchat-admin.js',
5452 - array('jquery'),
5453 - $plugin_version,
5454 - true
5455 - );
1325 + // Check if files exist and get modification times
1326 + $color_picker_version = file_exists($color_picker_js_path) ? filemtime($color_picker_js_path) : $plugin_version;
1327 + $embedding_check_version = file_exists($embedding_check_js_path) ? filemtime($embedding_check_js_path) : $plugin_version;
1328 + $admin_css_version = file_exists($admin_css_path) ? filemtime($admin_css_path) : $plugin_version;
1329 + $transcripts_js_version = file_exists($transcripts_js_path) ? filemtime($transcripts_js_path) : $plugin_version;
5456 1330
5457 - wp_localize_script('mxchat-admin-js', 'mxchatAdmin', array(
5458 - 'ajax_url' => admin_url('admin-ajax.php'),
5459 - 'license_nonce' => wp_create_nonce('mxchat_activate_license_nonce'),
5460 - 'inline_edit_nonce' => wp_create_nonce('mxchat_save_inline_nonce'),
5461 - 'setting_nonce' => wp_create_nonce('mxchat_save_setting_nonce'),
5462 - 'export_nonce' => wp_create_nonce('mxchat_export_transcripts'),
5463 - ));
1331 + // Enqueue scripts and styles with corrected paths
1332 + wp_enqueue_script(
1333 + 'mxchat-color-picker',
1334 + plugin_dir_url(__FILE__) . '../js/my-color-picker.js',
1335 + array('wp-color-picker'),
1336 + $color_picker_version,
1337 + true
1338 + );
5464 1339
5465 - // Enqueue the admin CSS
5466 - wp_enqueue_style(
5467 - 'mxchat-admin-css',
5468 - plugin_dir_url(__FILE__) . '../css/admin-style.css',
5469 - array(),
5470 - $admin_css_version
5471 - );
5472 -
5473 - if (isset($_GET['page']) && $_GET['page'] === 'mxchat-transcripts') {
5474 - wp_enqueue_style(
5475 - 'mxchat-chat-transcripts-css',
5476 - plugin_dir_url(__FILE__) . '../css/chat-transcripts.css',
1340 + wp_enqueue_script(
1341 + 'mxchat-embedding-check',
1342 + plugin_dir_url(__FILE__) . '../js/embedding-check.js',
5477 1343 array(),
5478 - $transcripts_css_version
1344 + $embedding_check_version,
1345 + true
5479 1346 );
5480 1347
5481 1348 wp_enqueue_script(
5482 1349 'mxchat-transcripts-js',
@@ -5484,515 +1351,278 @@
5484 1351 array('jquery'),
5485 1352 $transcripts_js_version,
5486 1353 true
5487 1354 );
5488 - }
5489 -
5490 - wp_enqueue_style(
5491 - 'mxchat-knowledge-css',
5492 - plugin_dir_url(__FILE__) . '../css/knowledge-style.css',
5493 - array(),
5494 - $knowledge_css_version
5495 - );
5496 1355
1356 + wp_enqueue_script(
1357 + 'mxchat-admin-js',
1358 + plugin_dir_url(__FILE__) . '../js/mxchat-admin.js',
1359 + array('jquery'),
1360 + $plugin_version,
1361 + true
1362 + );
5497 1363
5498 - wp_enqueue_style(
5499 - 'mxchat-intent-css',
5500 - plugin_dir_url(__FILE__) . '../css/intent-style.css',
5501 - array(),
5502 - $intent_css_version
5503 - );
1364 + wp_localize_script('mxchat-admin-js', 'mxchatAdmin', array(
1365 + 'ajax_url' => admin_url('admin-ajax.php'),
1366 + 'nonce' => wp_create_nonce('mxchat_activate_license_nonce'),
1367 + ));
5504 1368
5505 - // IMPORTANT: Use the same script handle as above for localizing mxchatPromptsAdmin
5506 - wp_localize_script( 'mxchat-admin-js', 'mxchatPromptsAdmin', array(
5507 - 'ajax_url' => admin_url( 'admin-ajax.php' ),
5508 - 'prompts_setting_nonce' => wp_create_nonce( 'mxchat_prompts_setting_nonce' ),
5509 - ) );
1369 + wp_enqueue_style(
1370 + 'mxchat-admin-css',
1371 + plugin_dir_url(__FILE__) . '../css/admin-style.css',
1372 + array(),
1373 + $admin_css_version
1374 + );
5510 1375
5511 - // Localize the script for color picker and settings
5512 - wp_localize_script('mxchat-color-picker', 'mxchatStyleSettings', array(
5513 - 'ajax_url' => admin_url('admin-ajax.php'),
5514 - 'link_target_toggle' => $this->options['link_target_toggle'] ?? 'off',
5515 - 'user_message_bg_color' => $this->options['user_message_bg_color'] ?? '#fff',
5516 - 'user_message_font_color' => $this->options['user_message_font_color'] ?? '#212121',
5517 - 'bot_message_bg_color' => $this->options['bot_message_bg_color'] ?? '#212121',
5518 - 'bot_message_font_color' => $this->options['bot_message_font_color'] ?? '#fff',
5519 - 'top_bar_bg_color' => $this->options['top_bar_bg_color'] ?? '#212121',
5520 - 'send_button_font_color' => $this->options['send_button_font_color'] ?? '#212121',
5521 - 'close_button_color' => $this->options['close_button_color'] ?? '#fff',
5522 - 'chatbot_background_color' => $this->options['chatbot_background_color'] ?? '#212121',
5523 - 'icon_color' => $this->options['icon_color'] ?? '#fff',
5524 - 'chat_input_font_color' => $this->options['chat_input_font_color'] ?? '#212121',
5525 - 'pre_chat_message' => $this->options['pre_chat_message'] ?? esc_html__('Hey there! Ask me anything!', 'mxchat'),
5526 - 'rate_limit_message' => $this->options['rate_limit_message'] ?? esc_html__('Rate limit exceeded. Please try again later.', 'mxchat'),
5527 - 'loops_api_key' => $this->options['loops_api_key'] ?? '',
5528 - 'loops_mailing_list' => $this->options['loops_mailing_list'] ?? '',
5529 - 'triggered_phrase_response' => $this->options['triggered_phrase_response'] ?? esc_html__('Would you like to join our mailing list? Please provide your email below.', 'mxchat'),
5530 - 'email_capture_response' => $this->options['email_capture_response'] ?? esc_html__('Thank you for providing your email! You\'ve been added to our list.', 'mxchat'),
5531 - 'pdf_intent_trigger_text' => $this->options['pdf_intent_trigger_text'] ?? esc_html__("Please provide the URL to the PDF you'd like to discuss.", 'mxchat'),
5532 - 'pdf_intent_success_text' => $this->options['pdf_intent_success_text'] ?? esc_html__("I've processed the PDF. What questions do you have about it?", 'mxchat'),
5533 - 'pdf_intent_error_text' => $this->options['pdf_intent_error_text'] ?? esc_html__("Sorry, I couldn't process the PDF. Please ensure it's a valid file.", 'mxchat'),
5534 - 'pdf_max_pages' => $this->options['pdf_max_pages'] ?? 69,
5535 - 'live_agent_webhook_url' => $this->options['live_agent_webhook_url'] ?? '',
5536 - 'live_agent_secret_key' => $this->options['live_agent_secret_key'] ?? '',
5537 - 'live_agent_bot_token' => $this->options['live_agent_bot_token'] ?? '',
5538 - 'live_agent_message_bg_color' => $this->options['live_agent_message_bg_color'] ?? '#ffffff',
5539 - 'live_agent_message_font_color' => $this->options['live_agent_message_font_color'] ?? '#333333',
5540 - 'chat_toolbar_toggle' => $this->options['chat_toolbar_toggle'] ?? 'off',
5541 - 'mode_indicator_bg_color' => $this->options['mode_indicator_bg_color'] ?? '#767676',
5542 - 'mode_indicator_font_color' => $this->options['mode_indicator_font_color'] ?? '#ffffff',
5543 - 'toolbar_icon_color' => $this->options['toolbar_icon_color'] ?? '#212121',
5544 - ));
5545 -}
5546 -
5547 -
5548 -public function mxchat_sanitize($input) {
5549 - $new_input = array();
5550 -
5551 - if (isset($input['api_key'])) {
5552 - $new_input['api_key'] = sanitize_text_field($input['api_key']);
1376 + // Use wp_json_encode for localizing script
1377 + wp_localize_script('mxchat-color-picker', 'mxchatStyleSettings', array(
1378 + 'ajax_url' => admin_url('admin-ajax.php'),
1379 + 'user_message_bg_color' => $this->options['user_message_bg_color'] ?? '#fff',
1380 + 'user_message_font_color' => $this->options['user_message_font_color'] ?? '#212121',
1381 + 'bot_message_bg_color' => $this->options['bot_message_bg_color'] ?? '#212121',
1382 + 'bot_message_font_color' => $this->options['bot_message_font_color'] ?? '#fff',
1383 + 'top_bar_bg_color' => $this->options['top_bar_bg_color'] ?? '#212121',
1384 + 'send_button_font_color' => $this->options['send_button_font_color'] ?? '#212121',
1385 + 'close_button_color' => $this->options['close_button_color'] ?? '#fff',
1386 + 'chatbot_background_color' => $this->options['chatbot_background_color'] ?? '#212121',
1387 + 'icon_color' => $this->options['icon_color'] ?? '#fff',
1388 + 'chat_input_font_color' => $this->options['chat_input_font_color'] ?? '#212121'
1389 + ));
5553 1390 }
5554 1391
5555 - if (isset($input['similarity_threshold'])) {
5556 - $new_input['similarity_threshold'] = absint($input['similarity_threshold']); // Ensure it's an integer
5557 - $new_input['similarity_threshold'] = min(max($new_input['similarity_threshold'], 70), 85); // Enforce range
5558 - }
1392 + public function mxchat_sanitize($input) {
1393 + $new_input = array();
5559 1394
5560 - if (isset($input['xai_api_key'])) {
5561 - $new_input['xai_api_key'] = sanitize_text_field($input['xai_api_key']);
5562 - }
1395 + if (isset($input['api_key'])) {
1396 + $new_input['api_key'] = sanitize_text_field($input['api_key']);
1397 + }
1398 +
1399 + if (isset($input['enable_woocommerce_integration'])) {
1400 + $new_input['enable_woocommerce_integration'] = isset($input['enable_woocommerce_integration']) && $input['enable_woocommerce_integration'] === '1' ? '1' : '0';
5563 1401
5564 - if (isset($input['claude_api_key'])) {
5565 - $new_input['claude_api_key'] = sanitize_text_field($input['claude_api_key']);
5566 - }
1402 + }
5567 1403
5568 - if (isset($input['deepseek_api_key'])) {
5569 - $new_input['deepseek_api_key'] = sanitize_text_field($input['deepseek_api_key']);
5570 - }
1404 + if (isset($input['system_prompt_instructions'])) {
1405 + $new_input['system_prompt_instructions'] = sanitize_textarea_field($input['system_prompt_instructions']);
1406 + }
5571 1407
5572 - if (isset($input['enable_woocommerce_integration'])) {
5573 - $new_input['enable_woocommerce_integration'] = $input['enable_woocommerce_integration'] === 'on' ? 'on' : 'off';
5574 - }
1408 + if (isset($input['mxchat_pro_email'])) {
1409 + $new_input['mxchat_pro_email'] = sanitize_email($input['mxchat_pro_email']);
1410 + }
5575 1411
5576 - if (isset($input['privacy_toggle'])) {
5577 - $new_input['privacy_toggle'] = $input['privacy_toggle'];
5578 - }
1412 + if (isset($input['mxchat_activation_key'])) {
1413 + $new_input['mxchat_activation_key'] = sanitize_text_field($input['mxchat_activation_key']);
1414 + }
5579 1415
5580 - if (isset($input['complianz_toggle'])) {
5581 - $new_input['complianz_toggle'] = $input['complianz_toggle'];
5582 - }
1416 + if (isset($input['append_to_body'])) {
1417 + $new_input['append_to_body'] = $input['append_to_body'] === 'on' ? 'on' : 'off';
1418 + }
5583 1419
5584 - // Handle custom privacy text input
5585 - if (isset($input['privacy_text'])) {
5586 - // Allow basic HTML for links
5587 - $new_input['privacy_text'] = wp_kses_post($input['privacy_text']);
5588 - }
1420 + if (isset($input['top_bar_title'])) {
1421 + $new_input['top_bar_title'] = sanitize_text_field($input['top_bar_title']);
1422 + }
5589 1423
5590 - if (isset($input['system_prompt_instructions'])) {
5591 - $new_input['system_prompt_instructions'] = sanitize_textarea_field($input['system_prompt_instructions']);
5592 - }
1424 + if (isset($input['intro_message'])) {
1425 + $new_input['intro_message'] = sanitize_text_field($input['intro_message']);
1426 + }
5593 1427
5594 - if (isset($input['mxchat_pro_email'])) {
5595 - $new_input['mxchat_pro_email'] = sanitize_email($input['mxchat_pro_email']);
5596 - }
5597 -
5598 - if (isset($input['mxchat_activation_key'])) {
5599 - $new_input['mxchat_activation_key'] = sanitize_text_field($input['mxchat_activation_key']);
5600 - }
5601 -
5602 - if (isset($input['append_to_body'])) {
5603 - $new_input['append_to_body'] = $input['append_to_body'] === 'on' ? 'on' : 'off';
5604 - }
5605 -
5606 - if (isset($input['top_bar_title'])) {
5607 - $new_input['top_bar_title'] = sanitize_text_field($input['top_bar_title']);
5608 - }
5609 -
5610 - if (isset($input['enable_email_block'])) {
5611 - $new_input['enable_email_block'] = sanitize_text_field($input['enable_email_block']);
5612 - }
5613 -
5614 - if (isset($input['email_blocker_header_content'])) {
5615 - // wp_kses_post() allows standard HTML tags permitted by WordPress
5616 - $new_input['email_blocker_header_content'] = wp_kses_post($input['email_blocker_header_content']);
5617 - }
5618 - if (isset($input['email_blocker_button_text'])) {
5619 - $new_input['email_blocker_button_text'] = sanitize_text_field($input['email_blocker_button_text']);
5620 - }
5621 -
5622 - if (isset($input['intro_message'])) {
5623 - $new_input['intro_message'] = sanitize_textarea_field($input['intro_message']); // Changed from sanitize_text_field
5624 - }
5625 -
5626 - if (isset($input['input_copy'])) {
5627 - $new_input['input_copy'] = sanitize_text_field($input['input_copy']);
5628 - }
5629 -
5630 - if (isset($input['rate_limit_message'])) {
5631 - $new_input['rate_limit_message'] = sanitize_text_field($input['rate_limit_message']);
5632 - }
5633 -
5634 - if (isset($input['rate_limit_logged_out'])) {
5635 - $allowed_limits = array('1', '3', '5', '10', '15', '20', '100', 'unlimited'); // Add 'unlimited' to allowed values
5636 - $rate_limit = sanitize_text_field($input['rate_limit_logged_out']);
5637 -
5638 - if (in_array($rate_limit, $allowed_limits, true)) {
5639 - $new_input['rate_limit_logged_out'] = $rate_limit;
5640 - } else {
5641 - $new_input['rate_limit_logged_out'] = '10'; // Default for logged-out users
1428 + if (isset($input['rate_limit_message'])) {
1429 + $new_input['rate_limit_message'] = sanitize_text_field($input['rate_limit_message']);
5642 1430 }
5643 - }
1431 +
1432 +
1433 + if (isset($input['pre_chat_message'])) {
1434 + $new_input['pre_chat_message'] = sanitize_textarea_field($input['pre_chat_message']);
1435 + }
5644 1436
5645 - // Handle role rate limits
5646 - if (isset($input['role_rate_limits']) && is_array($input['role_rate_limits'])) {
5647 - $allowed_limits = array('1', '3', '5', '10', '15', '20', '100', 'unlimited');
5648 - $new_input['role_rate_limits'] = array();
5649 -
5650 - foreach ($input['role_rate_limits'] as $role_id => $rate_limit) {
5651 - $rate_limit = sanitize_text_field($rate_limit);
5652 - if (in_array($rate_limit, $allowed_limits, true)) {
5653 - $new_input['role_rate_limits'][$role_id] = $rate_limit;
5654 - } else {
5655 - $new_input['role_rate_limits'][$role_id] = '100'; // Default
1437 + if (isset($input['model'])) {
1438 + $allowed_models = array(
1439 + 'gpt-4o',
1440 + 'gpt-4o-mini',
1441 + 'gpt-4-turbo',
1442 + 'gpt-4',
1443 + 'gpt-3.5-turbo',
1444 + );
1445 + if (in_array($input['model'], $allowed_models)) {
1446 + $new_input['model'] = sanitize_text_field($input['model']);
5656 1447 }
5657 1448 }
5658 - }
5659 1449
5660 - if (isset($input['pre_chat_message'])) {
5661 - $new_input['pre_chat_message'] = sanitize_textarea_field($input['pre_chat_message']);
5662 - }
1450 + // Sanitize new pro features
1451 + if (isset($input['close_button_color'])) {
1452 + $new_input['close_button_color'] = sanitize_hex_color($input['close_button_color']);
1453 + }
5663 1454
5664 - if (isset($input['model'])) {
5665 - $allowed_models = array(
5666 - 'grok-beta',
5667 - 'grok-2',
5668 - 'deepseek-chat',
5669 - 'claude-3-5-sonnet-20241022',
5670 - 'claude-3-opus-20240229',
5671 - 'claude-3-sonnet-20240229',
5672 - 'claude-3-haiku-20240307',
5673 - 'gpt-4o',
5674 - 'gpt-4o-mini',
5675 - 'gpt-4-turbo',
5676 - 'gpt-4',
5677 - 'gpt-3.5-turbo',
5678 - );
5679 - if (in_array($input['model'], $allowed_models)) {
5680 - $new_input['model'] = sanitize_text_field($input['model']);
1455 + if (isset($input['chatbot_bg_color'])) {
1456 + $new_input['chatbot_bg_color'] = sanitize_hex_color($input['chatbot_bg_color']);
5681 1457 }
5682 - }
1458 +
1459 + if (isset($input['woocommerce_consumer_key'])) {
1460 + $new_input['woocommerce_consumer_key'] = sanitize_text_field($input['woocommerce_consumer_key']);
1461 + }
1462 +
1463 + if (isset($input['woocommerce_consumer_secret'])) {
1464 + $new_input['woocommerce_consumer_secret'] = sanitize_text_field($input['woocommerce_consumer_secret']);
1465 + }
5683 1466
5684 - if (isset($input['close_button_color'])) {
5685 - $new_input['close_button_color'] = sanitize_hex_color($input['close_button_color']);
5686 - }
1467 + if (isset($input['user_message_bg_color'])) {
1468 + $new_input['user_message_bg_color'] = sanitize_hex_color($input['user_message_bg_color']);
1469 + }
5687 1470
5688 - if (isset($input['chatbot_bg_color'])) {
5689 - $new_input['chatbot_bg_color'] = sanitize_hex_color($input['chatbot_bg_color']);
5690 - }
1471 + if (isset($input['user_message_font_color'])) {
1472 + $new_input['user_message_font_color'] = sanitize_hex_color($input['user_message_font_color']);
1473 + }
5691 1474
5692 - if (isset($input['woocommerce_consumer_key'])) {
5693 - $new_input['woocommerce_consumer_key'] = sanitize_text_field($input['woocommerce_consumer_key']);
5694 - }
1475 + if (isset($input['bot_message_bg_color'])) {
1476 + $new_input['bot_message_bg_color'] = sanitize_hex_color($input['bot_message_bg_color']);
1477 + }
5695 1478
5696 - if (isset($input['woocommerce_consumer_secret'])) {
5697 - $new_input['woocommerce_consumer_secret'] = sanitize_text_field($input['woocommerce_consumer_secret']);
5698 - }
1479 + if (isset($input['bot_message_font_color'])) {
1480 + $new_input['bot_message_font_color'] = sanitize_hex_color($input['bot_message_font_color']);
1481 + }
5699 1482
5700 - if (isset($input['user_message_bg_color'])) {
5701 - $new_input['user_message_bg_color'] = sanitize_hex_color($input['user_message_bg_color']);
5702 - }
1483 + if (isset($input['top_bar_bg_color'])) {
1484 + $new_input['top_bar_bg_color'] = sanitize_hex_color($input['top_bar_bg_color']);
1485 + }
5703 1486
5704 - if (isset($input['user_message_font_color'])) {
5705 - $new_input['user_message_font_color'] = sanitize_hex_color($input['user_message_font_color']);
5706 - }
1487 + if (isset($input['send_button_font_color'])) {
1488 + $new_input['send_button_font_color'] = sanitize_hex_color($input['send_button_font_color']);
1489 + }
5707 1490
5708 - if (isset($input['bot_message_bg_color'])) {
5709 - $new_input['bot_message_bg_color'] = sanitize_hex_color($input['bot_message_bg_color']);
5710 - }
1491 + if (isset($input['chatbot_background_color'])) {
1492 + $new_input['chatbot_background_color'] = sanitize_hex_color($input['chatbot_background_color']);
1493 + }
5711 1494
5712 - if (isset($input['bot_message_font_color'])) {
5713 - $new_input['bot_message_font_color'] = sanitize_hex_color($input['bot_message_font_color']);
5714 - }
1495 + if (isset($input['icon_color'])) {
1496 + $new_input['icon_color'] = sanitize_hex_color($input['icon_color']);
1497 + }
5715 1498
5716 - if (isset($input['live_agent_message_bg_color'])) {
5717 - $new_input['live_agent_message_bg_color'] = sanitize_hex_color($input['live_agent_message_bg_color']);
5718 - }
1499 + if (isset($input['chat_input_font_color'])) {
1500 + $new_input['chat_input_font_color'] = sanitize_hex_color($input['chat_input_font_color']);
1501 + }
5719 1502
5720 - if (isset($input['live_agent_message_font_color'])) {
5721 - $new_input['live_agent_message_font_color'] = sanitize_hex_color($input['live_agent_message_font_color']);
1503 + return $new_input;
5722 1504 }
5723 1505
5724 - if (isset($input['mode_indicator_bg_color'])) {
5725 - $new_input['mode_indicator_bg_color'] = sanitize_hex_color($input['mode_indicator_bg_color']);
5726 - }
5727 1506
5728 - if (isset($input['mode_indicator_font_color'])) {
5729 - $new_input['mode_indicator_font_color'] = sanitize_hex_color($input['mode_indicator_font_color']);
1507 + // Method to append the chatbot to the body
1508 + public function mxchat_append_chatbot_to_body() {
1509 + $options = get_option('mxchat_options');
1510 + if (isset($options['append_to_body']) && $options['append_to_body'] === 'on') {
1511 + echo do_shortcode('[mxchat_chatbot floating="yes"]');
1512 + }
5730 1513 }
5731 1514
5732 - if (isset($input['toolbar_icon_color'])) {
5733 - $new_input['toolbar_icon_color'] = sanitize_hex_color($input['toolbar_icon_color']);
5734 - }
5735 1515
5736 - if (isset($input['top_bar_bg_color'])) {
5737 - $new_input['top_bar_bg_color'] = sanitize_hex_color($input['top_bar_bg_color']);
5738 - }
5739 1516
5740 - if (isset($input['send_button_font_color'])) {
5741 - $new_input['send_button_font_color'] = sanitize_hex_color($input['send_button_font_color']);
5742 - }
1517 +private function mxchat_extract_main_content($html) {
1518 + $dom = new DOMDocument;
1519 + libxml_use_internal_errors(true); // Suppress HTML parsing errors
1520 + @$dom->loadHTML($html);
1521 + libxml_clear_errors();
5743 1522
5744 - if (isset($input['chatbot_background_color'])) {
5745 - $new_input['chatbot_background_color'] = sanitize_hex_color($input['chatbot_background_color']);
5746 - }
1523 + $xpath = new DOMXPath($dom);
5747 1524
5748 - if (isset($input['icon_color'])) {
5749 - $new_input['icon_color'] = sanitize_hex_color($input['icon_color']);
5750 - }
1525 + // Simplified selectors focusing on common content areas
1526 + $selectors = [
1527 + '//article',
1528 + '//*[@id="content"]',
1529 + '//*[@class="entry-content"]',
1530 + '//main',
1531 + ];
5751 1532
5752 - if (isset($input['custom_icon'])) {
5753 - $new_input['custom_icon'] = esc_url_raw($input['custom_icon']);
1533 + foreach ($selectors as $selector) {
1534 + $nodes = $xpath->query($selector);
1535 + if ($nodes->length > 0) {
1536 + $content = '';
1537 + foreach ($nodes as $node) {
1538 + $content .= $dom->saveHTML($node);
1539 + }
1540 + return $content;
1541 + }
5754 1542 }
5755 1543
5756 - if (isset($input['title_icon'])) {
5757 - $new_input['title_icon'] = esc_url_raw($input['title_icon']);
5758 - }
1544 + // Fallback: Return the entire body content if no specific selector matches
1545 + $body = $dom->getElementsByTagName('body');
1546 + return $body->length > 0 ? $dom->saveHTML($body->item(0)) : $html;
1547 +}
5759 1548
5760 - if (isset($input['chat_input_font_color'])) {
5761 - $new_input['chat_input_font_color'] = sanitize_hex_color($input['chat_input_font_color']);
1549 +public function mxchat_handle_sitemap_submission() {
1550 + if (!isset($_POST['submit_sitemap']) || !current_user_can('manage_options')) {
1551 + return;
5762 1552 }
5763 1553
5764 - // Sanitize link_target_toggle
5765 - if (isset($input['link_target_toggle'])) {
5766 - $new_input['link_target_toggle'] = $input['link_target_toggle'] === 'on' ? 'on' : 'off';
5767 - }
1554 + check_admin_referer('mxchat_submit_sitemap_action', 'mxchat_submit_sitemap_nonce');
5768 1555
5769 - // Sanitize Loops API Key
5770 - if (isset($input['loops_api_key'])) {
5771 - $new_input['loops_api_key'] = sanitize_text_field($input['loops_api_key']);
5772 - }
1556 + $sitemap_url = esc_url_raw($_POST['sitemap_url']);
5773 1557
5774 - if (isset($input['chat_persistence_toggle'])) {
5775 - $new_input['chat_persistence_toggle'] = $input['chat_persistence_toggle'] === 'on' ? 'on' : 'off';
1558 + $response = wp_remote_get($sitemap_url);
1559 + if (is_wp_error($response) || wp_remote_retrieve_response_code($response) !== 200) {
1560 + set_transient('mxchat_admin_notice', 'Failed to fetch the sitemap. Please check the URL and try again.', 30);
1561 + wp_safe_redirect(esc_url(admin_url('admin.php?page=mxchat-prompts')));
1562 + exit;
5776 1563 }
5777 1564
5778 - if (isset($input['popular_question_1'])) {
5779 - $new_input['popular_question_1'] = sanitize_text_field($input['popular_question_1']);
5780 - }
1565 + $sitemap_content = wp_remote_retrieve_body($response);
5781 1566
5782 - if (isset($input['popular_question_2'])) {
5783 - $new_input['popular_question_2'] = sanitize_text_field($input['popular_question_2']);
1567 + $xml = simplexml_load_string($sitemap_content);
1568 + if ($xml === false) {
1569 + set_transient('mxchat_admin_notice', 'Invalid sitemap XML. Please provide a valid sitemap.', 30);
1570 + wp_safe_redirect(esc_url(admin_url('admin.php?page=mxchat-prompts')));
1571 + exit;
5784 1572 }
5785 1573
5786 - if (isset($input['popular_question_3'])) {
5787 - $new_input['popular_question_3'] = sanitize_text_field($input['popular_question_3']);
5788 - }
1574 + $embedding_success = true; // Flag to track if all embeddings are successful
5789 1575
5790 - if (isset($input['additional_popular_questions']) && is_array($input['additional_popular_questions'])) {
5791 - $new_input['additional_popular_questions'] = array_map('sanitize_text_field', $input['additional_popular_questions']);
5792 - }
5793 -
5794 - // Sanitize Loops Mailing List
5795 - if (isset($input['loops_mailing_list'])) {
5796 - $new_input['loops_mailing_list'] = sanitize_text_field($input['loops_mailing_list']);
5797 - }
5798 -
5799 - // Sanitize Triggered Phrase Response
5800 - if (isset($input['triggered_phrase_response'])) {
5801 - $new_input['triggered_phrase_response'] = wp_kses_post($input['triggered_phrase_response']);
5802 - }
5803 -
5804 - if (isset($input['email_capture_response'])) {
5805 - $new_input['email_capture_response'] = sanitize_textarea_field($input['email_capture_response']);
5806 - }
5807 -
5808 - // Sanitize Brave Search Settings
5809 - if (isset($input['brave_api_key'])) {
5810 - $new_input['brave_api_key'] = sanitize_text_field($input['brave_api_key']);
5811 - }
5812 -
5813 - if (isset($input['brave_image_count'])) {
5814 - $image_count = intval($input['brave_image_count']);
5815 - $new_input['brave_image_count'] = ($image_count >=1 && $image_count <=6) ? $image_count : 4;
5816 - }
5817 -
5818 - if (isset($input['brave_safe_search'])) {
5819 - $allowed = array('strict', 'off');
5820 - $new_input['brave_safe_search'] = in_array($input['brave_safe_search'], $allowed, true) ? $input['brave_safe_search'] : 'strict';
5821 - }
5822 -
5823 - if (isset($input['brave_news_count'])) {
5824 - $news_count = intval($input['brave_news_count']);
5825 - $new_input['brave_news_count'] = ($news_count >=1 && $news_count <=10) ? $news_count : 3;
5826 - }
5827 -
5828 - if (isset($input['brave_country'])) {
5829 - $new_input['brave_country'] = sanitize_text_field($input['brave_country']);
5830 - }
5831 -
5832 - if (isset($input['brave_language'])) {
5833 - $new_input['brave_language'] = sanitize_text_field($input['brave_language']);
5834 - }
5835 -
5836 - if (isset($input['chat_toolbar_toggle'])) {
5837 - $new_input['chat_toolbar_toggle'] = $input['chat_toolbar_toggle'] === 'on' ? 'on' : 'off';
5838 - }
5839 -
5840 - if (isset($input['pdf_intent_trigger_text'])) {
5841 - $new_input['pdf_intent_trigger_text'] = sanitize_text_field($input['pdf_intent_trigger_text']);
5842 - }
5843 -
5844 - if (isset($input['pdf_intent_success_text'])) {
5845 - $new_input['pdf_intent_success_text'] = sanitize_text_field($input['pdf_intent_success_text']);
5846 - }
5847 -
5848 - if (isset($input['pdf_intent_error_text'])) {
5849 - $new_input['pdf_intent_error_text'] = sanitize_text_field($input['pdf_intent_error_text']);
5850 - }
5851 -
5852 - if (isset($input['pdf_max_pages'])) {
5853 - $new_input['pdf_max_pages'] = intval($input['pdf_max_pages']);
5854 - if ($new_input['pdf_max_pages'] < 1 || $new_input['pdf_max_pages'] > 69) {
5855 - $new_input['pdf_max_pages'] = 69; // Default to 69 if out of range
1576 + foreach ($xml->url as $url_element) {
1577 + $page_url = (string)$url_element->loc;
1578 +
1579 + $page_response = wp_remote_get($page_url);
1580 + if (is_wp_error($page_response) || wp_remote_retrieve_response_code($page_response) !== 200) {
1581 + continue;
5856 1582 }
5857 - }
5858 -
5859 - if (isset($input['live_agent_webhook_url'])) {
5860 - $new_input['live_agent_webhook_url'] = esc_url_raw($input['live_agent_webhook_url']);
5861 - }
5862 - if (isset($input['live_agent_secret_key'])) {
5863 - $new_input['live_agent_secret_key'] = sanitize_text_field($input['live_agent_secret_key']);
5864 - }
5865 -
5866 - // Live Agent Integration
5867 - if (isset($input['live_agent_bot_token'])) {
5868 - $new_input['live_agent_bot_token'] = sanitize_text_field($input['live_agent_bot_token']);
5869 - }
5870 -
5871 - if (isset($input['live_agent_status'])) {
5872 - $new_input['live_agent_status'] = ($input['live_agent_status'] === 'on') ? 'on' : 'off';
5873 - }
5874 - if (isset($input['live_agent_away_message'])) {
5875 - $new_input['live_agent_away_message'] = sanitize_textarea_field($input['live_agent_away_message']);
5876 - }
5877 - if (isset($input['live_agent_notification_message'])) {
5878 - $new_input['live_agent_notification_message'] = sanitize_textarea_field($input['live_agent_notification_message']);
5879 - }
5880 -
5881 - return $new_input;
5882 -}
5883 -
5884 -
5885 - // Method to append the chatbot to the body
5886 - public function mxchat_append_chatbot_to_body() {
5887 - $options = get_option('mxchat_options');
5888 - if (isset($options['append_to_body']) && $options['append_to_body'] === 'on') {
5889 - echo do_shortcode('[mxchat_chatbot floating="yes"]');
5890 - }
5891 - }
5892 -
5893 -
5894 -
5895 -private static function mxchat_extract_main_content($html) {
5896 - if (empty($html)) {
5897 - //error_log('mxchat_extract_main_content: Empty HTML content received');
5898 - return '';
5899 - }
5900 -
5901 - try {
5902 - $dom = new DOMDocument;
5903 - libxml_use_internal_errors(true); // Suppress HTML parsing errors
5904 -
5905 - // Simple load of HTML, with @ to suppress warnings
5906 - @$dom->loadHTML($html, LIBXML_HTML_NOIMPLIED | LIBXML_HTML_NODEFDTD);
5907 -
5908 - $xpath = new DOMXPath($dom);
5909 -
5910 - // Simplified selectors focusing on common content areas
5911 - $selectors = [
5912 - '//article',
5913 - '//*[@id="content"]',
5914 - '//*[@class="entry-content"]',
5915 - '//main'
5916 - ];
5917 -
5918 - foreach ($selectors as $selector) {
5919 - $nodes = $xpath->query($selector);
5920 - if ($nodes && $nodes->length > 0) {
5921 - $content = '';
5922 - foreach ($nodes as $node) {
5923 - $content .= $dom->saveHTML($node);
5924 - }
5925 - if (!empty($content)) {
5926 - return $content;
5927 - }
1583 +
1584 + $page_html = wp_remote_retrieve_body($page_response);
1585 + $page_content = $this->mxchat_extract_main_content($page_html);
1586 + $sanitized_content = $this->mxchat_sanitize_content_for_api($page_content);
1587 +
1588 + if (!empty($sanitized_content)) {
1589 + $embedding_vector = $this->mxchat_generate_embedding($sanitized_content);
1590 + if (is_array($embedding_vector)) {
1591 + MxChat_Utils::submit_content_to_db($sanitized_content, $page_url, $this->options['api_key']);
1592 + } else {
1593 + $embedding_success = false; // Set flag to false if any embedding fails
5928 1594 }
5929 1595 }
5930 -
5931 - // Fallback: Return the entire body content if no specific selector matches
5932 - $body = $dom->getElementsByTagName('body');
5933 - if ($body->length > 0) {
5934 - return $dom->saveHTML($body->item(0));
5935 - }
5936 -
5937 - // Last resort: return the original HTML
5938 - return $html;
5939 -
5940 - } catch (Exception $e) {
5941 - //error_log('mxchat_extract_main_content error: ' . $e->getMessage());
5942 - return $html; // Return original HTML if parsing fails
5943 - } finally {
5944 - libxml_clear_errors();
5945 1596 }
5946 -}
5947 1597
5948 -
5949 -private function mxchat_fetch_loops_mailing_lists($api_key) {
5950 - $url = 'https://app.loops.so/api/v1/lists';
5951 - $response = wp_remote_get($url, array(
5952 - 'headers' => array(
5953 - 'Authorization' => 'Bearer ' . $api_key,
5954 - 'Content-Type' => 'application/json'
5955 - )
5956 - ));
5957 -
5958 - if (is_wp_error($response)) {
5959 - return array();
1598 + if ($embedding_success) {
1599 + set_transient('mxchat_admin_notice', 'Sitemap content successfully submitted!', 30);
1600 + } else {
1601 + set_transient('mxchat_admin_notice', 'Some content failed to embed. Please check your API key and try again.', 30);
5960 1602 }
5961 1603
5962 - $body = wp_remote_retrieve_body($response);
5963 - $lists = json_decode($body, true);
5964 -
5965 - return isset($lists) && is_array($lists) ? $lists : array();
1604 + wp_safe_redirect(esc_url(admin_url('admin.php?page=mxchat-prompts')));
1605 + exit;
5966 1606 }
5967 1607
5968 1608
5969 1609
1610 +private function mxchat_sanitize_content_for_api($content) {
1611 + // Remove script, style tags, and HTML comments
1612 + $content = preg_replace('/<script\b[^>]*>(.*?)<\/script>/is', '', $content);
1613 + $content = preg_replace('/<style\b[^>]*>(.*?)<\/style>/is', '', $content);
1614 + $content = preg_replace('/<!--(.|\s)*?-->/', '', $content);
5970 1615
1616 + // Remove all HTML tags and decode HTML entities
1617 + $content = wp_strip_all_tags($content);
1618 + $content = html_entity_decode($content, ENT_QUOTES | ENT_HTML5);
5971 1619
5972 -function mxchat_calculate_cosine_similarity($vec1, $vec2) {
5973 - if (empty($vec1) || empty($vec2)) {
5974 - return 0.0;
5975 - }
1620 + // Trim and normalize whitespace
1621 + $content = trim(preg_replace('/\s+/', ' ', $content));
5976 1622
5977 - $dot_product = 0.0;
5978 - $norm_a = 0.0;
5979 - $norm_b = 0.0;
5980 -
5981 - for ($i = 0; $i < count($vec1); $i++) {
5982 - $dot_product += $vec1[$i] * $vec2[$i];
5983 - $norm_a += pow($vec1[$i], 2);
5984 - $norm_b += pow($vec2[$i], 2);
5985 - }
5986 -
5987 - if ($norm_a == 0.0 || $norm_b == 0.0) {
5988 - return 0.0;
5989 - } else {
5990 - return $dot_product / (sqrt($norm_a) * sqrt($norm_b));
5991 - }
1623 + return $content;
5992 1624 }
5993 -
5994 -
5995 1625
5996 1626
5997 1627 }
5998 1628 ?>