PluginProbe
MxChat – AI Chatbot & Content Generation for WordPress / 1.0.5
MxChat – AI Chatbot & Content Generation for WordPress v1.0.5
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.0.5, at includes/class-mxchat-admin.php

1,354 lines 58.5 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
36 }
37
38 // Method to check if the license is active
39 private function is_license_active() {
40 $license_status = get_option('mxchat_license_status', 'inactive');
41 return $license_status === 'active';
42 }
43
44 // Initialize default options
45 private function initialize_default_options() {
46 $default_options = array(
47 'api_key' => '',
48 '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:
49 - Your name is [Chatbot Name]. Always introduce yourself as this name when appropriate.
50 - 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.
51 - When appropriate, highlight the benefits of [insert proper subject here]. Offer to guide visitors to relevant pages or provide them with more information.
52 - 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.
53 - Keep your responses short, concise, and to the point. Provide clear and direct answers suitable for a chatbot interaction.
54 - 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.
55 - 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.',
56 'model' => 'gpt-3.5-turbo',
57 'rate_limit' => '100',
58 'rate_limit_message' => 'Rate limit exceeded. Please try again later.',
59 'top_bar_title' => 'MxChat',
60 'intro_message' => 'Hello! How can I assist you today?',
61 'append_to_body' => 'on',
62 'close_button_color' => '#fff',
63 'chatbot_bg_color' => '#fff',
64 'user_message_bg_color' => '#fff',
65 'user_message_font_color' => '#212121',
66 'bot_message_bg_color' => '#212121',
67 'bot_message_font_color' => '#fff',
68 'top_bar_bg_color' => '#212121',
69 'send_button_font_color' => '#212121',
70 'chat_input_font_color' => '#212121',
71 'chatbot_background_color' => '#212121',
72 'icon_color' => '#fff',
73 );
74
75
76 // Merge existing options with defaults
77 $existing_options = get_option('mxchat_options', array());
78 $merged_options = wp_parse_args($existing_options, $default_options);
79
80 // Update the options if they have changed
81 if ($existing_options !== $merged_options) {
82 update_option('mxchat_options', $merged_options);
83 }
84
85 // Update the $this->options property
86 $this->options = $merged_options;
87 }
88
89 public function mxchat_add_plugin_page() {
90 // Main menu page
91 add_menu_page(
92 'MxChat Settings',
93 'MxChat',
94 'manage_options',
95 'mxchat-max',
96 array($this, 'mxchat_create_admin_page'),
97 'dashicons-testimonial',
98 6
99 );
100
101 // Submenu page for Knowledge
102 add_submenu_page(
103 'mxchat-max',
104 'Prompts',
105 'Knowledge',
106 'manage_options',
107 'mxchat-prompts',
108 array($this, 'mxchat_create_prompts_page')
109 );
110
111 // Submenu page for Chat Transcripts
112 add_submenu_page(
113 'mxchat-max', // Corrected parent slug to match the main menu
114 'Chat Transcripts',
115 'Transcripts',
116 'manage_options',
117 'mxchat-transcripts',
118 array($this, 'mxchat_create_transcripts_page') // Prefixed function name with mxchat_
119 );
120
121 // Submenu page for Activation Key
122 add_submenu_page(
123 'mxchat-max',
124 'Pro Upgrade',
125 'Pro Upgrade',
126 'manage_options',
127 'mxchat-activation',
128 array($this, 'mxchat_create_activation_page')
129 );
130 }
131
132
133 public function mxchat_handle_content_submission() {
134 // Check if the form was submitted and the user has sufficient permissions
135 if (!isset($_POST['submit_content']) || !current_user_can('manage_options')) {
136 return;
137 }
138
139 // Verify the nonce field for security
140 $nonce = isset($_POST['mxchat_submit_content_nonce']) ? sanitize_text_field(wp_unslash($_POST['mxchat_submit_content_nonce'])) : '';
141 if (!wp_verify_nonce($nonce, 'mxchat_submit_content_action')) {
142 wp_die('Nonce verification failed.');
143 }
144
145 // Sanitize the content input
146 $article_content = sanitize_textarea_field($_POST['article_content']);
147
148 // Generate the embedding vector for the content
149 $embedding_vector = $this->mxchat_generate_embedding($article_content);
150
151 global $wpdb;
152 $table_name = $wpdb->prefix . 'mxchat_system_prompt_content';
153
154 // Check if the 'source_url' column exists in the table and add it if it doesn't
155 if ($wpdb->get_var($wpdb->prepare("SHOW COLUMNS FROM {$table_name} LIKE %s", 'source_url')) != 'source_url') {
156 // Use wpdb::query and a prepared statement to avoid SQL injection
157 $wpdb->query($wpdb->prepare("ALTER TABLE {$table_name} ADD source_url VARCHAR(255) DEFAULT ''"));
158 }
159
160 if (is_array($embedding_vector)) {
161 // Serialize the embedding vector before storing it
162 $embedding_vector_serialized = serialize($embedding_vector);
163
164 // Insert the content and embedding vector into the database, using a prepared statement
165 $inserted = $wpdb->insert(
166 $table_name,
167 array(
168 'article_content' => $article_content,
169 'embedding_vector' => $embedding_vector_serialized,
170 'source_url' => '', // Empty string as a placeholder for now, or pass a valid URL if applicable
171 ),
172 array(
173 '%s', // Format for article_content (string)
174 '%s', // Format for embedding_vector (serialized string)
175 '%s', // Format for source_url (string)
176 )
177 );
178
179 if ($inserted === false) {
180 error_log('Error inserting content: ' . $wpdb->last_error);
181 } else {
182 wp_redirect(esc_url(admin_url('admin.php?page=mxchat-prompts&submitted=true')));
183 exit;
184 }
185 } else {
186 error_log('Embedding generation failed for article content: ' . $article_content);
187 wp_redirect(esc_url(admin_url('admin.php?page=mxchat-prompts&embedding_failed=true')));
188 exit;
189 }
190 }
191
192 public function mxchat_handle_delete_prompt() {
193 // Sanitize and validate nonce using wp_unslash and sanitize_text_field
194 $nonce = isset($_GET['_wpnonce']) ? sanitize_text_field(wp_unslash($_GET['_wpnonce'])) : '';
195 if (empty($nonce) || !wp_verify_nonce($nonce, 'mxchat_delete_prompt_nonce')) {
196 wp_die('Nonce verification failed.');
197 }
198
199 // Check user permissions
200 if (!current_user_can('manage_options')) {
201 wp_die('You do not have sufficient permissions to delete prompts.');
202 }
203
204 // Sanitize and validate the 'id' parameter
205 $id = isset($_GET['id']) ? intval($_GET['id']) : 0;
206 if ($id <= 0) {
207 wp_die('Invalid prompt ID.');
208 }
209
210 global $wpdb;
211 $table_name = $wpdb->prefix . 'mxchat_system_prompt_content';
212
213 // Clear relevant cache before deletion
214 $cache_key = 'prompt_' . $id;
215 wp_cache_delete($cache_key, 'mxchat_prompts');
216
217 // Delete the record using a prepared statement
218 $deleted = $wpdb->delete($table_name, array('id' => $id), array('%d'));
219
220 if ($deleted !== false) {
221 // Optionally, clear a general cache if you have one
222 wp_cache_delete('all_prompts', 'mxchat_prompts');
223 }
224
225 // Redirect to the prompts page with a success message
226 $redirect_url = add_query_arg(array(
227 'page' => 'mxchat-prompts',
228 'deleted' => 'true'
229 ), admin_url('admin.php'));
230
231 wp_safe_redirect($redirect_url);
232 exit;
233 }
234
235 public function mxchat_create_admin_page() {
236 ?>
237 <div class="wrap mxchat-admin">
238 <div class="mxchat-pro-banner">
239 <p>
240 Want even more features such as a fully customizable theme, chat transcripts review, a variety of icon selections, dedicated support, and much more?
241 <a href="https://mxchat.ai/" target="_blank">Upgrade to MxChat Pro today!</a>
242 </p>
243 </div>
244 <h2 class="admin-title">Mx<span class="admin-emphasis">Chat</span></h2>
245 <form method="post" action="options.php">
246 <?php
247 settings_fields('mxchat_option_group');
248 do_settings_sections('mxchat-max');
249
250 $append_to_body_checked = isset($this->options['append_to_body']) && $this->options['append_to_body'] === 'on' ? 'checked' : '';
251 ?>
252 <h3>Chat Widget Settings</h3>
253 <label class="toggle-switch-label" for="append_to_body">Append Chat Widget to Body:</label>
254 <label class="toggle-switch">
255 <input type="checkbox" id="append_to_body" name="mxchat_options[append_to_body]" <?php echo esc_attr($append_to_body_checked); ?> />
256 <span class="slider"></span>
257 </label>
258 <p class="description">Enable to append the chat widget directly to the body element.</p>
259 <p>If not appended to body - use shortcode: [mxchat_chatbot floating="yes"]</p>
260
261 <?php
262 submit_button();
263 ?>
264 </form>
265 </div>
266 <?php
267 }
268
269
270 public function mxchat_create_transcripts_page() {
271 ?>
272 <div class="wrap mxchat-admin">
273 <h2><?php esc_html_e('Chat Transcripts', 'mxchat'); ?></h2>
274 <form id="mxchat-delete-form" method="post">
275 <?php wp_nonce_field('mxchat_delete_chat_history', 'mxchat_delete_chat_nonce'); ?>
276 <div class="mxchat-controls">
277 <label for="mxchat-select-all-transcripts" class="mxchat-select-all-label">
278 <input type="checkbox" id="mxchat-select-all-transcripts" /> <?php esc_html_e('Select All', 'mxchat'); ?>
279 </label>
280 <input type="submit" value="<?php esc_attr_e('Delete Selected', 'mxchat'); ?>" class="button button-primary delete-chats-button" />
281 </div>
282 <div id="mxchat-transcripts">
283 <!-- Transcripts will be loaded here -->
284 </div>
285 </form>
286 </div>
287 <?php
288 }
289
290
291
292
293 public function mxchat_create_prompts_page() {
294 global $wpdb;
295 $table_name = $wpdb->prefix . 'mxchat_system_prompt_content';
296
297 // Verify the nonce before processing the request
298 $nonce = isset($_GET['_wpnonce']) ? sanitize_text_field($_GET['_wpnonce']) : '';
299
300 if (!empty($nonce) && wp_verify_nonce($nonce, 'mxchat_prompts_search_nonce')) {
301 // Sanitize input data
302 $search_query = isset($_GET['search']) ? sanitize_text_field($_GET['search']) : '';
303 $current_page = isset($_GET['paged']) ? absint($_GET['paged']) : 1;
304 } else {
305 $search_query = '';
306 $current_page = 1;
307 }
308
309 $per_page = 10;
310
311 // Create cache keys
312 $cache_key_total = 'total_prompts_' . md5($search_query);
313 $cache_key_prompts = 'prompts_' . md5($search_query . '_' . $current_page);
314
315 // Retrieve total number of prompts from cache or database
316 $total_prompts = wp_cache_get($cache_key_total, 'mxchat_prompts');
317 if ($total_prompts === false) {
318 if (!empty($search_query)) {
319 $total_prompts = $wpdb->get_var(
320 $wpdb->prepare(
321 "SELECT COUNT(*) FROM {$table_name} WHERE article_content LIKE %s",
322 '%' . $wpdb->esc_like($search_query) . '%'
323 )
324 );
325 } else {
326 $total_prompts = $wpdb->get_var("SELECT COUNT(*) FROM {$table_name}");
327 }
328 wp_cache_set($cache_key_total, $total_prompts, 'mxchat_prompts', 3600); // Cache for 1 hour
329 }
330
331 $total_pages = ceil($total_prompts / $per_page);
332 $offset = ($current_page - 1) * $per_page;
333
334 // Retrieve prompts from cache or database
335 $prompts = wp_cache_get($cache_key_prompts, 'mxchat_prompts');
336 if ($prompts === false) {
337 if (!empty($search_query)) {
338 $prompts = $wpdb->get_results(
339 $wpdb->prepare(
340 "SELECT * FROM {$table_name} WHERE article_content LIKE %s ORDER BY timestamp DESC LIMIT %d OFFSET %d",
341 '%' . $wpdb->esc_like($search_query) . '%',
342 $per_page,
343 $offset
344 )
345 );
346 } else {
347 $prompts = $wpdb->get_results(
348 $wpdb->prepare(
349 "SELECT * FROM {$table_name} ORDER BY timestamp DESC LIMIT %d OFFSET %d",
350 $per_page,
351 $offset
352 )
353 );
354 }
355 wp_cache_set($cache_key_prompts, $prompts, 'mxchat_prompts', 3600); // Cache for 1 hour
356 }
357
358 ?>
359
360 <div class="wrap mxchat-admin">
361 <div class="mxchat-grid-container">
362
363 <!-- Submit Content -->
364 <div class="mxchat-grid-item full-width">
365 <h2>Submit Content</h2>
366 <form method="post" action="<?php echo esc_url(admin_url('admin-post.php?action=mxchat_submit_content')); ?>">
367 <?php wp_nonce_field('mxchat_submit_content_action', 'mxchat_submit_content_nonce'); ?>
368 <div class="mxchat-form-group">
369 <label for="article_content">Article Content:</label>
370 <textarea name="article_content" id="article_content" required></textarea>
371 <input type="submit" name="submit_content" value="Submit Content" class="button button-primary submit-content-button" />
372 </div>
373 </form>
374 </div>
375
376 <!-- Submit Sitemap -->
377 <div class="mxchat-grid-item">
378 <h2>Submit Sitemap</h2>
379 <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')); ?>">
380 <?php wp_nonce_field('mxchat_submit_sitemap_action', 'mxchat_submit_sitemap_nonce'); ?>
381 <div class="mxchat-search-group">
382 <input type="url" name="sitemap_url" id="sitemap_url" placeholder="Sitemap URL" required />
383 <input type="submit" name="submit_sitemap" value="Submit Sitemap" class="button button-primary" />
384 </div>
385 </form>
386 <div id="mxchat-sitemap-loading" class="mxchat-spinner" style="display: none;"></div>
387 <div id="mxchat-loading-text" style="display: none; margin-top: 10px; color: #333;">Loading sitemap content into database, please wait...</div>
388 </div>
389
390 <!-- Search Knowledge -->
391 <div class="mxchat-grid-item">
392 <h2>Search Knowledge</h2>
393 <form method="get" id="knowledge-search">
394 <?php wp_nonce_field('mxchat_prompts_search_nonce'); ?>
395 <input type="hidden" name="page" value="mxchat-prompts" />
396 <div class="mxchat-search-group">
397 <input type="text" name="search" placeholder="Search Knowledge" value="<?php echo esc_attr($search_query); ?>" />
398 <input type="submit" value="Search" class="button button-primary" />
399 </div>
400 </form>
401 </div>
402 </div>
403
404 <!-- Table below the forms -->
405 <div class="tablenav">
406 <div class="tablenav-pages">
407 <span class="displaying-num"><?php echo esc_html($total_prompts); ?> items</span>
408 <?php
409 $page_links = paginate_links(array(
410 'base' => add_query_arg('paged', '%#%', admin_url('admin.php?page=mxchat-prompts')),
411 'format' => '',
412 'prev_text' => __('&laquo; Previous'),
413 'next_text' => __('Next &raquo;'),
414 'total' => $total_pages,
415 'current' => $current_page,
416 'add_args' => array(
417 'search' => $search_query,
418 '_wpnonce' => wp_create_nonce('mxchat_prompts_search_nonce')
419 ),
420 ));
421
422 if ($page_links) {
423 echo '<div class="tablenav-pages">' . wp_kses_post($page_links) . '</div>';
424 }
425 ?>
426 </div>
427 </div>
428 <table class="wp-list-table widefat fixed striped">
429 <thead>
430 <tr>
431 <th>ID</th>
432 <th>Article Content</th>
433 <th>URL</th>
434 <th>Actions</th>
435 </tr>
436 </thead>
437 <tbody>
438 <?php
439 if ($prompts) {
440 foreach ($prompts as $prompt) {
441 ?>
442 <tr>
443 <td><?php echo esc_html($prompt->id); ?></td>
444 <td class="mxchat_article_content_dashboard"><?php echo wp_kses_post(wpautop(esc_textarea($prompt->article_content))); ?></td>
445 <td class="mxchat_article_url_dashboard">
446 <?php if (!empty($prompt->source_url)): ?>
447 <a href="<?php echo esc_url($prompt->source_url); ?>" target="_blank"><?php echo esc_html($prompt->source_url); ?></a>
448 <?php else: ?>
449 N/A
450 <?php endif; ?>
451 </td>
452 <td>
453 <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>
454 </td>
455 </tr>
456 <?php
457 }
458 } else {
459 ?>
460 <tr>
461 <td colspan="4">No prompts found.</td>
462 </tr>
463 <?php
464 }
465 ?>
466 </tbody>
467 </table>
468 </div>
469
470 <?php
471 }
472
473 public function mxchat_generate_embedding($text) {
474 $options = get_option('mxchat_options');
475 $api_key = $options['api_key'] ?? 'default_api_key';
476
477 $response = wp_remote_post('https://api.openai.com/v1/embeddings', array(
478 'body' => wp_json_encode(array(
479 'model' => 'text-embedding-ada-002',
480 'input' => $text
481 )),
482 'headers' => array(
483 'Authorization' => 'Bearer ' . $api_key,
484 'Content-Type' => 'application/json'
485 ),
486 ));
487
488 if (is_wp_error($response)) {
489 return null;
490 }
491
492 $response_data = json_decode(wp_remote_retrieve_body($response), true);
493 return $response_data['data'][0]['embedding'] ?? null;
494 }
495
496 public function mxchat_delete_chat_history() {
497 if (!current_user_can('manage_options')) {
498 echo wp_json_encode(['error' => 'You do not have sufficient permissions.']);
499 wp_die();
500 }
501
502 check_ajax_referer('mxchat_delete_chat_history', 'security');
503
504 global $wpdb;
505 $table_name = $wpdb->prefix . 'mxchat_chat_transcripts';
506
507 if (isset($_POST['delete_session_ids']) && is_array($_POST['delete_session_ids'])) {
508 foreach ($_POST['delete_session_ids'] as $session_id) {
509 $session_id_sanitized = sanitize_text_field($session_id);
510
511 // Clear relevant cache before deletion
512 $cache_key = 'chat_session_' . $session_id_sanitized;
513 wp_cache_delete($cache_key, 'mxchat_chat_sessions');
514
515 // Perform the deletion
516 $wpdb->delete($table_name, ['session_id' => $session_id_sanitized]);
517 }
518
519 // Optionally, clear a general cache if you have one
520 wp_cache_delete('all_chat_sessions', 'mxchat_chat_sessions');
521
522 echo wp_json_encode(['success' => 'Selected chat sessions have been deleted.']);
523 } else {
524 echo wp_json_encode(['error' => 'No chat sessions selected for deletion.']);
525 }
526
527 wp_die();
528 }
529
530
531
532 public function mxchat_fetch_chat_history() {
533 global $wpdb;
534 $table_name = $wpdb->prefix . 'mxchat_chat_transcripts';
535
536 if (!current_user_can('manage_options')) {
537 echo esc_html__('You do not have sufficient permissions to view this page.', 'mxchat');
538 wp_die();
539 }
540
541 $chat_transcripts = $wpdb->get_results($wpdb->prepare("SELECT * FROM $table_name ORDER BY timestamp ASC"));
542
543 if (empty($chat_transcripts)) {
544 echo esc_html__('No chat history available.', 'mxchat');
545 wp_die();
546 }
547
548 ob_start();
549 $current_session_id = '';
550 foreach ($chat_transcripts as $transcript) {
551 if ($current_session_id !== $transcript->session_id) {
552 if ($current_session_id !== '') {
553 echo '</div>';
554 }
555 $current_session_id = sanitize_text_field($transcript->session_id);
556 echo '<div class="chat-session">';
557 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>";
558 }
559
560 $formatted_timestamp = date_i18n('F j, Y g:i a', strtotime($transcript->timestamp));
561
562 echo '<div class="chat-message">';
563 echo '<strong>' . esc_html($transcript->role) . ' (' . esc_html($formatted_timestamp) . '):</strong> ';
564 echo wp_kses_post($transcript->message);
565 echo '</div>';
566 }
567 echo '</div>';
568 $output = ob_get_clean();
569
570 echo $output;
571 wp_die();
572 }
573
574
575 public function mxchat_create_activation_page() {
576 $license_status = get_option('mxchat_license_status', 'inactive');
577 $license_error = get_option('mxchat_license_error', '');
578
579 ?>
580 <div class="wrap mxchat-admin">
581 <h2>MxChat Pro: Activation</h2>
582 <?php if ($license_status === 'inactive' && !empty($license_error)): ?>
583 <div class="error notice">
584 <p><?php echo esc_html($license_error); ?></p>
585 </div>
586 <?php endif; ?>
587 <form id="mxchat-activation-form">
588 <table class="form-table">
589 <tr valign="top">
590 <th scope="row">Email Address</th>
591 <td>
592 <input type="email" id="mxchat_pro_email" name="mxchat_pro_email" value="<?php echo esc_attr(get_option('mxchat_pro_email')); ?>" class="regular-text" />
593 </td>
594 </tr>
595 <tr valign="top">
596 <th scope="row">Activation Key</th>
597 <td>
598 <input type="text" id="mxchat_activation_key" name="mxchat_activation_key" value="<?php echo esc_attr(get_option('mxchat_activation_key')); ?>" class="regular-text" />
599 </td>
600 </tr>
601 </table>
602 <?php submit_button('Activate License', 'primary', 'activate_license'); ?>
603 </form>
604 <h3>License Status: <span id="mxchat-license-status"><?php echo $license_status === 'active' ? 'Active' : 'Inactive'; ?></span></h3>
605 </div>
606 <?php
607 }
608
609
610 public function mxchat_page_init() {
611
612 // Register settings for activation page
613 register_setting(
614 'mxchat_activation_group',
615 'mxchat_pro_email',
616 array($this, 'mxchat_sanitize')
617 );
618 register_setting(
619 'mxchat_activation_group',
620 'mxchat_activation_key',
621 array($this, 'mxchat_sanitize')
622 );
623
624 register_setting(
625 'mxchat_option_group',
626 'mxchat_options',
627 array($this, 'mxchat_sanitize')
628 );
629
630 add_settings_section(
631 'mxchat_setting_section_id',
632 'Settings',
633 null,
634 'mxchat-max'
635 );
636
637 // Add fields with corresponding callbacks
638 $this->mxchat_add_option_field('api_key', 'API Key');
639 $this->mxchat_add_option_field('system_prompt_instructions', 'AI Instructions');
640 $this->mxchat_add_option_field('model', 'Model', 'mxchat_model_callback');
641 $this->mxchat_add_option_field('top_bar_title', 'Top Bar Title', 'mxchat_top_bar_title_callback');
642 $this->mxchat_add_option_field('intro_message', 'Introductory Message', 'mxchat_intro_message_callback');
643
644 //pro features
645 $this->mxchat_add_option_field('rate_limit', 'Rate Limit', 'mxchat_rate_limit_callback');
646 $this->mxchat_add_option_field('rate_limit_message', 'Rate Limit Message', 'mxchat_rate_limit_message_callback');
647
648 //new pro features
649 $this->mxchat_add_option_field('close_button_color', 'Close Button & Title Color', 'mxchat_close_button_color_callback');
650 $this->mxchat_add_option_field('chatbot_bg_color', 'Chatbot Background Color', 'mxchat_chatbot_bg_color_callback');
651 $this->mxchat_add_option_field('user_message_bg_color', 'User Message Background Color', 'mxchat_user_message_bg_color_callback');
652 $this->mxchat_add_option_field('user_message_font_color', 'User Message Font Color', 'mxchat_user_message_font_color_callback');
653 $this->mxchat_add_option_field('bot_message_bg_color', 'Bot Message Background Color', 'mxchat_bot_message_bg_color_callback');
654 $this->mxchat_add_option_field('bot_message_font_color', 'Bot Message Font Color', 'mxchat_bot_message_font_color_callback');
655 $this->mxchat_add_option_field('top_bar_bg_color', 'Top Bar Background Color', 'mxchat_top_bar_bg_color_callback');
656 $this->mxchat_add_option_field('send_button_font_color', 'Send Button Color', 'mxchat_send_button_font_color_callback');
657 $this->mxchat_add_option_field('chat_input_font_color', 'Chat Input Font Color', 'mxchat_chat_input_font_color_callback');
658 $this->mxchat_add_option_field('chatbot_background_color', 'Floating Widget Background Color', 'mxchat_chatbot_background_color_callback');
659 $this->mxchat_add_option_field('icon_color', 'Chatbot Icon Color', 'mxchat_icon_color_callback');
660 $this->mxchat_add_option_field('pre_chat_message', 'Pre-Chat Message', 'mxchat_pre_chat_message_callback');
661
662
663 }
664
665 public function mxchat_handle_activate_license() {
666 check_ajax_referer('mxchat_activate_license_nonce', 'security');
667
668 $license_key = isset($_POST['key']) ? sanitize_text_field($_POST['key']) : '';
669 $customer_email = isset($_POST['email']) ? sanitize_email($_POST['email']) : '';
670
671 if (empty($license_key) || empty($customer_email)) {
672 wp_send_json_error('Email or License Key is missing');
673 }
674
675 $product_id = 'MxChatPRO';
676
677 $response = wp_remote_get("http://mxchat.ai/?wc-api=software-api&request=activation&email={$customer_email}&license_key={$license_key}&product_id={$product_id}");
678
679 if (is_wp_error($response)) {
680 wp_send_json_error('Activation failed due to a server error');
681 }
682
683 $body = wp_remote_retrieve_body($response);
684 $data = json_decode($body);
685
686 if ($data && isset($data->activated) && $data->activated) {
687 update_option('mxchat_license_status', 'active');
688 wp_send_json_success();
689 } else {
690 $error_message = isset($data->error) ? $data->error : 'Activation failed';
691 update_option('mxchat_license_status', 'inactive');
692 update_option('mxchat_license_error', $error_message);
693 wp_send_json_error($error_message);
694 }
695 }
696
697
698 public function mxchat_rate_limit_callback() {
699 $rate_limits = array('5', '10', '15', '20', '100');
700 $selected_rate_limit = isset($this->options['rate_limit']) ? $this->options['rate_limit'] : '100';
701
702 $disabled = $this->is_activated ? '' : 'disabled';
703 $class = $this->is_activated ? 'pro-feature-wrapper active' : 'pro-feature-wrapper inactive';
704
705 echo '<div class="' . esc_attr($class) . '">';
706 echo '<select id="rate_limit" name="mxchat_options[rate_limit]" ' . $disabled . '>';
707 foreach ($rate_limits as $limit) {
708 echo '<option value="' . esc_attr($limit) . '" ' . selected($selected_rate_limit, $limit, false) . '>' . esc_html($limit) . '</option>';
709 }
710 echo '</select>';
711
712 if (!$this->is_activated) {
713 echo '<div class="pro-feature-overlay">';
714 echo '<a href="https://mxchat.ai/" target="_blank"><img src="' . plugin_dir_url(__FILE__) . '../images/pro-only-dark.png" alt="Pro Only" /></a>';
715 echo '</div>';
716 }
717
718 echo '</div>';
719 }
720
721 public function mxchat_rate_limit_message_callback() {
722 $disabled = $this->is_activated ? '' : 'disabled';
723 $class = $this->is_activated ? 'pro-feature-wrapper active' : 'pro-feature-wrapper inactive';
724
725 echo '<div class="' . esc_attr($class) . '">';
726 printf(
727 '<textarea id="rate_limit_message" name="mxchat_options[rate_limit_message]" rows="3" cols="50" %s>%s</textarea>',
728 esc_attr($disabled),
729 isset($this->options['rate_limit_message']) ? esc_textarea($this->options['rate_limit_message']) : 'Rate limit exceeded. Please try again later.'
730 );
731
732 if (!$this->is_activated) {
733 echo '<div class="pro-feature-overlay">';
734 echo '<a href="https://mxchat.ai/" target="_blank"><img src="' . plugin_dir_url(__FILE__) . '../images/pro-only-dark.png" alt="Pro Only" /></a>';
735 echo '</div>';
736 }
737
738 echo '</div>';
739 }
740
741
742
743 private function mxchat_add_option_field($id, $title, $callback = '') {
744 add_settings_field(
745 $id,
746 $title,
747 $callback ? array($this, $callback) : array($this, $id . '_callback'),
748 'mxchat-max',
749 'mxchat_setting_section_id',
750 $id === 'model' ? ['label_for' => 'model'] : []
751 );
752 }
753
754 // Callback for API Key input
755 public function api_key_callback() {
756 printf(
757 '<input type="text" id="api_key" name="mxchat_options[api_key]" value="%s" class="regular-text" />',
758 isset($this->options['api_key']) ? esc_attr($this->options['api_key']) : ''
759 );
760 }
761
762 public function mxchat_pre_chat_message_callback() {
763 printf(
764 '<textarea id="pre_chat_message" name="mxchat_options[pre_chat_message]" rows="5" cols="50">%s</textarea>',
765 isset($this->options['pre_chat_message']) ? esc_textarea($this->options['pre_chat_message']) : ''
766 );
767 }
768
769 // Callback for AI Instructions textarea
770 public function system_prompt_instructions_callback() {
771 printf(
772 '<textarea id="system_prompt_instructions" name="mxchat_options[system_prompt_instructions]" rows="5" cols="50">%s</textarea>',
773 isset($this->options['system_prompt_instructions']) ? esc_textarea($this->options['system_prompt_instructions']) : ''
774 );
775 }
776
777 public function mxchat_model_callback() {
778 $models = array(
779 'gpt-4o' => 'gpt-4o',
780 'gpt-4' => 'gpt-4',
781 'gpt-4-32k' => 'gpt-4-32k',
782 'gpt-4-vision-preview' => 'gpt-4-vision-preview',
783 'gpt-4-1106-preview' => 'gpt-4-1106-preview',
784 'gpt-3.5-turbo-1106' => 'gpt-3.5-turbo-1106',
785 'gpt-3.5-turbo' => 'gpt-3.5-turbo',
786 'gpt-3.5-turbo-16k' => 'gpt-3.5-turbo-16k',
787 );
788
789 $selected_model = isset($this->options['model']) ? $this->options['model'] : 'gpt-3.5-turbo';
790
791 echo '<select id="model" name="mxchat_options[model]">';
792 foreach ($models as $model_value => $model_label) {
793 echo '<option value="' . esc_attr($model_value) . '" ' . selected($selected_model, $model_value, false) . '>' . esc_html($model_label) . '</option>';
794 }
795 echo '</select>';
796 }
797
798 public function mxchat_top_bar_title_callback() {
799 printf(
800 '<input type="text" id="top_bar_title" name="mxchat_options[top_bar_title]" value="%s" />',
801 isset($this->options['top_bar_title']) ? esc_attr($this->options['top_bar_title']) : ''
802 );
803 }
804
805 public function mxchat_intro_message_callback() {
806 printf(
807 '<textarea id="intro_message" name="mxchat_options[intro_message]" rows="5" cols="50">%s</textarea>',
808 isset($this->options['intro_message']) ? esc_textarea($this->options['intro_message']) : 'Hello! How can I assist you today?'
809 );
810 }
811
812
813
814
815
816 public function mxchat_close_button_color_callback() {
817 $disabled = $this->is_activated ? '' : 'disabled';
818
819 echo '<div class="pro-feature-wrapper">';
820 printf(
821 '<input type="text" id="close_button_color" name="mxchat_options[close_button_color]" value="%s" class="my-color-field" data-default-color="#4a4a4a" %s />',
822 isset($this->options['close_button_color']) ? esc_attr($this->options['close_button_color']) : '',
823 esc_attr($disabled)
824 );
825
826 if (!$this->is_activated) {
827 echo '<div class="pro-feature-overlay">';
828 echo '<a href="https://mxchat.ai/" target="_blank"><img src="' . plugin_dir_url(__FILE__) . '../images/pro-only-dark.png" alt="Pro Only" /></a>';
829 echo '</div>';
830 }
831
832 echo '</div>';
833 }
834
835 public function mxchat_chatbot_bg_color_callback() {
836 $disabled = $this->is_activated ? '' : 'disabled';
837
838 echo '<div class="pro-feature-wrapper">';
839 printf(
840 '<input type="text" id="chatbot_bg_color" name="mxchat_options[chatbot_bg_color]" value="%s" class="my-color-field" data-default-color="#f9f9f9" %s />',
841 isset($this->options['chatbot_bg_color']) ? esc_attr($this->options['chatbot_bg_color']) : '',
842 esc_attr($disabled)
843 );
844
845 if (!$this->is_activated) {
846 echo '<div class="pro-feature-overlay">';
847 echo '<a href="https://mxchat.ai/" target="_blank"><img src="' . plugin_dir_url(__FILE__) . '../images/pro-only-dark.png" alt="Pro Only" /></a>';
848 echo '</div>';
849 }
850
851 echo '</div>';
852 }
853
854 public function mxchat_user_message_bg_color_callback() {
855 $disabled = $this->is_activated ? '' : 'disabled';
856
857 echo '<div class="pro-feature-wrapper">';
858 printf(
859 '<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 />',
860 isset($this->options['user_message_bg_color']) ? esc_attr($this->options['user_message_bg_color']) : '',
861 esc_attr($disabled)
862 );
863
864 if (!$this->is_activated) {
865 echo '<div class="pro-feature-overlay">';
866 echo '<a href="https://mxchat.ai/" target="_blank"><img src="' . plugin_dir_url(__FILE__) . '../images/pro-only-dark.png" alt="Pro Only" /></a>';
867 echo '</div>';
868 }
869
870 echo '</div>';
871 }
872
873 public function mxchat_user_message_font_color_callback() {
874 $disabled = $this->is_activated ? '' : 'disabled';
875
876 echo '<div class="pro-feature-wrapper">';
877 printf(
878 '<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 />',
879 isset($this->options['user_message_font_color']) ? esc_attr($this->options['user_message_font_color']) : '',
880 esc_attr($disabled)
881 );
882
883 if (!$this->is_activated) {
884 echo '<div class="pro-feature-overlay">';
885 echo '<a href="https://mxchat.ai/" target="_blank"><img src="' . plugin_dir_url(__FILE__) . '../images/pro-only-dark.png" alt="Pro Only" /></a>';
886 echo '</div>';
887 }
888
889 echo '</div>';
890 }
891
892 public function mxchat_bot_message_bg_color_callback() {
893 $disabled = $this->is_activated ? '' : 'disabled';
894
895 echo '<div class="pro-feature-wrapper">';
896 printf(
897 '<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 />',
898 isset($this->options['bot_message_bg_color']) ? esc_attr($this->options['bot_message_bg_color']) : '',
899 esc_attr($disabled)
900 );
901
902 if (!$this->is_activated) {
903 echo '<div class="pro-feature-overlay">';
904 echo '<a href="https://mxchat.ai/" target="_blank"><img src="' . plugin_dir_url(__FILE__) . '../images/pro-only-dark.png" alt="Pro Only" /></a>';
905 echo '</div>';
906 }
907
908 echo '</div>';
909 }
910
911 public function mxchat_bot_message_font_color_callback() {
912 $disabled = $this->is_activated ? '' : 'disabled';
913
914 echo '<div class="pro-feature-wrapper">';
915 printf(
916 '<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 />',
917 isset($this->options['bot_message_font_color']) ? esc_attr($this->options['bot_message_font_color']) : '',
918 esc_attr($disabled)
919 );
920
921 if (!$this->is_activated) {
922 echo '<div class="pro-feature-overlay">';
923 echo '<a href="https://mxchat.ai/" target="_blank"><img src="' . plugin_dir_url(__FILE__) . '../images/pro-only-dark.png" alt="Pro Only" /></a>';
924 echo '</div>';
925 }
926
927 echo '</div>';
928 }
929
930 public function mxchat_top_bar_bg_color_callback() {
931 $disabled = $this->is_activated ? '' : 'disabled';
932
933 echo '<div class="pro-feature-wrapper">';
934 printf(
935 '<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 />',
936 isset($this->options['top_bar_bg_color']) ? esc_attr($this->options['top_bar_bg_color']) : '',
937 esc_attr($disabled)
938 );
939
940 if (!$this->is_activated) {
941 echo '<div class="pro-feature-overlay">';
942 echo '<a href="https://mxchat.ai/" target="_blank"><img src="' . plugin_dir_url(__FILE__) . '../images/pro-only-dark.png" alt="Pro Only" /></a>';
943 echo '</div>';
944 }
945
946 echo '</div>';
947 }
948
949 public function mxchat_send_button_font_color_callback() {
950 $disabled = $this->is_activated ? '' : 'disabled';
951
952 echo '<div class="pro-feature-wrapper">';
953 printf(
954 '<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 />',
955 isset($this->options['send_button_font_color']) ? esc_attr($this->options['send_button_font_color']) : '',
956 esc_attr($disabled)
957 );
958
959 if (!$this->is_activated) {
960 echo '<div class="pro-feature-overlay">';
961 echo '<a href="https://mxchat.ai/" target="_blank"><img src="' . plugin_dir_url(__FILE__) . '../images/pro-only-dark.png" alt="Pro Only" /></a>';
962 echo '</div>';
963 }
964
965 echo '</div>';
966 }
967
968 public function mxchat_chatbot_background_color_callback() {
969 $disabled = $this->is_activated ? '' : 'disabled';
970
971 echo '<div class="pro-feature-wrapper">';
972 printf(
973 '<input type="text" id="chatbot_background_color" name="mxchat_options[chatbot_background_color]" value="%s" class="my-color-field" data-default-color="#000000" %s />',
974 isset($this->options['chatbot_background_color']) ? esc_attr($this->options['chatbot_background_color']) : '',
975 esc_attr($disabled)
976 );
977
978 if (!$this->is_activated) {
979 echo '<div class="pro-feature-overlay">';
980 echo '<a href="https://mxchat.ai/" target="_blank"><img src="' . plugin_dir_url(__FILE__) . '../images/pro-only-dark.png" alt="Pro Only" /></a>';
981 echo '</div>';
982 }
983
984 echo '</div>';
985 }
986
987 public function mxchat_icon_color_callback() {
988 $disabled = $this->is_activated ? '' : 'disabled';
989
990 echo '<div class="pro-feature-wrapper">';
991 printf(
992 '<input type="text" id="icon_color" name="mxchat_options[icon_color]" value="%s" class="my-color-field" data-default-color="#ffffff" %s />',
993 isset($this->options['icon_color']) ? esc_attr($this->options['icon_color']) : '',
994 esc_attr($disabled)
995 );
996
997 if (!$this->is_activated) {
998 echo '<div class="pro-feature-overlay">';
999 echo '<a href="https://mxchat.ai/" target="_blank"><img src="' . plugin_dir_url(__FILE__) . '../images/pro-only-dark.png" alt="Pro Only" /></a>';
1000 echo '</div>';
1001 }
1002
1003 echo '</div>';
1004 }
1005
1006 public function mxchat_chat_input_font_color_callback() {
1007 $disabled = $this->is_activated ? '' : 'disabled';
1008
1009 echo '<div class="pro-feature-wrapper">';
1010 printf(
1011 '<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 />',
1012 isset($this->options['chat_input_font_color']) ? esc_attr($this->options['chat_input_font_color']) : '',
1013 esc_attr($disabled)
1014 );
1015
1016 if (!$this->is_activated) {
1017 echo '<div class="pro-feature-overlay">';
1018 echo '<a href="https://mxchat.ai/" target="_blank"><img src="' . plugin_dir_url(__FILE__) . '../images/pro-only-dark.png" alt="Pro Only" /></a>';
1019 echo '</div>';
1020 }
1021
1022 echo '</div>';
1023 }
1024
1025
1026 public function mxchat_append_to_body_callback() {
1027 $append_to_body_checked = isset($this->options['append_to_body']) && $this->options['append_to_body'] === 'on' ? 'checked' : '';
1028 printf(
1029 '<input type="checkbox" id="append_to_body" name="mxchat_options[append_to_body]" %s />',
1030 esc_attr($append_to_body_checked)
1031 );
1032 echo '<p class="description">Enable to append the chat widget directly to the body element.</p>';
1033 }
1034
1035
1036
1037
1038 public function mxchat_enqueue_admin_assets() {
1039 wp_enqueue_style('wp-color-picker');
1040
1041 // Get the plugin version or file modification time for cache busting
1042 $plugin_version = '1.0.5'; // Replace this with your plugin's version
1043
1044 // File paths
1045 $color_picker_js_path = plugin_dir_path(__FILE__) . '../js/my-color-picker.js';
1046 $embedding_check_js_path = plugin_dir_path(__FILE__) . '../js/embedding-check.js';
1047 $admin_css_path = plugin_dir_path(__FILE__) . '../css/admin-style.css';
1048 $transcripts_js_path = plugin_dir_path(__FILE__) . '../js/mxchat_transcripts.js';
1049
1050 // Check if files exist and get modification times
1051 $color_picker_version = file_exists($color_picker_js_path) ? filemtime($color_picker_js_path) : $plugin_version;
1052 $embedding_check_version = file_exists($embedding_check_js_path) ? filemtime($embedding_check_js_path) : $plugin_version;
1053 $admin_css_version = file_exists($admin_css_path) ? filemtime($admin_css_path) : $plugin_version;
1054 $transcripts_js_version = file_exists($transcripts_js_path) ? filemtime($transcripts_js_path) : $plugin_version;
1055
1056 // Enqueue scripts and styles with corrected paths
1057 wp_enqueue_script(
1058 'mxchat-color-picker',
1059 plugin_dir_url(__FILE__) . '../js/my-color-picker.js',
1060 array('wp-color-picker'),
1061 $color_picker_version,
1062 true
1063 );
1064
1065 wp_enqueue_script(
1066 'mxchat-embedding-check',
1067 plugin_dir_url(__FILE__) . '../js/embedding-check.js',
1068 array(),
1069 $embedding_check_version,
1070 true
1071 );
1072
1073 wp_enqueue_script(
1074 'mxchat-transcripts-js',
1075 plugin_dir_url(__FILE__) . '../js/mxchat_transcripts.js',
1076 array('jquery'),
1077 $transcripts_js_version,
1078 true
1079 );
1080
1081 wp_enqueue_script(
1082 'mxchat-admin-js',
1083 plugin_dir_url(__FILE__) . '../js/mxchat-admin.js',
1084 array('jquery'),
1085 $plugin_version,
1086 true
1087 );
1088
1089 wp_localize_script('mxchat-admin-js', 'mxchatAdmin', array(
1090 'ajax_url' => admin_url('admin-ajax.php'),
1091 'nonce' => wp_create_nonce('mxchat_activate_license_nonce'),
1092 ));
1093
1094 wp_enqueue_style(
1095 'mxchat-admin-css',
1096 plugin_dir_url(__FILE__) . '../css/admin-style.css',
1097 array(),
1098 $admin_css_version
1099 );
1100
1101 // Use wp_json_encode for localizing script
1102 wp_localize_script('mxchat-color-picker', 'mxchatStyleSettings', array(
1103 'ajax_url' => admin_url('admin-ajax.php'),
1104 'user_message_bg_color' => $this->options['user_message_bg_color'] ?? '#fff',
1105 'user_message_font_color' => $this->options['user_message_font_color'] ?? '#212121',
1106 'bot_message_bg_color' => $this->options['bot_message_bg_color'] ?? '#212121',
1107 'bot_message_font_color' => $this->options['bot_message_font_color'] ?? '#fff',
1108 'top_bar_bg_color' => $this->options['top_bar_bg_color'] ?? '#212121',
1109 'send_button_font_color' => $this->options['send_button_font_color'] ?? '#212121',
1110 'close_button_color' => $this->options['close_button_color'] ?? '#fff',
1111 'chatbot_background_color' => $this->options['chatbot_background_color'] ?? '#212121',
1112 'icon_color' => $this->options['icon_color'] ?? '#fff',
1113 'chat_input_font_color' => $this->options['chat_input_font_color'] ?? '#212121'
1114 ));
1115 }
1116
1117 public function mxchat_sanitize($input) {
1118 $new_input = array();
1119
1120 if (isset($input['api_key'])) {
1121 $new_input['api_key'] = sanitize_text_field($input['api_key']);
1122 }
1123
1124 if (isset($input['system_prompt_instructions'])) {
1125 $new_input['system_prompt_instructions'] = sanitize_textarea_field($input['system_prompt_instructions']);
1126 }
1127
1128 if (isset($input['mxchat_pro_email'])) {
1129 $new_input['mxchat_pro_email'] = sanitize_email($input['mxchat_pro_email']);
1130 }
1131
1132 if (isset($input['mxchat_activation_key'])) {
1133 $new_input['mxchat_activation_key'] = sanitize_text_field($input['mxchat_activation_key']);
1134 }
1135
1136 if (isset($input['append_to_body'])) {
1137 $new_input['append_to_body'] = $input['append_to_body'] === 'on' ? 'on' : 'off';
1138 }
1139
1140 if (isset($input['top_bar_title'])) {
1141 $new_input['top_bar_title'] = sanitize_text_field($input['top_bar_title']);
1142 }
1143
1144 if (isset($input['intro_message'])) {
1145 $new_input['intro_message'] = sanitize_text_field($input['intro_message']);
1146 }
1147
1148 if (isset($input['rate_limit_message'])) {
1149 $new_input['rate_limit_message'] = sanitize_text_field($input['rate_limit_message']);
1150 }
1151
1152
1153 if (isset($input['pre_chat_message'])) {
1154 $new_input['pre_chat_message'] = sanitize_textarea_field($input['pre_chat_message']);
1155 }
1156
1157 if (isset($input['model'])) {
1158 $allowed_models = array(
1159 'gpt-4o',
1160 'gpt-4',
1161 'gpt-4-32k',
1162 'gpt-4-vision-preview',
1163 'gpt-4-1106-preview',
1164 'gpt-3.5-turbo-1106',
1165 'gpt-3.5-turbo',
1166 'gpt-3.5-turbo-16k',
1167 );
1168 if (in_array($input['model'], $allowed_models)) {
1169 $new_input['model'] = sanitize_text_field($input['model']);
1170 }
1171 }
1172
1173 // Sanitize new pro features
1174 if (isset($input['close_button_color'])) {
1175 $new_input['close_button_color'] = sanitize_hex_color($input['close_button_color']);
1176 }
1177
1178 if (isset($input['chatbot_bg_color'])) {
1179 $new_input['chatbot_bg_color'] = sanitize_hex_color($input['chatbot_bg_color']);
1180 }
1181
1182 if (isset($input['user_message_bg_color'])) {
1183 $new_input['user_message_bg_color'] = sanitize_hex_color($input['user_message_bg_color']);
1184 }
1185
1186 if (isset($input['user_message_font_color'])) {
1187 $new_input['user_message_font_color'] = sanitize_hex_color($input['user_message_font_color']);
1188 }
1189
1190 if (isset($input['bot_message_bg_color'])) {
1191 $new_input['bot_message_bg_color'] = sanitize_hex_color($input['bot_message_bg_color']);
1192 }
1193
1194 if (isset($input['bot_message_font_color'])) {
1195 $new_input['bot_message_font_color'] = sanitize_hex_color($input['bot_message_font_color']);
1196 }
1197
1198 if (isset($input['top_bar_bg_color'])) {
1199 $new_input['top_bar_bg_color'] = sanitize_hex_color($input['top_bar_bg_color']);
1200 }
1201
1202 if (isset($input['send_button_font_color'])) {
1203 $new_input['send_button_font_color'] = sanitize_hex_color($input['send_button_font_color']);
1204 }
1205
1206 if (isset($input['chatbot_background_color'])) {
1207 $new_input['chatbot_background_color'] = sanitize_hex_color($input['chatbot_background_color']);
1208 }
1209
1210 if (isset($input['icon_color'])) {
1211 $new_input['icon_color'] = sanitize_hex_color($input['icon_color']);
1212 }
1213
1214 if (isset($input['chat_input_font_color'])) {
1215 $new_input['chat_input_font_color'] = sanitize_hex_color($input['chat_input_font_color']);
1216 }
1217
1218 return $new_input;
1219 }
1220
1221
1222 // Method to append the chatbot to the body
1223 public function mxchat_append_chatbot_to_body() {
1224 $options = get_option('mxchat_options');
1225 if (isset($options['append_to_body']) && $options['append_to_body'] === 'on') {
1226 echo do_shortcode('[mxchat_chatbot floating="yes"]');
1227 }
1228 }
1229
1230
1231
1232 private function mxchat_extract_main_content($html) {
1233 $dom = new DOMDocument;
1234 libxml_use_internal_errors(true); // Suppress HTML parsing errors
1235 @$dom->loadHTML($html);
1236 libxml_clear_errors();
1237
1238 $xpath = new DOMXPath($dom);
1239
1240 // Simplified selectors focusing on common content areas
1241 $selectors = [
1242 '//article',
1243 '//*[@id="content"]',
1244 '//*[@class="entry-content"]',
1245 '//main',
1246 ];
1247
1248 foreach ($selectors as $selector) {
1249 $nodes = $xpath->query($selector);
1250 if ($nodes->length > 0) {
1251 $content = '';
1252 foreach ($nodes as $node) {
1253 $content .= $dom->saveHTML($node);
1254 }
1255 return $content;
1256 }
1257 }
1258
1259 // Fallback: Return the entire body content if no specific selector matches
1260 $body = $dom->getElementsByTagName('body');
1261 return $body->length > 0 ? $dom->saveHTML($body->item(0)) : $html;
1262 }
1263
1264 public function mxchat_handle_sitemap_submission() {
1265 if (!isset($_POST['submit_sitemap']) || !current_user_can('manage_options')) {
1266 return;
1267 }
1268
1269 check_admin_referer('mxchat_submit_sitemap_action', 'mxchat_submit_sitemap_nonce');
1270
1271 $sitemap_url = esc_url_raw($_POST['sitemap_url']);
1272
1273 $response = wp_remote_get($sitemap_url);
1274 if (is_wp_error($response) || wp_remote_retrieve_response_code($response) !== 200) {
1275 wp_die('Failed to fetch the sitemap. Please check the URL and try again.');
1276 }
1277
1278 $sitemap_content = wp_remote_retrieve_body($response);
1279
1280 $xml = simplexml_load_string($sitemap_content);
1281 if ($xml === false) {
1282 wp_die('Invalid sitemap XML.');
1283 }
1284
1285 foreach ($xml->url as $url_element) {
1286 $page_url = (string)$url_element->loc;
1287
1288 $page_response = wp_remote_get($page_url);
1289 if (is_wp_error($page_response) || wp_remote_retrieve_response_code($page_response) !== 200) {
1290 continue;
1291 }
1292
1293 $page_html = wp_remote_retrieve_body($page_response);
1294 $page_content = $this->mxchat_extract_main_content($page_html);
1295
1296 // Sanitize the extracted content
1297 $sanitized_content = $this->mxchat_sanitize_content_for_api($page_content);
1298
1299 if (!empty($sanitized_content)) {
1300 $this->mxchat_submit_content_to_db($sanitized_content, $page_url);
1301 }
1302 }
1303
1304 wp_redirect(esc_url(admin_url('admin.php?page=mxchat-prompts&sitemap_submitted=true')));
1305 exit;
1306 }
1307
1308 private function mxchat_sanitize_content_for_api($content) {
1309 // Remove script, style tags, and HTML comments
1310 $content = preg_replace('/<script\b[^>]*>(.*?)<\/script>/is', '', $content);
1311 $content = preg_replace('/<style\b[^>]*>(.*?)<\/style>/is', '', $content);
1312 $content = preg_replace('/<!--(.|\s)*?-->/', '', $content);
1313
1314 // Remove all HTML tags and decode HTML entities
1315 $content = wp_strip_all_tags($content);
1316 $content = html_entity_decode($content, ENT_QUOTES | ENT_HTML5);
1317
1318 // Trim and normalize whitespace
1319 $content = trim(preg_replace('/\s+/', ' ', $content));
1320
1321 return $content;
1322 }
1323
1324
1325
1326 private function mxchat_submit_content_to_db($content, $source_url) {
1327 global $wpdb;
1328 $table_name = $wpdb->prefix . 'mxchat_system_prompt_content';
1329
1330 $embedding_vector = $this->mxchat_generate_embedding($content);
1331
1332 if (is_array($embedding_vector)) {
1333 $embedding_vector_serialized = serialize($embedding_vector);
1334
1335 $wpdb->insert(
1336 $table_name,
1337 array(
1338 'article_content' => $content,
1339 'embedding_vector' => $embedding_vector_serialized,
1340 'source_url' => $source_url,
1341 ),
1342 array(
1343 '%s',
1344 '%s',
1345 '%s',
1346 )
1347 );
1348 } else {
1349 error_log('Embedding generation failed for content from ' . $source_url);
1350 }
1351 }
1352 }
1353 ?>
1354