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

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

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