PluginProbe
MxChat – AI Chatbot & Content Generation for WordPress / 1.1.0
MxChat – AI Chatbot & Content Generation for WordPress v1.1.0
3.2.21 3.2.20 3.2.19 3.2.18 3.2.17 3.2.16 3.2.15 3.2.14 3.2.12 3.2.13 3.2.11 3.2.10 3.2.9 3.2.8 3.2.7 3.2.6 3.2.5 3.2.4 3.2.3 3.2.2 3.2.1 2.0.3 2.0.4 2.0.5 2.0.6 All 152 releases
mxchat-basic / includes / class-mxchat-admin.php

class-mxchat-admin.php in MxChat – AI Chatbot & Content Generation for WordPress 1.1.0, at includes/class-mxchat-admin.php

1,840 lines 72.1 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 if (!defined('ABSPATH')) {
3 exit; // Exit if accessed directly
4 }
5
6 class MxChat_Admin {
7 private $options;
8 private $chat_count;
9 private $is_activated;
10
11 public function __construct() {
12 $this->options = get_option('mxchat_options');
13 $this->chat_count = get_option('mxchat_chat_count', 0);
14 $this->is_activated = $this->is_license_active();
15
16 // Initialize default options if they are not set
17 if (!$this->options) {
18 $this->initialize_default_options();
19 }
20
21 // Add admin menu and initialize settings
22 add_action('admin_menu', array($this, 'mxchat_add_plugin_page'));
23 add_action('admin_init', array($this, 'mxchat_page_init'));
24 add_action('admin_enqueue_scripts', array($this, 'mxchat_enqueue_admin_assets'));
25 add_action('wp_ajax_mxchat_delete_chat_history', array($this, 'mxchat_delete_chat_history'));
26 add_action('admin_post_mxchat_submit_content', array($this, 'mxchat_handle_content_submission'));
27 add_action('admin_post_mxchat_delete_prompt', array($this, 'mxchat_handle_delete_prompt'));
28 add_action('wp_ajax_mxchat_fetch_chat_history', array($this, 'mxchat_fetch_chat_history'));
29 add_action('wp_ajax_nopriv_mxchat_fetch_chat_history', array($this, 'mxchat_fetch_chat_history'));
30 add_action('admin_post_mxchat_submit_sitemap', array($this, 'mxchat_handle_sitemap_submission'));
31 add_action('wp_footer', array($this, 'mxchat_append_chatbot_to_body'));
32 add_action('admin_head-mxchat-prompts', array($this, 'mxchat_enqueue_admin_assets'));
33 add_action('admin_head-toplevel_page_mxchat-max', array($this, 'mxchat_enqueue_admin_assets'));
34 add_action('wp_ajax_mxchat_activate_license', array($this, 'mxchat_handle_activate_license'));
35 add_action('admin_notices', array($this, 'mxchat_display_admin_notice'));
36
37 }
38
39 // Method to check if the license is active
40 private function is_license_active() {
41 $license_status = get_option('mxchat_license_status', 'inactive');
42 return $license_status === 'active';
43 }
44
45 // Initialize default options
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 'input_copy' => 'How can I assist?',
63 'append_to_body' => 'on',
64 'close_button_color' => '#fff',
65 'chatbot_bg_color' => '#fff',
66 'user_message_bg_color' => '#fff',
67 'user_message_font_color' => '#212121',
68 'bot_message_bg_color' => '#212121',
69 'bot_message_font_color' => '#fff',
70 'top_bar_bg_color' => '#212121',
71 'send_button_font_color' => '#212121',
72 'chat_input_font_color' => '#212121',
73 'chatbot_background_color' => '#212121',
74 'icon_color' => '#fff',
75 'enable_woocommerce_integration' => '0',
76 'enable_woocommerce_order_access' => '0',
77 'link_target_toggle' => 'on',
78 );
79
80
81 // Merge existing options with defaults
82 $existing_options = get_option('mxchat_options', array());
83 $merged_options = wp_parse_args($existing_options, $default_options);
84
85 // Update the options if they have changed
86 if ($existing_options !== $merged_options) {
87 update_option('mxchat_options', $merged_options);
88 }
89
90 // Update the $this->options property
91 $this->options = $merged_options;
92 }
93
94 public function mxchat_add_plugin_page() {
95 // Main menu page
96 add_menu_page(
97 'MxChat Settings',
98 'MxChat',
99 'manage_options',
100 'mxchat-max',
101 array($this, 'mxchat_create_admin_page'),
102 'dashicons-testimonial',
103 6
104 );
105
106 // Submenu page for Knowledge
107 add_submenu_page(
108 'mxchat-max',
109 'Prompts',
110 'Knowledge',
111 'manage_options',
112 'mxchat-prompts',
113 array($this, 'mxchat_create_prompts_page')
114 );
115
116 // Submenu page for Chat Transcripts
117 add_submenu_page(
118 'mxchat-max', // Corrected parent slug to match the main menu
119 'Chat Transcripts',
120 'Transcripts',
121 'manage_options',
122 'mxchat-transcripts',
123 array($this, 'mxchat_create_transcripts_page') // Prefixed function name with mxchat_
124 );
125
126 // Submenu page for Activation Key
127 add_submenu_page(
128 'mxchat-max',
129 'Pro Upgrade',
130 'Pro Upgrade',
131 'manage_options',
132 'mxchat-activation',
133 array($this, 'mxchat_create_activation_page')
134 );
135 }
136
137
138 public function mxchat_handle_content_submission() {
139 // Check if the form was submitted and the user has sufficient permissions
140 if (!isset($_POST['submit_content']) || !current_user_can('manage_options')) {
141 return;
142 }
143
144 // Verify the nonce field for security
145 $nonce = isset($_POST['mxchat_submit_content_nonce']) ? sanitize_text_field(wp_unslash($_POST['mxchat_submit_content_nonce'])) : '';
146 if (!wp_verify_nonce($nonce, 'mxchat_submit_content_action')) {
147 wp_die('Nonce verification failed.');
148 }
149
150 // Sanitize the content input
151 $article_content = sanitize_textarea_field($_POST['article_content']);
152
153 // Generate the embedding vector for the content
154 $embedding_vector = $this->mxchat_generate_embedding($article_content);
155
156 global $wpdb;
157 $table_name = $wpdb->prefix . 'mxchat_system_prompt_content';
158
159 // Check if the 'source_url' column exists in the table and add it if it doesn't
160 if ($wpdb->get_var($wpdb->prepare("SHOW COLUMNS FROM {$table_name} LIKE %s", 'source_url')) != 'source_url') {
161 // Use wpdb::query and a prepared statement to avoid SQL injection
162 $wpdb->query($wpdb->prepare("ALTER TABLE {$table_name} ADD source_url VARCHAR(255) DEFAULT ''"));
163 }
164
165 if (is_array($embedding_vector)) {
166 // Serialize the embedding vector before storing it
167 $embedding_vector_serialized = serialize($embedding_vector);
168
169 // Insert the content and embedding vector into the database, using a prepared statement
170 $inserted = $wpdb->insert(
171 $table_name,
172 array(
173 'article_content' => $article_content,
174 'embedding_vector' => $embedding_vector_serialized,
175 'source_url' => '', // Empty string as a placeholder for now, or pass a valid URL if applicable
176 ),
177 array(
178 '%s', // Format for article_content (string)
179 '%s', // Format for embedding_vector (serialized string)
180 '%s', // Format for source_url (string)
181 )
182 );
183
184 if ($inserted === false) {
185 error_log('Error inserting content: ' . $wpdb->last_error);
186 set_transient('mxchat_admin_notice', 'Error inserting content into the database. Please try again.', 30);
187 } else {
188 set_transient('mxchat_admin_notice', 'Content successfully submitted!', 30);
189 }
190 } else {
191 error_log('Embedding generation failed for article content: ' . $article_content);
192 set_transient('mxchat_admin_notice', 'Embedding generation failed. Please ensure your API key is correct and try again.', 30);
193 }
194
195 // Redirect after setting the transient
196 wp_safe_redirect(esc_url(admin_url('admin.php?page=mxchat-prompts')));
197 exit;
198 }
199
200 public function mxchat_display_admin_notice() {
201 // Get the message from the transient
202 $message = get_transient('mxchat_admin_notice');
203
204 if ($message) {
205 echo '<div class="notice notice-error is-dismissible">';
206 echo '<p>' . esc_html($message) . '</p>';
207 echo '</div>';
208
209 // Delete the transient after displaying the message
210 delete_transient('mxchat_admin_notice');
211 }
212 }
213
214
215 public function mxchat_handle_delete_prompt() {
216 // Sanitize and validate nonce using wp_unslash and sanitize_text_field
217 $nonce = isset($_GET['_wpnonce']) ? sanitize_text_field(wp_unslash($_GET['_wpnonce'])) : '';
218 if (empty($nonce) || !wp_verify_nonce($nonce, 'mxchat_delete_prompt_nonce')) {
219 wp_die('Nonce verification failed.');
220 }
221
222 // Check user permissions
223 if (!current_user_can('manage_options')) {
224 wp_die('You do not have sufficient permissions to delete prompts.');
225 }
226
227 // Sanitize and validate the 'id' parameter
228 $id = isset($_GET['id']) ? intval($_GET['id']) : 0;
229 if ($id <= 0) {
230 wp_die('Invalid prompt ID.');
231 }
232
233 global $wpdb;
234 $table_name = $wpdb->prefix . 'mxchat_system_prompt_content';
235
236 // Clear relevant cache before deletion
237 $cache_key = 'prompt_' . $id;
238 wp_cache_delete($cache_key, 'mxchat_prompts');
239
240 // Delete the record using a prepared statement
241 $deleted = $wpdb->delete($table_name, array('id' => $id), array('%d'));
242
243 if ($deleted !== false) {
244 // Optionally, clear a general cache if you have one
245 wp_cache_delete('all_prompts', 'mxchat_prompts');
246 }
247
248 // Redirect to the prompts page with a success message
249 $redirect_url = add_query_arg(array(
250 'page' => 'mxchat-prompts',
251 'deleted' => 'true'
252 ), admin_url('admin.php'));
253
254 wp_safe_redirect($redirect_url);
255 exit;
256 }
257
258
259 public function mxchat_create_admin_page() {
260 ?>
261 <div class="wrap mxchat-admin">
262 <?php if (!$this->is_activated): ?>
263 <div class="mxchat-pro-banner">
264 <p>
265 Want even more features such as a fully customizable theme, WooCommerce integration, dedicated support, and much more?
266 <a href="https://mxchat.ai/" target="_blank">Upgrade to MxChat Pro today and get a special launch lifetime license for only $49.97!</a>
267 </p>
268 </div>
269 <?php endif; ?>
270 <h2 class="admin-title">Mx<span class="admin-emphasis">Chat</span></h2>
271 <h2 class="nav-tab-wrapper">
272 <a href="#chatbot" class="nav-tab nav-tab-active" data-tab="chatbot">Chatbot</a>
273 <a href="#embed" class="nav-tab" data-tab="embed">Embed</a>
274 <a href="#theme" class="nav-tab" data-tab="theme">Theme</a>
275 <a href="#general" class="nav-tab" data-tab="general">General</a>
276 </h2>
277 <form method="post" action="options.php">
278 <?php settings_fields('mxchat_option_group'); ?>
279 <div id="chatbot" class="tab-content active">
280 <?php do_settings_sections('mxchat-chatbot'); ?>
281 </div>
282 <div id="embed" class="tab-content">
283 <?php do_settings_sections('mxchat-embed'); ?>
284 </div>
285 <div id="theme" class="tab-content">
286 <?php do_settings_sections('mxchat-theme'); ?>
287 </div>
288 <div id="general" class="tab-content">
289 <?php do_settings_sections('mxchat-general'); ?>
290 <div class="mxchat-general-notes">
291 <h3>Important Notes</h3>
292 <p>
293 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.
294 </p>
295 <p>
296 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.
297 </p>
298 </div>
299 </div>
300 <?php submit_button(); ?>
301 </form>
302 </div>
303 <?php
304 }
305
306
307 public function mxchat_create_transcripts_page() {
308 ?>
309 <div class="wrap mxchat-admin">
310 <h2><?php esc_html_e('Chat Transcripts', 'mxchat'); ?></h2>
311 <form id="mxchat-delete-form" method="post">
312 <?php wp_nonce_field('mxchat_delete_chat_history', 'mxchat_delete_chat_nonce'); ?>
313 <div class="mxchat-controls">
314 <label for="mxchat-select-all-transcripts" class="mxchat-select-all-label">
315 <input type="checkbox" id="mxchat-select-all-transcripts" /> <?php esc_html_e('Select All', 'mxchat'); ?>
316 </label>
317 <input type="submit" value="<?php esc_attr_e('Delete Selected', 'mxchat'); ?>" class="button button-primary delete-chats-button" />
318 </div>
319 <div id="mxchat-transcripts">
320 <!-- Transcripts will be loaded here -->
321 </div>
322 </form>
323 </div>
324 <?php
325 }
326
327
328
329
330 public function mxchat_create_prompts_page() {
331 global $wpdb;
332 $table_name = $wpdb->prefix . 'mxchat_system_prompt_content';
333
334 // Verify the nonce before processing the request
335 $nonce = isset($_GET['_wpnonce']) ? sanitize_text_field($_GET['_wpnonce']) : '';
336
337 if (!empty($nonce) && wp_verify_nonce($nonce, 'mxchat_prompts_search_nonce')) {
338 // Sanitize input data
339 $search_query = isset($_GET['search']) ? sanitize_text_field($_GET['search']) : '';
340 $current_page = isset($_GET['paged']) ? absint($_GET['paged']) : 1;
341 } else {
342 $search_query = '';
343 $current_page = 1;
344 }
345
346 $per_page = 10;
347
348 // Create cache keys
349 $cache_key_total = 'total_prompts_' . md5($search_query);
350 $cache_key_prompts = 'prompts_' . md5($search_query . '_' . $current_page);
351
352 // Retrieve total number of prompts from cache or database
353 $total_prompts = wp_cache_get($cache_key_total, 'mxchat_prompts');
354 if ($total_prompts === false) {
355 if (!empty($search_query)) {
356 $total_prompts = $wpdb->get_var(
357 $wpdb->prepare(
358 "SELECT COUNT(*) FROM {$table_name} WHERE article_content LIKE %s",
359 '%' . $wpdb->esc_like($search_query) . '%'
360 )
361 );
362 } else {
363 $total_prompts = $wpdb->get_var("SELECT COUNT(*) FROM {$table_name}");
364 }
365 wp_cache_set($cache_key_total, $total_prompts, 'mxchat_prompts', 3600); // Cache for 1 hour
366 }
367
368 $total_pages = ceil($total_prompts / $per_page);
369 $offset = ($current_page - 1) * $per_page;
370
371 // Retrieve prompts from cache or database
372 $prompts = wp_cache_get($cache_key_prompts, 'mxchat_prompts');
373 if ($prompts === false) {
374 if (!empty($search_query)) {
375 $prompts = $wpdb->get_results(
376 $wpdb->prepare(
377 "SELECT * FROM {$table_name} WHERE article_content LIKE %s ORDER BY timestamp DESC LIMIT %d OFFSET %d",
378 '%' . $wpdb->esc_like($search_query) . '%',
379 $per_page,
380 $offset
381 )
382 );
383 } else {
384 $prompts = $wpdb->get_results(
385 $wpdb->prepare(
386 "SELECT * FROM {$table_name} ORDER BY timestamp DESC LIMIT %d OFFSET %d",
387 $per_page,
388 $offset
389 )
390 );
391 }
392 wp_cache_set($cache_key_prompts, $prompts, 'mxchat_prompts', 3600); // Cache for 1 hour
393 }
394
395 ?>
396
397 <div class="wrap mxchat-admin">
398 <div class="mxchat-grid-container">
399
400 <!-- Submit Content -->
401 <div class="mxchat-grid-item full-width">
402 <h2>Submit Content</h2>
403 <form method="post" action="<?php echo esc_url(admin_url('admin-post.php?action=mxchat_submit_content')); ?>">
404 <?php wp_nonce_field('mxchat_submit_content_action', 'mxchat_submit_content_nonce'); ?>
405 <div class="mxchat-form-group">
406 <label for="article_content">Article Content:</label>
407 <textarea name="article_content" id="article_content" required></textarea>
408 <input type="submit" name="submit_content" value="Submit Content" class="button button-primary submit-content-button" />
409 </div>
410 </form>
411 </div>
412
413 <!-- Submit Sitemap -->
414 <div class="mxchat-grid-item">
415 <h2>Submit Sitemap</h2>
416 <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')); ?>">
417 <?php wp_nonce_field('mxchat_submit_sitemap_action', 'mxchat_submit_sitemap_nonce'); ?>
418 <div class="mxchat-search-group">
419 <input type="url" name="sitemap_url" id="sitemap_url" placeholder="Sitemap URL" required />
420 <input type="submit" name="submit_sitemap" value="Submit Sitemap" class="button button-primary" />
421 </div>
422 </form>
423 <div id="mxchat-sitemap-loading" class="mxchat-spinner" style="display: none;"></div>
424 <div id="mxchat-loading-text" style="display: none; margin-top: 10px; color: #333;">Loading sitemap content into database, please wait...</div>
425 </div>
426
427 <!-- Search Knowledge -->
428 <div class="mxchat-grid-item">
429 <h2>Search Knowledge</h2>
430 <form method="get" id="knowledge-search">
431 <?php wp_nonce_field('mxchat_prompts_search_nonce'); ?>
432 <input type="hidden" name="page" value="mxchat-prompts" />
433 <div class="mxchat-search-group">
434 <input type="text" name="search" placeholder="Search Knowledge" value="<?php echo esc_attr($search_query); ?>" />
435 <input type="submit" value="Search" class="button button-primary" />
436 </div>
437 </form>
438 </div>
439 </div>
440
441 <!-- Table below the forms -->
442 <div class="tablenav">
443 <div class="tablenav-pages">
444 <span class="displaying-num"><?php echo esc_html($total_prompts); ?> items</span>
445 <?php
446 $page_links = paginate_links(array(
447 'base' => add_query_arg('paged', '%#%', admin_url('admin.php?page=mxchat-prompts')),
448 'format' => '',
449 'prev_text' => __('&laquo; Previous'),
450 'next_text' => __('Next &raquo;'),
451 'total' => $total_pages,
452 'current' => $current_page,
453 'add_args' => array(
454 'search' => $search_query,
455 '_wpnonce' => wp_create_nonce('mxchat_prompts_search_nonce')
456 ),
457 ));
458
459 if ($page_links) {
460 echo '<div class="tablenav-pages">' . wp_kses_post($page_links) . '</div>';
461 }
462 ?>
463 </div>
464 </div>
465 <table class="wp-list-table widefat fixed striped">
466 <thead>
467 <tr>
468 <th>ID</th>
469 <th>Article Content</th>
470 <th>URL</th>
471 <th>Actions</th>
472 </tr>
473 </thead>
474 <tbody>
475 <?php
476 if ($prompts) {
477 foreach ($prompts as $prompt) {
478 ?>
479 <tr>
480 <td><?php echo esc_html($prompt->id); ?></td>
481 <td class="mxchat_article_content_dashboard"><?php echo wp_kses_post(wpautop(esc_textarea($prompt->article_content))); ?></td>
482 <td class="mxchat_article_url_dashboard">
483 <?php if (!empty($prompt->source_url)): ?>
484 <a href="<?php echo esc_url($prompt->source_url); ?>" target="_blank"><?php echo esc_html($prompt->source_url); ?></a>
485 <?php else: ?>
486 N/A
487 <?php endif; ?>
488 </td>
489 <td>
490 <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>
491 </td>
492 </tr>
493 <?php
494 }
495 } else {
496 ?>
497 <tr>
498 <td colspan="4">No prompts found.</td>
499 </tr>
500 <?php
501 }
502 ?>
503 </tbody>
504 </table>
505 </div>
506
507 <?php
508 }
509
510 public function mxchat_generate_embedding($text) {
511 $options = get_option('mxchat_options');
512 $api_key = $options['api_key'] ?? 'default_api_key';
513
514 $response = wp_remote_post('https://api.openai.com/v1/embeddings', array(
515 'body' => wp_json_encode(array(
516 'model' => 'text-embedding-ada-002',
517 'input' => $text
518 )),
519 'headers' => array(
520 'Authorization' => 'Bearer ' . $api_key,
521 'Content-Type' => 'application/json'
522 ),
523 ));
524
525 if (is_wp_error($response)) {
526 return null;
527 }
528
529 $response_data = json_decode(wp_remote_retrieve_body($response), true);
530 return $response_data['data'][0]['embedding'] ?? null;
531 }
532
533 public function mxchat_delete_chat_history() {
534 if (!current_user_can('manage_options')) {
535 echo wp_json_encode(['error' => 'You do not have sufficient permissions.']);
536 wp_die();
537 }
538
539 check_ajax_referer('mxchat_delete_chat_history', 'security');
540
541 global $wpdb;
542 $table_name = $wpdb->prefix . 'mxchat_chat_transcripts';
543
544 if (isset($_POST['delete_session_ids']) && is_array($_POST['delete_session_ids'])) {
545 foreach ($_POST['delete_session_ids'] as $session_id) {
546 $session_id_sanitized = sanitize_text_field($session_id);
547
548 // Clear relevant cache before deletion
549 $cache_key = 'chat_session_' . $session_id_sanitized;
550 wp_cache_delete($cache_key, 'mxchat_chat_sessions');
551
552 // Perform the deletion
553 $wpdb->delete($table_name, ['session_id' => $session_id_sanitized]);
554 }
555
556 // Optionally, clear a general cache if you have one
557 wp_cache_delete('all_chat_sessions', 'mxchat_chat_sessions');
558
559 echo wp_json_encode(['success' => 'Selected chat sessions have been deleted.']);
560 } else {
561 echo wp_json_encode(['error' => 'No chat sessions selected for deletion.']);
562 }
563
564 wp_die();
565 }
566
567
568
569 public function mxchat_fetch_chat_history() {
570 global $wpdb;
571 $table_name = $wpdb->prefix . 'mxchat_chat_transcripts';
572
573 // Check if the current user has sufficient permissions
574 if (!current_user_can('manage_options')) {
575 echo esc_html__('You do not have sufficient permissions to view this page.', 'mxchat');
576 wp_die();
577 }
578
579 // Fetch chat transcripts from the database, ordered by timestamp
580 $chat_transcripts = $wpdb->get_results(
581 $wpdb->prepare("SELECT * FROM {$table_name} ORDER BY timestamp ASC")
582 );
583
584 // If no transcripts are available, display a message
585 if (empty($chat_transcripts)) {
586 echo esc_html__('No chat history available.', 'mxchat');
587 wp_die();
588 }
589
590 ob_start();
591 $current_session_id = '';
592
593 foreach ($chat_transcripts as $transcript) {
594 // Start a new session block if session ID changes
595 if ($current_session_id !== $transcript->session_id) {
596 if ($current_session_id !== '') {
597 echo '</div>'; // Close the previous session block
598 }
599 $current_session_id = sanitize_text_field($transcript->session_id);
600 echo '<div class="chat-session">';
601 echo '<h4><input type="checkbox" name="delete_session_ids[]" value="' . esc_attr($transcript->session_id) . '"> ' . esc_html__('Session ID:', 'mxchat') . ' ' . esc_html($current_session_id) . '</h4>';
602 }
603
604 // Format the timestamp for display
605 $formatted_timestamp = date_i18n('F j, Y g:i a', strtotime($transcript->timestamp));
606
607 // Determine the role to display (user identifier or email for users, bot for the AI)
608 $role = $transcript->role;
609 if ($role === 'user') {
610 // Sanitize email if available
611 if (!empty($transcript->user_email)) {
612 $role = sanitize_email($transcript->user_email);
613 } else {
614 // Sanitize user identifier, anonymize if it's an IP address
615 $user_identifier = sanitize_text_field($transcript->user_identifier);
616
617 // Check if the user identifier is an IP address and anonymize it
618 if (filter_var($user_identifier, FILTER_VALIDATE_IP)) {
619 $role = preg_replace('/\.\d+$/', '.xxx', $user_identifier); // Mask the last octet
620 } else {
621 $role = $user_identifier; // If it's not an IP, just display the identifier
622 }
623 }
624 }
625
626 // Output the chat message
627 echo '<div class="chat-message">';
628 echo '<strong>' . esc_html($role) . ' (' . esc_html($formatted_timestamp) . '):</strong> ';
629 echo wp_kses_post($transcript->message);
630 echo '</div>';
631 }
632
633 // Close the final session block
634 echo '</div>';
635
636 $output = ob_get_clean();
637
638 echo $output;
639 wp_die();
640 }
641
642
643 public function mxchat_create_activation_page() {
644 $license_status = get_option('mxchat_license_status', 'inactive');
645 $license_error = get_option('mxchat_license_error', '');
646
647 ?>
648 <div class="wrap mxchat-admin">
649 <h2>MxChat Pro: Activation</h2>
650 <?php if ($license_status === 'inactive' && !empty($license_error)): ?>
651 <div class="error notice">
652 <p><?php echo esc_html($license_error); ?></p>
653 </div>
654 <?php endif; ?>
655 <form id="mxchat-activation-form">
656 <table class="form-table">
657 <tr valign="top">
658 <th scope="row">Email Address</th>
659 <td>
660 <input type="email" id="mxchat_pro_email" name="mxchat_pro_email" value="<?php echo esc_attr(get_option('mxchat_pro_email')); ?>" class="regular-text" />
661 </td>
662 </tr>
663 <tr valign="top">
664 <th scope="row">Activation Key</th>
665 <td>
666 <input type="text" id="mxchat_activation_key" name="mxchat_activation_key" value="<?php echo esc_attr(get_option('mxchat_activation_key')); ?>" class="regular-text" />
667 </td>
668 </tr>
669 </table>
670 <?php if ($license_status !== 'active'): ?>
671 <?php submit_button('Activate License', 'primary', 'activate_license'); ?>
672 <?php else: ?>
673 <h3>MxChat Pro</h3>
674 <?php endif; ?>
675 </form>
676 <h3>License Status: <span id="mxchat-license-status"><?php echo $license_status === 'active' ? 'Active' : 'Inactive'; ?></span></h3>
677 </div>
678 <?php
679 }
680
681
682
683 public function mxchat_page_init() {
684 // Register settings
685 register_setting(
686 'mxchat_option_group',
687 'mxchat_options',
688 array($this, 'mxchat_sanitize')
689 );
690
691 // Chatbot Settings Section
692 add_settings_section(
693 'mxchat_chatbot_section',
694 'Chatbot Settings',
695 null,
696 'mxchat-chatbot'
697 );
698
699 // Registering fields for the Chatbot Settings section
700 add_settings_field(
701 'api_key',
702 'API Key',
703 array($this, 'api_key_callback'),
704 'mxchat-chatbot',
705 'mxchat_chatbot_section'
706 );
707
708 add_settings_field(
709 'system_prompt_instructions',
710 'AI Instructions',
711 array($this, 'system_prompt_instructions_callback'),
712 'mxchat-chatbot',
713 'mxchat_chatbot_section'
714 );
715
716 add_settings_field(
717 'model',
718 'Model',
719 array($this, 'mxchat_model_callback'),
720 'mxchat-chatbot',
721 'mxchat_chatbot_section'
722 );
723
724 add_settings_field(
725 'top_bar_title',
726 'Top Bar Title',
727 array($this, 'mxchat_top_bar_title_callback'),
728 'mxchat-chatbot',
729 'mxchat_chatbot_section'
730 );
731
732 add_settings_field(
733 'intro_message',
734 'Introductory Message',
735 array($this, 'mxchat_intro_message_callback'),
736 'mxchat-chatbot',
737 'mxchat_chatbot_section'
738 );
739
740 add_settings_field(
741 'input_copy',
742 'Input Copy',
743 array($this, 'mxchat_input_copy_callback'),
744 'mxchat-chatbot',
745 'mxchat_chatbot_section'
746 );
747
748 add_settings_field(
749 'rate_limit',
750 'Rate Limit',
751 array($this, 'mxchat_rate_limit_callback'),
752 'mxchat-chatbot',
753 'mxchat_chatbot_section'
754 );
755
756 add_settings_field(
757 'rate_limit_message',
758 'Rate Limit Message',
759 array($this, 'mxchat_rate_limit_message_callback'),
760 'mxchat-chatbot',
761 'mxchat_chatbot_section'
762 );
763
764 add_settings_field(
765 'pre_chat_message',
766 'Pre-Chat Message',
767 array($this, 'mxchat_pre_chat_message_callback'),
768 'mxchat-chatbot',
769 'mxchat_chatbot_section'
770 );
771
772 add_settings_field(
773 'append_to_body',
774 'Append Chat Widget to Body',
775 array($this, 'mxchat_append_to_body_callback'),
776 'mxchat-chatbot',
777 'mxchat_chatbot_section'
778 );
779
780 add_settings_field(
781 'privacy_toggle',
782 'Toggle Privacy Notice',
783 array($this, 'mxchat_privacy_toggle_callback'),
784 'mxchat-chatbot',
785 'mxchat_chatbot_section'
786 );
787
788 add_settings_field(
789 'complianz_toggle',
790 'Enable Complianz',
791 array($this, 'mxchat_complianz_toggle_callback'),
792 'mxchat-chatbot',
793 'mxchat_chatbot_section'
794 );
795
796 add_settings_field(
797 'link_target_toggle',
798 'Open Links in a New Tab',
799 array($this, 'mxchat_link_target_toggle_callback'),
800 'mxchat-chatbot',
801 'mxchat_chatbot_section'
802 );
803
804 // Embed Settings Section
805 add_settings_section(
806 'mxchat_embed_section',
807 'Embed Settings',
808 null,
809 'mxchat-embed'
810 );
811
812 add_settings_field(
813 'enable_woocommerce_integration',
814 'Automatically Embed Products',
815 array($this, 'mxchat_enable_woocommerce_integration_callback'),
816 'mxchat-embed',
817 'mxchat_embed_section'
818 );
819
820 add_settings_field(
821 'enable_woocommerce_order_access',
822 'Order History Access',
823 array($this, 'mxchat_enable_woocommerce_order_access_callback'),
824 'mxchat-embed',
825 'mxchat_embed_section'
826 );
827
828 add_settings_field(
829 'woocommerce_consumer_key',
830 'WooCommerce Consumer Key',
831 array($this, 'mxchat_woocommerce_consumer_key_callback'),
832 'mxchat-embed',
833 'mxchat_embed_section'
834 );
835
836 add_settings_field(
837 'woocommerce_consumer_secret',
838 'WooCommerce Consumer Secret',
839 array($this, 'mxchat_woocommerce_consumer_secret_callback'),
840 'mxchat-embed',
841 'mxchat_embed_section'
842 );
843
844 // Theme Settings Section
845 add_settings_section(
846 'mxchat_theme_section',
847 'Theme Settings',
848 null,
849 'mxchat-theme'
850 );
851
852 add_settings_field(
853 'close_button_color',
854 'Close Button & Title Color',
855 array($this, 'mxchat_close_button_color_callback'),
856 'mxchat-theme',
857 'mxchat_theme_section'
858 );
859
860 add_settings_field(
861 'chatbot_bg_color',
862 'Chatbot Background Color',
863 array($this, 'mxchat_chatbot_bg_color_callback'),
864 'mxchat-theme',
865 'mxchat_theme_section'
866 );
867
868 add_settings_field(
869 'user_message_bg_color',
870 'User Message Background Color',
871 array($this, 'mxchat_user_message_bg_color_callback'),
872 'mxchat-theme',
873 'mxchat_theme_section'
874 );
875
876 add_settings_field(
877 'user_message_font_color',
878 'User Message Font Color',
879 array($this, 'mxchat_user_message_font_color_callback'),
880 'mxchat-theme',
881 'mxchat_theme_section'
882 );
883
884 add_settings_field(
885 'bot_message_bg_color',
886 'Bot Message Background Color',
887 array($this, 'mxchat_bot_message_bg_color_callback'),
888 'mxchat-theme',
889 'mxchat_theme_section'
890 );
891
892 add_settings_field(
893 'bot_message_font_color',
894 'Bot Message Font Color',
895 array($this, 'mxchat_bot_message_font_color_callback'),
896 'mxchat-theme',
897 'mxchat_theme_section'
898 );
899
900 add_settings_field(
901 'top_bar_bg_color',
902 'Top Bar Background Color',
903 array($this, 'mxchat_top_bar_bg_color_callback'),
904 'mxchat-theme',
905 'mxchat_theme_section'
906 );
907
908 add_settings_field(
909 'send_button_font_color',
910 'Send Button Color',
911 array($this, 'mxchat_send_button_font_color_callback'),
912 'mxchat-theme',
913 'mxchat_theme_section'
914 );
915
916 add_settings_field(
917 'chat_input_font_color',
918 'Chat Input Font Color',
919 array($this, 'mxchat_chat_input_font_color_callback'),
920 'mxchat-theme',
921 'mxchat_theme_section'
922 );
923
924 add_settings_field(
925 'chatbot_background_color',
926 'Floating Widget Background Color',
927 array($this, 'mxchat_chatbot_background_color_callback'),
928 'mxchat-theme',
929 'mxchat_theme_section'
930 );
931
932 add_settings_field(
933 'icon_color',
934 'Chatbot Icon Color',
935 array($this, 'mxchat_icon_color_callback'),
936 'mxchat-theme',
937 'mxchat_theme_section'
938 );
939
940 // General Settings Section
941 add_settings_section(
942 'mxchat_general_section',
943 'General Information',
944 null,
945 'mxchat-general'
946 );
947
948
949 }
950
951
952
953
954 public function mxchat_handle_activate_license() {
955 check_ajax_referer('mxchat_activate_license_nonce', 'security');
956
957 $license_key = isset($_POST['key']) ? sanitize_text_field($_POST['key']) : '';
958 $customer_email = isset($_POST['email']) ? sanitize_email($_POST['email']) : '';
959
960 if (empty($license_key) || empty($customer_email)) {
961 wp_send_json_error('Email or License Key is missing');
962 }
963
964 $product_id = 'MxChatPRO';
965
966 $response = wp_remote_get("http://mxchat.ai/?wc-api=software-api&request=activation&email={$customer_email}&license_key={$license_key}&product_id={$product_id}");
967
968 if (is_wp_error($response)) {
969 wp_send_json_error('Activation failed due to a server error');
970 }
971
972 $body = wp_remote_retrieve_body($response);
973 $data = json_decode($body);
974
975 if ($data && isset($data->activated) && $data->activated) {
976 update_option('mxchat_license_status', 'active');
977 wp_send_json_success();
978 } else {
979 $error_message = isset($data->error) ? $data->error : 'Activation failed';
980 update_option('mxchat_license_status', 'inactive');
981 update_option('mxchat_license_error', $error_message);
982 wp_send_json_error($error_message);
983 }
984 }
985
986
987 public function mxchat_rate_limit_callback() {
988 $rate_limits = array('5', '10', '15', '20', '100');
989 $selected_rate_limit = isset($this->options['rate_limit']) ? $this->options['rate_limit'] : '100';
990
991 $disabled = $this->is_activated ? '' : 'disabled';
992 $class = $this->is_activated ? 'pro-feature-wrapper active' : 'pro-feature-wrapper inactive';
993
994 echo '<div class="' . esc_attr($class) . '">';
995 echo '<select id="rate_limit" name="mxchat_options[rate_limit]" ' . $disabled . '>';
996 foreach ($rate_limits as $limit) {
997 echo '<option value="' . esc_attr($limit) . '" ' . selected($selected_rate_limit, $limit, false) . '>' . esc_html($limit) . '</option>';
998 }
999 echo '</select>';
1000
1001 if (!$this->is_activated) {
1002 echo '<div class="pro-feature-overlay">';
1003 echo '<a href="https://mxchat.ai/" target="_blank"><img src="' . plugin_dir_url(__FILE__) . '../images/pro-only-dark.png" alt="Pro Only" /></a>';
1004 echo '</div>';
1005 }
1006
1007 echo '</div>';
1008 }
1009
1010 public function mxchat_rate_limit_message_callback() {
1011 $disabled = $this->is_activated ? '' : 'disabled';
1012 $class = $this->is_activated ? 'pro-feature-wrapper active' : 'pro-feature-wrapper inactive';
1013
1014 echo '<div class="' . esc_attr($class) . '">';
1015 printf(
1016 '<textarea id="rate_limit_message" name="mxchat_options[rate_limit_message]" rows="3" cols="50" %s>%s</textarea>',
1017 esc_attr($disabled),
1018 isset($this->options['rate_limit_message']) ? esc_textarea($this->options['rate_limit_message']) : 'Rate limit exceeded. Please try again later.'
1019 );
1020
1021 if (!$this->is_activated) {
1022 echo '<div class="pro-feature-overlay">';
1023 echo '<a href="https://mxchat.ai/" target="_blank"><img src="' . plugin_dir_url(__FILE__) . '../images/pro-only-dark.png" alt="Pro Only" /></a>';
1024 echo '</div>';
1025 }
1026
1027 echo '</div>';
1028 }
1029
1030
1031 public function mxchat_enable_woocommerce_integration_callback() {
1032 $checked = isset($this->options['enable_woocommerce_integration']) && $this->options['enable_woocommerce_integration'] === '1' ? 'checked' : '';
1033 $disabled = $this->is_activated ? '' : 'disabled';
1034 $class = $this->is_activated ? 'pro-feature-wrapper active' : 'pro-feature-wrapper inactive';
1035
1036 echo '<div class="' . esc_attr($class) . '">';
1037 echo '<label class="toggle-switch">';
1038 echo '<input type="checkbox" id="enable_woocommerce_integration" name="mxchat_options[enable_woocommerce_integration]" value="1" ' . $checked . ' ' . $disabled . '>';
1039 echo '<span class="slider"></span>';
1040 echo '</label>';
1041
1042 if (!$this->is_activated) {
1043 echo '<div class="pro-feature-overlay">';
1044 echo '<a href="https://mxchat.ai/" target="_blank"><img src="' . plugin_dir_url(__FILE__) . '../images/pro-only-dark.png" alt="Pro Only" /></a>';
1045 echo '</div>';
1046 }
1047
1048 echo '</div>';
1049 }
1050
1051
1052 public function mxchat_enable_woocommerce_order_access_callback() {
1053 $checked = isset($this->options['enable_woocommerce_order_access']) && $this->options['enable_woocommerce_order_access'] === '1' ? 'checked' : '';
1054 $disabled = $this->is_activated ? '' : 'disabled';
1055 $class = $this->is_activated ? 'pro-feature-wrapper active' : 'pro-feature-wrapper inactive';
1056
1057 echo '<div class="' . esc_attr($class) . '">';
1058 echo '<label class="toggle-switch">';
1059 echo '<input type="checkbox" id="enable_woocommerce_order_access" name="mxchat_options[enable_woocommerce_order_access]" value="1" ' . $checked . ' ' . $disabled . '>';
1060 echo '<span class="slider"></span>';
1061 echo '</label>';
1062
1063 if (!$this->is_activated) {
1064 echo '<div class="pro-feature-overlay">';
1065 echo '<a href="https://mxchat.ai/" target="_blank"><img src="' . plugin_dir_url(__FILE__) . '../images/pro-only-dark.png" alt="Pro Only" /></a>';
1066 echo '</div>';
1067 }
1068
1069 echo '</div>';
1070 }
1071
1072
1073 private function mxchat_add_option_field($id, $title, $callback = '') {
1074 add_settings_field(
1075 $id,
1076 $title,
1077 $callback ? array($this, $callback) : array($this, $id . '_callback'),
1078 'mxchat-max',
1079 'mxchat_setting_section_id',
1080 $id === 'model' ? ['label_for' => 'model'] : []
1081 );
1082 }
1083
1084
1085 public function api_key_callback() {
1086 $apiKey = isset($this->options['api_key']) ? esc_attr($this->options['api_key']) : '';
1087 echo '<input type="password" id="api_key" name="mxchat_options[api_key]" value="' . $apiKey . '" class="regular-text" />';
1088 echo '<button type="button" id="toggleApiKeyVisibility">Show</button>';
1089 }
1090
1091
1092
1093 public function mxchat_woocommerce_consumer_key_callback() {
1094 $disabled = $this->is_activated ? '' : 'disabled';
1095 $class = $this->is_activated ? 'pro-feature-wrapper active' : 'pro-feature-wrapper inactive';
1096
1097 echo '<div class="' . esc_attr($class) . '">';
1098 printf(
1099 '<input type="text" id="woocommerce_consumer_key" name="mxchat_options[woocommerce_consumer_key]" value="%s" class="regular-text" %s />',
1100 isset($this->options['woocommerce_consumer_key']) ? esc_attr($this->options['woocommerce_consumer_key']) : '',
1101 $disabled
1102 );
1103
1104 if (!$this->is_activated) {
1105 echo '<div class="pro-feature-overlay">';
1106 echo '<a href="https://mxchat.ai/" target="_blank"><img src="' . plugin_dir_url(__FILE__) . '../images/pro-only-dark.png" alt="Pro Only" /></a>';
1107 echo '</div>';
1108 }
1109
1110 echo '</div>';
1111 }
1112
1113 public function mxchat_woocommerce_consumer_secret_callback() {
1114 $disabled = $this->is_activated ? '' : 'disabled';
1115 $class = $this->is_activated ? 'pro-feature-wrapper active' : 'pro-feature-wrapper inactive';
1116
1117 echo '<div class="' . esc_attr($class) . '">';
1118 printf(
1119 '<input type="password" id="woocommerce_consumer_secret" name="mxchat_options[woocommerce_consumer_secret]" value="%s" class="regular-text" %s />',
1120 isset($this->options['woocommerce_consumer_secret']) ? esc_attr($this->options['woocommerce_consumer_secret']) : '',
1121 $disabled
1122 );
1123 echo '<button type="button" id="toggleWooCommerceSecretVisibility">Show</button>';
1124
1125 if (!$this->is_activated) {
1126 echo '<div class="pro-feature-overlay">';
1127 echo '<a href="https://mxchat.ai/" target="_blank"><img src="' . plugin_dir_url(__FILE__) . '../images/pro-only-dark.png" alt="Pro Only" /></a>';
1128 echo '</div>';
1129 }
1130
1131 echo '</div>';
1132 }
1133
1134
1135
1136 public function mxchat_pre_chat_message_callback() {
1137 printf(
1138 '<textarea id="pre_chat_message" name="mxchat_options[pre_chat_message]" rows="5" cols="50">%s</textarea>',
1139 isset($this->options['pre_chat_message']) ? esc_textarea($this->options['pre_chat_message']) : ''
1140 );
1141 }
1142
1143 // Callback for AI Instructions textarea
1144 public function system_prompt_instructions_callback() {
1145 printf(
1146 '<textarea id="system_prompt_instructions" name="mxchat_options[system_prompt_instructions]" rows="5" cols="50">%s</textarea>',
1147 isset($this->options['system_prompt_instructions']) ? esc_textarea($this->options['system_prompt_instructions']) : ''
1148 );
1149 }
1150
1151 public function mxchat_model_callback() {
1152 $models = array(
1153 'gpt-4o' => 'gpt-4o',
1154 'gpt-4o-mini' => 'gpt-4o-mini',
1155 'gpt-4-turbo' => 'gpt-4-turbo',
1156 'gpt-4' => 'gpt-4',
1157 'gpt-3.5-turbo' => 'gpt-3.5-turbo',
1158 );
1159
1160 $selected_model = isset($this->options['model']) ? $this->options['model'] : 'gpt-3.5-turbo';
1161
1162 echo '<select id="model" name="mxchat_options[model]">';
1163 foreach ($models as $model_value => $model_label) {
1164 echo '<option value="' . esc_attr($model_value) . '" ' . selected($selected_model, $model_value, false) . '>' . esc_html($model_label) . '</option>';
1165 }
1166 echo '</select>';
1167 }
1168
1169 public function mxchat_top_bar_title_callback() {
1170 printf(
1171 '<input type="text" id="top_bar_title" name="mxchat_options[top_bar_title]" value="%s" />',
1172 isset($this->options['top_bar_title']) ? esc_attr($this->options['top_bar_title']) : ''
1173 );
1174 }
1175
1176 public function mxchat_intro_message_callback() {
1177 printf(
1178 '<textarea id="intro_message" name="mxchat_options[intro_message]" rows="5" cols="50">%s</textarea>',
1179 isset($this->options['intro_message']) ? esc_textarea($this->options['intro_message']) : 'Hello! How can I assist you today?'
1180 );
1181 }
1182
1183 public function mxchat_input_copy_callback() {
1184 printf(
1185 '<input type="text" id="input_copy" name="mxchat_options[input_copy]" value="%s" placeholder="How can I assist?" />',
1186 isset($this->options['input_copy']) ? esc_attr($this->options['input_copy']) : 'How can I assist?'
1187 );
1188 echo '<p class="description">This is the placeholder text for the chat input field.</p>';
1189 }
1190
1191
1192
1193
1194
1195
1196 public function mxchat_close_button_color_callback() {
1197 $disabled = $this->is_activated ? '' : 'disabled';
1198
1199 echo '<div class="pro-feature-wrapper">';
1200 printf(
1201 '<input type="text" id="close_button_color" name="mxchat_options[close_button_color]" value="%s" class="my-color-field" data-default-color="#4a4a4a" %s />',
1202 isset($this->options['close_button_color']) ? esc_attr($this->options['close_button_color']) : '',
1203 esc_attr($disabled)
1204 );
1205
1206 if (!$this->is_activated) {
1207 echo '<div class="pro-feature-overlay">';
1208 echo '<a href="https://mxchat.ai/" target="_blank"><img src="' . plugin_dir_url(__FILE__) . '../images/pro-only-dark.png" alt="Pro Only" /></a>';
1209 echo '</div>';
1210 }
1211
1212 echo '</div>';
1213 }
1214
1215 public function mxchat_chatbot_bg_color_callback() {
1216 $disabled = $this->is_activated ? '' : 'disabled';
1217
1218 echo '<div class="pro-feature-wrapper">';
1219 printf(
1220 '<input type="text" id="chatbot_bg_color" name="mxchat_options[chatbot_bg_color]" value="%s" class="my-color-field" data-default-color="#f9f9f9" %s />',
1221 isset($this->options['chatbot_bg_color']) ? esc_attr($this->options['chatbot_bg_color']) : '',
1222 esc_attr($disabled)
1223 );
1224
1225 if (!$this->is_activated) {
1226 echo '<div class="pro-feature-overlay">';
1227 echo '<a href="https://mxchat.ai/" target="_blank"><img src="' . plugin_dir_url(__FILE__) . '../images/pro-only-dark.png" alt="Pro Only" /></a>';
1228 echo '</div>';
1229 }
1230
1231 echo '</div>';
1232 }
1233
1234 public function mxchat_user_message_bg_color_callback() {
1235 $disabled = $this->is_activated ? '' : 'disabled';
1236
1237 echo '<div class="pro-feature-wrapper">';
1238 printf(
1239 '<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 />',
1240 isset($this->options['user_message_bg_color']) ? esc_attr($this->options['user_message_bg_color']) : '',
1241 esc_attr($disabled)
1242 );
1243
1244 if (!$this->is_activated) {
1245 echo '<div class="pro-feature-overlay">';
1246 echo '<a href="https://mxchat.ai/" target="_blank"><img src="' . plugin_dir_url(__FILE__) . '../images/pro-only-dark.png" alt="Pro Only" /></a>';
1247 echo '</div>';
1248 }
1249
1250 echo '</div>';
1251 }
1252
1253 public function mxchat_user_message_font_color_callback() {
1254 $disabled = $this->is_activated ? '' : 'disabled';
1255
1256 echo '<div class="pro-feature-wrapper">';
1257 printf(
1258 '<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 />',
1259 isset($this->options['user_message_font_color']) ? esc_attr($this->options['user_message_font_color']) : '',
1260 esc_attr($disabled)
1261 );
1262
1263 if (!$this->is_activated) {
1264 echo '<div class="pro-feature-overlay">';
1265 echo '<a href="https://mxchat.ai/" target="_blank"><img src="' . plugin_dir_url(__FILE__) . '../images/pro-only-dark.png" alt="Pro Only" /></a>';
1266 echo '</div>';
1267 }
1268
1269 echo '</div>';
1270 }
1271
1272 public function mxchat_bot_message_bg_color_callback() {
1273 $disabled = $this->is_activated ? '' : 'disabled';
1274
1275 echo '<div class="pro-feature-wrapper">';
1276 printf(
1277 '<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 />',
1278 isset($this->options['bot_message_bg_color']) ? esc_attr($this->options['bot_message_bg_color']) : '',
1279 esc_attr($disabled)
1280 );
1281
1282 if (!$this->is_activated) {
1283 echo '<div class="pro-feature-overlay">';
1284 echo '<a href="https://mxchat.ai/" target="_blank"><img src="' . plugin_dir_url(__FILE__) . '../images/pro-only-dark.png" alt="Pro Only" /></a>';
1285 echo '</div>';
1286 }
1287
1288 echo '</div>';
1289 }
1290
1291 public function mxchat_bot_message_font_color_callback() {
1292 $disabled = $this->is_activated ? '' : 'disabled';
1293
1294 echo '<div class="pro-feature-wrapper">';
1295 printf(
1296 '<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 />',
1297 isset($this->options['bot_message_font_color']) ? esc_attr($this->options['bot_message_font_color']) : '',
1298 esc_attr($disabled)
1299 );
1300
1301 if (!$this->is_activated) {
1302 echo '<div class="pro-feature-overlay">';
1303 echo '<a href="https://mxchat.ai/" target="_blank"><img src="' . plugin_dir_url(__FILE__) . '../images/pro-only-dark.png" alt="Pro Only" /></a>';
1304 echo '</div>';
1305 }
1306
1307 echo '</div>';
1308 }
1309
1310 public function mxchat_top_bar_bg_color_callback() {
1311 $disabled = $this->is_activated ? '' : 'disabled';
1312
1313 echo '<div class="pro-feature-wrapper">';
1314 printf(
1315 '<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 />',
1316 isset($this->options['top_bar_bg_color']) ? esc_attr($this->options['top_bar_bg_color']) : '',
1317 esc_attr($disabled)
1318 );
1319
1320 if (!$this->is_activated) {
1321 echo '<div class="pro-feature-overlay">';
1322 echo '<a href="https://mxchat.ai/" target="_blank"><img src="' . plugin_dir_url(__FILE__) . '../images/pro-only-dark.png" alt="Pro Only" /></a>';
1323 echo '</div>';
1324 }
1325
1326 echo '</div>';
1327 }
1328
1329 public function mxchat_send_button_font_color_callback() {
1330 $disabled = $this->is_activated ? '' : 'disabled';
1331
1332 echo '<div class="pro-feature-wrapper">';
1333 printf(
1334 '<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 />',
1335 isset($this->options['send_button_font_color']) ? esc_attr($this->options['send_button_font_color']) : '',
1336 esc_attr($disabled)
1337 );
1338
1339 if (!$this->is_activated) {
1340 echo '<div class="pro-feature-overlay">';
1341 echo '<a href="https://mxchat.ai/" target="_blank"><img src="' . plugin_dir_url(__FILE__) . '../images/pro-only-dark.png" alt="Pro Only" /></a>';
1342 echo '</div>';
1343 }
1344
1345 echo '</div>';
1346 }
1347
1348 public function mxchat_chatbot_background_color_callback() {
1349 $disabled = $this->is_activated ? '' : 'disabled';
1350
1351 echo '<div class="pro-feature-wrapper">';
1352 printf(
1353 '<input type="text" id="chatbot_background_color" name="mxchat_options[chatbot_background_color]" value="%s" class="my-color-field" data-default-color="#000000" %s />',
1354 isset($this->options['chatbot_background_color']) ? esc_attr($this->options['chatbot_background_color']) : '',
1355 esc_attr($disabled)
1356 );
1357
1358 if (!$this->is_activated) {
1359 echo '<div class="pro-feature-overlay">';
1360 echo '<a href="https://mxchat.ai/" target="_blank"><img src="' . plugin_dir_url(__FILE__) . '../images/pro-only-dark.png" alt="Pro Only" /></a>';
1361 echo '</div>';
1362 }
1363
1364 echo '</div>';
1365 }
1366
1367 public function mxchat_icon_color_callback() {
1368 $disabled = $this->is_activated ? '' : 'disabled';
1369
1370 echo '<div class="pro-feature-wrapper">';
1371 printf(
1372 '<input type="text" id="icon_color" name="mxchat_options[icon_color]" value="%s" class="my-color-field" data-default-color="#ffffff" %s />',
1373 isset($this->options['icon_color']) ? esc_attr($this->options['icon_color']) : '',
1374 esc_attr($disabled)
1375 );
1376
1377 if (!$this->is_activated) {
1378 echo '<div class="pro-feature-overlay">';
1379 echo '<a href="https://mxchat.ai/" target="_blank"><img src="' . plugin_dir_url(__FILE__) . '../images/pro-only-dark.png" alt="Pro Only" /></a>';
1380 echo '</div>';
1381 }
1382
1383 echo '</div>';
1384 }
1385
1386 public function mxchat_chat_input_font_color_callback() {
1387 $disabled = $this->is_activated ? '' : 'disabled';
1388
1389 echo '<div class="pro-feature-wrapper">';
1390 printf(
1391 '<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 />',
1392 isset($this->options['chat_input_font_color']) ? esc_attr($this->options['chat_input_font_color']) : '',
1393 esc_attr($disabled)
1394 );
1395
1396 if (!$this->is_activated) {
1397 echo '<div class="pro-feature-overlay">';
1398 echo '<a href="https://mxchat.ai/" target="_blank"><img src="' . plugin_dir_url(__FILE__) . '../images/pro-only-dark.png" alt="Pro Only" /></a>';
1399 echo '</div>';
1400 }
1401
1402 echo '</div>';
1403 }
1404
1405
1406 public function mxchat_append_to_body_callback() {
1407 $append_to_body_checked = isset($this->options['append_to_body']) && $this->options['append_to_body'] === 'on' ? 'checked' : '';
1408 echo '<label class="toggle-switch">';
1409 printf(
1410 '<input type="checkbox" id="append_to_body" name="mxchat_options[append_to_body]" %s />',
1411 esc_attr($append_to_body_checked)
1412 );
1413 echo '<span class="slider"></span>';
1414 echo '</label>';
1415 echo '<p class="description">Enable to append the chat widget directly to the body element or use shortcode: [mxchat_chatbot floating="yes"]</p>';
1416 }
1417
1418
1419 public function mxchat_privacy_toggle_callback() {
1420 // Check if the privacy toggle is enabled
1421 $privacy_toggle_checked = isset($this->options['privacy_toggle']) && $this->options['privacy_toggle'] === 'on' ? 'checked' : '';
1422
1423 // Retrieve the stored privacy text if it exists
1424 $privacy_text = isset($this->options['privacy_text']) ? wp_kses_post($this->options['privacy_text']) : 'By chatting, you agree to our <a href="https://example.com/privacy-policy" target="_blank">privacy policy</a>.';
1425
1426 // Output the toggle switch
1427 echo '<label class="toggle-switch">';
1428 printf(
1429 '<input type="checkbox" id="privacy_toggle" name="mxchat_options[privacy_toggle]" %s />',
1430 esc_attr($privacy_toggle_checked)
1431 );
1432 echo '<span class="slider"></span>';
1433 echo '</label>';
1434 echo '<p class="description">Enable this option to display a privacy notice below the chat widget.</p>';
1435
1436 // Output the custom text input field
1437 printf(
1438 '<textarea id="privacy_text" name="mxchat_options[privacy_text]" rows="5" cols="50" class="regular-text">%s</textarea>',
1439 esc_textarea($privacy_text)
1440 );
1441 echo '<p class="description">Enter the privacy policy text. You can include HTML links.</p>';
1442 }
1443
1444
1445 public function mxchat_complianz_toggle_callback() {
1446 // Check if the Complianz toggle is enabled
1447 $complianz_toggle_checked = isset($this->options['complianz_toggle']) && $this->options['complianz_toggle'] === 'on' ? 'checked' : '';
1448
1449 // Check if the plugin is activated (paid feature)
1450 $disabled = $this->is_activated ? '' : 'disabled';
1451 $class = $this->is_activated ? 'pro-feature-wrapper active' : 'pro-feature-wrapper inactive';
1452
1453 echo '<div class="' . esc_attr($class) . '">';
1454
1455 // Output the toggle switch
1456 echo '<label class="toggle-switch">';
1457 printf(
1458 '<input type="checkbox" id="complianz_toggle" name="mxchat_options[complianz_toggle]" %s %s />',
1459 esc_attr($complianz_toggle_checked),
1460 esc_attr($disabled)
1461 );
1462 echo '<span class="slider"></span>';
1463 echo '</label>';
1464 echo '<p class="description">Enable this option to apply Complianz consent logic to the chatbot.</p>';
1465
1466 // If the feature is not activated, show the Pro feature overlay
1467 if (!$this->is_activated) {
1468 echo '<div class="pro-feature-overlay">';
1469 echo '<a href="https://mxchat.ai/" target="_blank"><img src="' . plugin_dir_url(__FILE__) . '../images/pro-only-dark.png" alt="Pro Only" /></a>';
1470 echo '</div>';
1471 }
1472
1473 echo '</div>';
1474 }
1475
1476
1477
1478
1479
1480 public function mxchat_link_target_toggle_callback() {
1481 // Check if the toggle is enabled in the options
1482 $link_target_toggle = isset($this->options['link_target_toggle']) && $this->options['link_target_toggle'] === 'on' ? 'checked' : '';
1483
1484 // Output the toggle switch
1485 echo '<label class="toggle-switch">';
1486 printf(
1487 '<input type="checkbox" id="link_target_toggle" name="mxchat_options[link_target_toggle]" %s />',
1488 esc_attr($link_target_toggle)
1489 );
1490 echo '<span class="slider"></span>';
1491 echo '</label>';
1492 echo '<p class="description">Enable to open links in a new tab (default is to open in the same tab).</p>';
1493 }
1494
1495
1496
1497
1498 public function mxchat_enqueue_admin_assets() {
1499 wp_enqueue_style('wp-color-picker');
1500
1501 // Get the plugin version or file modification time for cache busting
1502 $plugin_version = '1.1.0'; // Replace this with your plugin's version
1503
1504 // File paths
1505 $color_picker_js_path = plugin_dir_path(__FILE__) . '../js/my-color-picker.js';
1506 $embedding_check_js_path = plugin_dir_path(__FILE__) . '../js/embedding-check.js';
1507 $admin_css_path = plugin_dir_path(__FILE__) . '../css/admin-style.css';
1508 $transcripts_js_path = plugin_dir_path(__FILE__) . '../js/mxchat_transcripts.js';
1509
1510 // Check if files exist and get modification times
1511 $color_picker_version = file_exists($color_picker_js_path) ? filemtime($color_picker_js_path) : $plugin_version;
1512 $embedding_check_version = file_exists($embedding_check_js_path) ? filemtime($embedding_check_js_path) : $plugin_version;
1513 $admin_css_version = file_exists($admin_css_path) ? filemtime($admin_css_path) : $plugin_version;
1514 $transcripts_js_version = file_exists($transcripts_js_path) ? filemtime($transcripts_js_path) : $plugin_version;
1515
1516 // Enqueue scripts and styles with corrected paths
1517 wp_enqueue_script(
1518 'mxchat-color-picker',
1519 plugin_dir_url(__FILE__) . '../js/my-color-picker.js',
1520 array('wp-color-picker'),
1521 $color_picker_version,
1522 true
1523 );
1524
1525 wp_enqueue_script(
1526 'mxchat-embedding-check',
1527 plugin_dir_url(__FILE__) . '../js/embedding-check.js',
1528 array(),
1529 $embedding_check_version,
1530 true
1531 );
1532
1533 wp_enqueue_script(
1534 'mxchat-transcripts-js',
1535 plugin_dir_url(__FILE__) . '../js/mxchat_transcripts.js',
1536 array('jquery'),
1537 $transcripts_js_version,
1538 true
1539 );
1540
1541 wp_enqueue_script(
1542 'mxchat-admin-js',
1543 plugin_dir_url(__FILE__) . '../js/mxchat-admin.js',
1544 array('jquery'),
1545 $plugin_version,
1546 true
1547 );
1548
1549 wp_localize_script('mxchat-admin-js', 'mxchatAdmin', array(
1550 'ajax_url' => admin_url('admin-ajax.php'),
1551 'nonce' => wp_create_nonce('mxchat_activate_license_nonce'),
1552 ));
1553
1554 wp_enqueue_style(
1555 'mxchat-admin-css',
1556 plugin_dir_url(__FILE__) . '../css/admin-style.css',
1557 array(),
1558 $admin_css_version
1559 );
1560
1561 // Use wp_json_encode for localizing script
1562 wp_localize_script('mxchat-color-picker', 'mxchatStyleSettings', array(
1563 'ajax_url' => admin_url('admin-ajax.php'),
1564 'link_target' => $link_target,
1565 'user_message_bg_color' => $this->options['user_message_bg_color'] ?? '#fff',
1566 'user_message_font_color' => $this->options['user_message_font_color'] ?? '#212121',
1567 'bot_message_bg_color' => $this->options['bot_message_bg_color'] ?? '#212121',
1568 'bot_message_font_color' => $this->options['bot_message_font_color'] ?? '#fff',
1569 'top_bar_bg_color' => $this->options['top_bar_bg_color'] ?? '#212121',
1570 'send_button_font_color' => $this->options['send_button_font_color'] ?? '#212121',
1571 'close_button_color' => $this->options['close_button_color'] ?? '#fff',
1572 'chatbot_background_color' => $this->options['chatbot_background_color'] ?? '#212121',
1573 'icon_color' => $this->options['icon_color'] ?? '#fff',
1574 'chat_input_font_color' => $this->options['chat_input_font_color'] ?? '#212121'
1575 ));
1576 }
1577
1578 public function mxchat_sanitize($input) {
1579 $new_input = array();
1580
1581 if (isset($input['api_key'])) {
1582 $new_input['api_key'] = sanitize_text_field($input['api_key']);
1583 }
1584
1585 if (isset($input['enable_woocommerce_integration'])) {
1586 $new_input['enable_woocommerce_integration'] = isset($input['enable_woocommerce_integration']) && $input['enable_woocommerce_integration'] === '1' ? '1' : '0';
1587
1588 }
1589
1590 if (isset($input['privacy_toggle'])) {
1591 $new_input['privacy_toggle'] = $input['privacy_toggle'];
1592 }
1593
1594 if (isset($input['complianz_toggle'])) {
1595 $new_input['complianz_toggle'] = $input['complianz_toggle'];
1596 }
1597
1598 // Handle custom privacy text input
1599 if (isset($input['privacy_text'])) {
1600 // Allow basic HTML for links
1601 $new_input['privacy_text'] = wp_kses_post($input['privacy_text']);
1602 }
1603
1604
1605 if (isset($input['enable_woocommerce_order_access'])) {
1606 $new_input['enable_woocommerce_order_access'] = isset($input['enable_woocommerce_order_access']) && $input['enable_woocommerce_order_access'] === '1' ? '1' : '0';
1607
1608 }
1609
1610 if (isset($input['system_prompt_instructions'])) {
1611 $new_input['system_prompt_instructions'] = sanitize_textarea_field($input['system_prompt_instructions']);
1612 }
1613
1614 if (isset($input['mxchat_pro_email'])) {
1615 $new_input['mxchat_pro_email'] = sanitize_email($input['mxchat_pro_email']);
1616 }
1617
1618 if (isset($input['mxchat_activation_key'])) {
1619 $new_input['mxchat_activation_key'] = sanitize_text_field($input['mxchat_activation_key']);
1620 }
1621
1622 if (isset($input['append_to_body'])) {
1623 $new_input['append_to_body'] = $input['append_to_body'] === 'on' ? 'on' : 'off';
1624 }
1625
1626 if (isset($input['top_bar_title'])) {
1627 $new_input['top_bar_title'] = sanitize_text_field($input['top_bar_title']);
1628 }
1629
1630 if (isset($input['intro_message'])) {
1631 $new_input['intro_message'] = sanitize_text_field($input['intro_message']);
1632 }
1633
1634 if (isset($input['input_copy'])) {
1635 $new_input['input_copy'] = sanitize_text_field($input['input_copy']);
1636 }
1637
1638
1639 if (isset($input['rate_limit_message'])) {
1640 $new_input['rate_limit_message'] = sanitize_text_field($input['rate_limit_message']);
1641 }
1642
1643
1644 if (isset($input['pre_chat_message'])) {
1645 $new_input['pre_chat_message'] = sanitize_textarea_field($input['pre_chat_message']);
1646 }
1647
1648 if (isset($input['model'])) {
1649 $allowed_models = array(
1650 'gpt-4o',
1651 'gpt-4o-mini',
1652 'gpt-4-turbo',
1653 'gpt-4',
1654 'gpt-3.5-turbo',
1655 );
1656 if (in_array($input['model'], $allowed_models)) {
1657 $new_input['model'] = sanitize_text_field($input['model']);
1658 }
1659 }
1660
1661 // Sanitize new pro features
1662 if (isset($input['close_button_color'])) {
1663 $new_input['close_button_color'] = sanitize_hex_color($input['close_button_color']);
1664 }
1665
1666 if (isset($input['chatbot_bg_color'])) {
1667 $new_input['chatbot_bg_color'] = sanitize_hex_color($input['chatbot_bg_color']);
1668 }
1669
1670 if (isset($input['woocommerce_consumer_key'])) {
1671 $new_input['woocommerce_consumer_key'] = sanitize_text_field($input['woocommerce_consumer_key']);
1672 }
1673
1674 if (isset($input['woocommerce_consumer_secret'])) {
1675 $new_input['woocommerce_consumer_secret'] = sanitize_text_field($input['woocommerce_consumer_secret']);
1676 }
1677
1678 if (isset($input['user_message_bg_color'])) {
1679 $new_input['user_message_bg_color'] = sanitize_hex_color($input['user_message_bg_color']);
1680 }
1681
1682 if (isset($input['user_message_font_color'])) {
1683 $new_input['user_message_font_color'] = sanitize_hex_color($input['user_message_font_color']);
1684 }
1685
1686 if (isset($input['bot_message_bg_color'])) {
1687 $new_input['bot_message_bg_color'] = sanitize_hex_color($input['bot_message_bg_color']);
1688 }
1689
1690 if (isset($input['bot_message_font_color'])) {
1691 $new_input['bot_message_font_color'] = sanitize_hex_color($input['bot_message_font_color']);
1692 }
1693
1694 if (isset($input['top_bar_bg_color'])) {
1695 $new_input['top_bar_bg_color'] = sanitize_hex_color($input['top_bar_bg_color']);
1696 }
1697
1698 if (isset($input['send_button_font_color'])) {
1699 $new_input['send_button_font_color'] = sanitize_hex_color($input['send_button_font_color']);
1700 }
1701
1702 if (isset($input['chatbot_background_color'])) {
1703 $new_input['chatbot_background_color'] = sanitize_hex_color($input['chatbot_background_color']);
1704 }
1705
1706 if (isset($input['icon_color'])) {
1707 $new_input['icon_color'] = sanitize_hex_color($input['icon_color']);
1708 }
1709
1710 if (isset($input['chat_input_font_color'])) {
1711 $new_input['chat_input_font_color'] = sanitize_hex_color($input['chat_input_font_color']);
1712 }
1713
1714 return $new_input;
1715 }
1716
1717
1718 // Method to append the chatbot to the body
1719 public function mxchat_append_chatbot_to_body() {
1720 $options = get_option('mxchat_options');
1721 if (isset($options['append_to_body']) && $options['append_to_body'] === 'on') {
1722 echo do_shortcode('[mxchat_chatbot floating="yes"]');
1723 }
1724 }
1725
1726
1727
1728 private function mxchat_extract_main_content($html) {
1729 $dom = new DOMDocument;
1730 libxml_use_internal_errors(true); // Suppress HTML parsing errors
1731 @$dom->loadHTML($html);
1732 libxml_clear_errors();
1733
1734 $xpath = new DOMXPath($dom);
1735
1736 // Simplified selectors focusing on common content areas
1737 $selectors = [
1738 '//article',
1739 '//*[@id="content"]',
1740 '//*[@class="entry-content"]',
1741 '//main',
1742 ];
1743
1744 foreach ($selectors as $selector) {
1745 $nodes = $xpath->query($selector);
1746 if ($nodes->length > 0) {
1747 $content = '';
1748 foreach ($nodes as $node) {
1749 $content .= $dom->saveHTML($node);
1750 }
1751 return $content;
1752 }
1753 }
1754
1755 // Fallback: Return the entire body content if no specific selector matches
1756 $body = $dom->getElementsByTagName('body');
1757 return $body->length > 0 ? $dom->saveHTML($body->item(0)) : $html;
1758 }
1759
1760 public function mxchat_handle_sitemap_submission() {
1761 if (!isset($_POST['submit_sitemap']) || !current_user_can('manage_options')) {
1762 return;
1763 }
1764
1765 check_admin_referer('mxchat_submit_sitemap_action', 'mxchat_submit_sitemap_nonce');
1766
1767 $sitemap_url = esc_url_raw($_POST['sitemap_url']);
1768
1769 $response = wp_remote_get($sitemap_url);
1770 if (is_wp_error($response) || wp_remote_retrieve_response_code($response) !== 200) {
1771 set_transient('mxchat_admin_notice', 'Failed to fetch the sitemap. Please check the URL and try again.', 30);
1772 wp_safe_redirect(esc_url(admin_url('admin.php?page=mxchat-prompts')));
1773 exit;
1774 }
1775
1776 $sitemap_content = wp_remote_retrieve_body($response);
1777
1778 $xml = simplexml_load_string($sitemap_content);
1779 if ($xml === false) {
1780 set_transient('mxchat_admin_notice', 'Invalid sitemap XML. Please provide a valid sitemap.', 30);
1781 wp_safe_redirect(esc_url(admin_url('admin.php?page=mxchat-prompts')));
1782 exit;
1783 }
1784
1785 $embedding_success = true; // Flag to track if all embeddings are successful
1786
1787 foreach ($xml->url as $url_element) {
1788 $page_url = (string)$url_element->loc;
1789
1790 $page_response = wp_remote_get($page_url);
1791 if (is_wp_error($page_response) || wp_remote_retrieve_response_code($page_response) !== 200) {
1792 continue;
1793 }
1794
1795 $page_html = wp_remote_retrieve_body($page_response);
1796 $page_content = $this->mxchat_extract_main_content($page_html);
1797 $sanitized_content = $this->mxchat_sanitize_content_for_api($page_content);
1798
1799 if (!empty($sanitized_content)) {
1800 $embedding_vector = $this->mxchat_generate_embedding($sanitized_content);
1801 if (is_array($embedding_vector)) {
1802 MxChat_Utils::submit_content_to_db($sanitized_content, $page_url, $this->options['api_key']);
1803 } else {
1804 $embedding_success = false; // Set flag to false if any embedding fails
1805 }
1806 }
1807 }
1808
1809 if ($embedding_success) {
1810 set_transient('mxchat_admin_notice', 'Sitemap content successfully submitted!', 30);
1811 } else {
1812 set_transient('mxchat_admin_notice', 'Some content failed to embed. Please check your API key and try again.', 30);
1813 }
1814
1815 wp_safe_redirect(esc_url(admin_url('admin.php?page=mxchat-prompts')));
1816 exit;
1817 }
1818
1819
1820
1821 private function mxchat_sanitize_content_for_api($content) {
1822 // Remove script, style tags, and HTML comments
1823 $content = preg_replace('/<script\b[^>]*>(.*?)<\/script>/is', '', $content);
1824 $content = preg_replace('/<style\b[^>]*>(.*?)<\/style>/is', '', $content);
1825 $content = preg_replace('/<!--(.|\s)*?-->/', '', $content);
1826
1827 // Remove all HTML tags and decode HTML entities
1828 $content = wp_strip_all_tags($content);
1829 $content = html_entity_decode($content, ENT_QUOTES | ENT_HTML5);
1830
1831 // Trim and normalize whitespace
1832 $content = trim(preg_replace('/\s+/', ' ', $content));
1833
1834 return $content;
1835 }
1836
1837
1838 }
1839 ?>
1840