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

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

1,629 lines 66.3 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 <div class="mxchat-pro-banner">
260 <p>
261 Want even more features such as a fully customizable theme, WooCommerce integration, dedicated support, and much more?
262 <a href="https://mxchat.ai/" target="_blank">Upgrade to MxChat Pro today and get a special launch lifetime license for only $49.97!</a>
263 </p>
264 </div>
265 <h2 class="admin-title">Mx<span class="admin-emphasis">Chat</span></h2>
266 <h2 class="nav-tab-wrapper">
267 <a href="#chatbot" class="nav-tab nav-tab-active" data-tab="chatbot">Chatbot</a>
268 <a href="#embed" class="nav-tab" data-tab="embed">Embed</a>
269 <a href="#theme" class="nav-tab" data-tab="theme">Theme</a>
270 <a href="#general" class="nav-tab" data-tab="general">General</a>
271 </h2>
272 <form method="post" action="options.php">
273 <?php
274 settings_fields('mxchat_option_group');
275 ?>
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
288 <div class="mxchat-general-notes">
289 <h3>Important Notes</h3>
290 <p>
291 You can add the chatbot to your site using the <code>[mxchat_chatbot floating="yes"]</code> or <code>[mxchat_chatbot floating="no"]</code> shortcode. Additionally, you can automatically append the chatbot to your site’s body element from the settings page.
292 </p>
293 <p>
294 Please note that you must have an OpenAI API key to use the chatbot. You can obtain an API key from the <a href="https://platform.openai.com/signup" target="_blank">OpenAI website</a>. It's easy to sign up, and you'll need to add credits to your account before using the chatbot. Generally, as little as $5 in credits is sufficient to get started.
295 </p>
296 </div>
297 </div>
298 <?php submit_button(); ?>
299 </form>
300 </div>
301 <?php
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 if (!current_user_can('manage_options')) {
571 echo esc_html__('You do not have sufficient permissions to view this page.', 'mxchat');
572 wp_die();
573 }
574
575 $chat_transcripts = $wpdb->get_results($wpdb->prepare("SELECT * FROM $table_name ORDER BY timestamp ASC"));
576
577 if (empty($chat_transcripts)) {
578 echo esc_html__('No chat history available.', 'mxchat');
579 wp_die();
580 }
581
582 ob_start();
583 $current_session_id = '';
584 foreach ($chat_transcripts as $transcript) {
585 if ($current_session_id !== $transcript->session_id) {
586 if ($current_session_id !== '') {
587 echo '</div>';
588 }
589 $current_session_id = sanitize_text_field($transcript->session_id);
590 echo '<div class="chat-session">';
591 echo "<h4><input type='checkbox' name='delete_session_ids[]' value='" . esc_attr($transcript->session_id) . "'> " . esc_html__('Session ID:', 'mxchat') . " " . esc_html($transcript->session_id) . "</h4>";
592 }
593
594 $formatted_timestamp = date_i18n('F j, Y g:i a', strtotime($transcript->timestamp));
595
596 echo '<div class="chat-message">';
597 echo '<strong>' . esc_html($transcript->role) . ' (' . esc_html($formatted_timestamp) . '):</strong> ';
598 echo wp_kses_post($transcript->message);
599 echo '</div>';
600 }
601 echo '</div>';
602 $output = ob_get_clean();
603
604 echo $output;
605 wp_die();
606 }
607
608
609 public function mxchat_create_activation_page() {
610 $license_status = get_option('mxchat_license_status', 'inactive');
611 $license_error = get_option('mxchat_license_error', '');
612
613 ?>
614 <div class="wrap mxchat-admin">
615 <h2>MxChat Pro: Activation</h2>
616 <?php if ($license_status === 'inactive' && !empty($license_error)): ?>
617 <div class="error notice">
618 <p><?php echo esc_html($license_error); ?></p>
619 </div>
620 <?php endif; ?>
621 <form id="mxchat-activation-form">
622 <table class="form-table">
623 <tr valign="top">
624 <th scope="row">Email Address</th>
625 <td>
626 <input type="email" id="mxchat_pro_email" name="mxchat_pro_email" value="<?php echo esc_attr(get_option('mxchat_pro_email')); ?>" class="regular-text" />
627 </td>
628 </tr>
629 <tr valign="top">
630 <th scope="row">Activation Key</th>
631 <td>
632 <input type="text" id="mxchat_activation_key" name="mxchat_activation_key" value="<?php echo esc_attr(get_option('mxchat_activation_key')); ?>" class="regular-text" />
633 </td>
634 </tr>
635 </table>
636 <?php submit_button('Activate License', 'primary', 'activate_license'); ?>
637 </form>
638 <h3>License Status: <span id="mxchat-license-status"><?php echo $license_status === 'active' ? 'Active' : 'Inactive'; ?></span></h3>
639 </div>
640 <?php
641 }
642
643
644 public function mxchat_page_init() {
645 // Register settings
646 register_setting(
647 'mxchat_option_group',
648 'mxchat_options',
649 array($this, 'mxchat_sanitize')
650 );
651
652 // Chatbot Settings Section
653 add_settings_section(
654 'mxchat_chatbot_section',
655 'Chatbot Settings',
656 null,
657 'mxchat-chatbot'
658 );
659
660 // Registering fields for the Chatbot Settings section
661 add_settings_field(
662 'api_key',
663 'API Key',
664 array($this, 'api_key_callback'),
665 'mxchat-chatbot',
666 'mxchat_chatbot_section'
667 );
668
669 add_settings_field(
670 'system_prompt_instructions',
671 'AI Instructions',
672 array($this, 'system_prompt_instructions_callback'),
673 'mxchat-chatbot',
674 'mxchat_chatbot_section'
675 );
676
677 add_settings_field(
678 'model',
679 'Model',
680 array($this, 'mxchat_model_callback'),
681 'mxchat-chatbot',
682 'mxchat_chatbot_section'
683 );
684
685 add_settings_field(
686 'top_bar_title',
687 'Top Bar Title',
688 array($this, 'mxchat_top_bar_title_callback'),
689 'mxchat-chatbot',
690 'mxchat_chatbot_section'
691 );
692
693 add_settings_field(
694 'intro_message',
695 'Introductory Message',
696 array($this, 'mxchat_intro_message_callback'),
697 'mxchat-chatbot',
698 'mxchat_chatbot_section'
699 );
700
701 add_settings_field(
702 'rate_limit',
703 'Rate Limit',
704 array($this, 'mxchat_rate_limit_callback'),
705 'mxchat-chatbot',
706 'mxchat_chatbot_section'
707 );
708
709 add_settings_field(
710 'rate_limit_message',
711 'Rate Limit Message',
712 array($this, 'mxchat_rate_limit_message_callback'),
713 'mxchat-chatbot',
714 'mxchat_chatbot_section'
715 );
716
717 add_settings_field(
718 'pre_chat_message',
719 'Pre-Chat Message',
720 array($this, 'mxchat_pre_chat_message_callback'),
721 'mxchat-chatbot',
722 'mxchat_chatbot_section'
723 );
724
725 add_settings_field(
726 'append_to_body',
727 'Append Chat Widget to Body',
728 array($this, 'mxchat_append_to_body_callback'),
729 'mxchat-chatbot',
730 'mxchat_chatbot_section'
731 );
732
733 // Embed Settings Section
734 add_settings_section(
735 'mxchat_embed_section',
736 'Embed Settings',
737 null,
738 'mxchat-embed'
739 );
740
741 add_settings_field(
742 'enable_woocommerce_integration',
743 'Enable WooCommerce Integration',
744 array($this, 'mxchat_enable_woocommerce_integration_callback'),
745 'mxchat-embed',
746 'mxchat_embed_section'
747 );
748
749 add_settings_field(
750 'woocommerce_consumer_key',
751 'WooCommerce Consumer Key',
752 array($this, 'mxchat_woocommerce_consumer_key_callback'),
753 'mxchat-embed',
754 'mxchat_embed_section'
755 );
756
757 add_settings_field(
758 'woocommerce_consumer_secret',
759 'WooCommerce Consumer Secret',
760 array($this, 'mxchat_woocommerce_consumer_secret_callback'),
761 'mxchat-embed',
762 'mxchat_embed_section'
763 );
764
765 // Theme Settings Section
766 add_settings_section(
767 'mxchat_theme_section',
768 'Theme Settings',
769 null,
770 'mxchat-theme'
771 );
772
773 add_settings_field(
774 'close_button_color',
775 'Close Button & Title Color',
776 array($this, 'mxchat_close_button_color_callback'),
777 'mxchat-theme',
778 'mxchat_theme_section'
779 );
780
781 add_settings_field(
782 'chatbot_bg_color',
783 'Chatbot Background Color',
784 array($this, 'mxchat_chatbot_bg_color_callback'),
785 'mxchat-theme',
786 'mxchat_theme_section'
787 );
788
789 add_settings_field(
790 'user_message_bg_color',
791 'User Message Background Color',
792 array($this, 'mxchat_user_message_bg_color_callback'),
793 'mxchat-theme',
794 'mxchat_theme_section'
795 );
796
797 add_settings_field(
798 'user_message_font_color',
799 'User Message Font Color',
800 array($this, 'mxchat_user_message_font_color_callback'),
801 'mxchat-theme',
802 'mxchat_theme_section'
803 );
804
805 add_settings_field(
806 'bot_message_bg_color',
807 'Bot Message Background Color',
808 array($this, 'mxchat_bot_message_bg_color_callback'),
809 'mxchat-theme',
810 'mxchat_theme_section'
811 );
812
813 add_settings_field(
814 'bot_message_font_color',
815 'Bot Message Font Color',
816 array($this, 'mxchat_bot_message_font_color_callback'),
817 'mxchat-theme',
818 'mxchat_theme_section'
819 );
820
821 add_settings_field(
822 'top_bar_bg_color',
823 'Top Bar Background Color',
824 array($this, 'mxchat_top_bar_bg_color_callback'),
825 'mxchat-theme',
826 'mxchat_theme_section'
827 );
828
829 add_settings_field(
830 'send_button_font_color',
831 'Send Button Color',
832 array($this, 'mxchat_send_button_font_color_callback'),
833 'mxchat-theme',
834 'mxchat_theme_section'
835 );
836
837 add_settings_field(
838 'chat_input_font_color',
839 'Chat Input Font Color',
840 array($this, 'mxchat_chat_input_font_color_callback'),
841 'mxchat-theme',
842 'mxchat_theme_section'
843 );
844
845 add_settings_field(
846 'chatbot_background_color',
847 'Floating Widget Background Color',
848 array($this, 'mxchat_chatbot_background_color_callback'),
849 'mxchat-theme',
850 'mxchat_theme_section'
851 );
852
853 add_settings_field(
854 'icon_color',
855 'Chatbot Icon Color',
856 array($this, 'mxchat_icon_color_callback'),
857 'mxchat-theme',
858 'mxchat_theme_section'
859 );
860
861 // General Settings Section
862 add_settings_section(
863 'mxchat_general_section',
864 'General Information',
865 null,
866 'mxchat-general'
867 );
868
869
870 }
871
872
873
874
875 public function mxchat_handle_activate_license() {
876 check_ajax_referer('mxchat_activate_license_nonce', 'security');
877
878 $license_key = isset($_POST['key']) ? sanitize_text_field($_POST['key']) : '';
879 $customer_email = isset($_POST['email']) ? sanitize_email($_POST['email']) : '';
880
881 if (empty($license_key) || empty($customer_email)) {
882 wp_send_json_error('Email or License Key is missing');
883 }
884
885 $product_id = 'MxChatPRO';
886
887 $response = wp_remote_get("http://mxchat.ai/?wc-api=software-api&request=activation&email={$customer_email}&license_key={$license_key}&product_id={$product_id}");
888
889 if (is_wp_error($response)) {
890 wp_send_json_error('Activation failed due to a server error');
891 }
892
893 $body = wp_remote_retrieve_body($response);
894 $data = json_decode($body);
895
896 if ($data && isset($data->activated) && $data->activated) {
897 update_option('mxchat_license_status', 'active');
898 wp_send_json_success();
899 } else {
900 $error_message = isset($data->error) ? $data->error : 'Activation failed';
901 update_option('mxchat_license_status', 'inactive');
902 update_option('mxchat_license_error', $error_message);
903 wp_send_json_error($error_message);
904 }
905 }
906
907
908 public function mxchat_rate_limit_callback() {
909 $rate_limits = array('5', '10', '15', '20', '100');
910 $selected_rate_limit = isset($this->options['rate_limit']) ? $this->options['rate_limit'] : '100';
911
912 $disabled = $this->is_activated ? '' : 'disabled';
913 $class = $this->is_activated ? 'pro-feature-wrapper active' : 'pro-feature-wrapper inactive';
914
915 echo '<div class="' . esc_attr($class) . '">';
916 echo '<select id="rate_limit" name="mxchat_options[rate_limit]" ' . $disabled . '>';
917 foreach ($rate_limits as $limit) {
918 echo '<option value="' . esc_attr($limit) . '" ' . selected($selected_rate_limit, $limit, false) . '>' . esc_html($limit) . '</option>';
919 }
920 echo '</select>';
921
922 if (!$this->is_activated) {
923 echo '<div class="pro-feature-overlay">';
924 echo '<a href="https://mxchat.ai/" target="_blank"><img src="' . plugin_dir_url(__FILE__) . '../images/pro-only-dark.png" alt="Pro Only" /></a>';
925 echo '</div>';
926 }
927
928 echo '</div>';
929 }
930
931 public function mxchat_rate_limit_message_callback() {
932 $disabled = $this->is_activated ? '' : 'disabled';
933 $class = $this->is_activated ? 'pro-feature-wrapper active' : 'pro-feature-wrapper inactive';
934
935 echo '<div class="' . esc_attr($class) . '">';
936 printf(
937 '<textarea id="rate_limit_message" name="mxchat_options[rate_limit_message]" rows="3" cols="50" %s>%s</textarea>',
938 esc_attr($disabled),
939 isset($this->options['rate_limit_message']) ? esc_textarea($this->options['rate_limit_message']) : 'Rate limit exceeded. Please try again later.'
940 );
941
942 if (!$this->is_activated) {
943 echo '<div class="pro-feature-overlay">';
944 echo '<a href="https://mxchat.ai/" target="_blank"><img src="' . plugin_dir_url(__FILE__) . '../images/pro-only-dark.png" alt="Pro Only" /></a>';
945 echo '</div>';
946 }
947
948 echo '</div>';
949 }
950
951
952 public function mxchat_enable_woocommerce_integration_callback() {
953 $checked = isset($this->options['enable_woocommerce_integration']) && $this->options['enable_woocommerce_integration'] === '1' ? 'checked' : '';
954 $disabled = $this->is_activated ? '' : 'disabled';
955 $class = $this->is_activated ? 'pro-feature-wrapper active' : 'pro-feature-wrapper inactive';
956
957 echo '<div class="' . esc_attr($class) . '">';
958 echo '<label class="toggle-switch">';
959 echo '<input type="checkbox" id="enable_woocommerce_integration" name="mxchat_options[enable_woocommerce_integration]" value="1" ' . $checked . ' ' . $disabled . '>';
960 echo '<span class="slider"></span>';
961 echo '</label>';
962
963 if (!$this->is_activated) {
964 echo '<div class="pro-feature-overlay">';
965 echo '<a href="https://mxchat.ai/" target="_blank"><img src="' . plugin_dir_url(__FILE__) . '../images/pro-only-dark.png" alt="Pro Only" /></a>';
966 echo '</div>';
967 }
968
969 echo '</div>';
970 }
971
972
973 private function mxchat_add_option_field($id, $title, $callback = '') {
974 add_settings_field(
975 $id,
976 $title,
977 $callback ? array($this, $callback) : array($this, $id . '_callback'),
978 'mxchat-max',
979 'mxchat_setting_section_id',
980 $id === 'model' ? ['label_for' => 'model'] : []
981 );
982 }
983
984 // Callback for API Key input
985 public function api_key_callback() {
986 printf(
987 '<input type="text" id="api_key" name="mxchat_options[api_key]" value="%s" class="regular-text" />',
988 isset($this->options['api_key']) ? esc_attr($this->options['api_key']) : ''
989 );
990 }
991
992
993
994 public function mxchat_woocommerce_consumer_key_callback() {
995 $disabled = $this->is_activated ? '' : 'disabled';
996 $class = $this->is_activated ? 'pro-feature-wrapper active' : 'pro-feature-wrapper inactive';
997
998 echo '<div class="' . esc_attr($class) . '">';
999 printf(
1000 '<input type="text" id="woocommerce_consumer_key" name="mxchat_options[woocommerce_consumer_key]" value="%s" class="regular-text" %s />',
1001 isset($this->options['woocommerce_consumer_key']) ? esc_attr($this->options['woocommerce_consumer_key']) : '',
1002 $disabled
1003 );
1004
1005 if (!$this->is_activated) {
1006 echo '<div class="pro-feature-overlay">';
1007 echo '<a href="https://mxchat.ai/" target="_blank"><img src="' . plugin_dir_url(__FILE__) . '../images/pro-only-dark.png" alt="Pro Only" /></a>';
1008 echo '</div>';
1009 }
1010
1011 echo '</div>';
1012 }
1013
1014 public function mxchat_woocommerce_consumer_secret_callback() {
1015 $disabled = $this->is_activated ? '' : 'disabled';
1016 $class = $this->is_activated ? 'pro-feature-wrapper active' : 'pro-feature-wrapper inactive';
1017
1018 echo '<div class="' . esc_attr($class) . '">';
1019 printf(
1020 '<input type="text" id="woocommerce_consumer_secret" name="mxchat_options[woocommerce_consumer_secret]" value="%s" class="regular-text" %s />',
1021 isset($this->options['woocommerce_consumer_secret']) ? esc_attr($this->options['woocommerce_consumer_secret']) : '',
1022 $disabled
1023 );
1024
1025 if (!$this->is_activated) {
1026 echo '<div class="pro-feature-overlay">';
1027 echo '<a href="https://mxchat.ai/" target="_blank"><img src="' . plugin_dir_url(__FILE__) . '../images/pro-only-dark.png" alt="Pro Only" /></a>';
1028 echo '</div>';
1029 }
1030
1031 echo '</div>';
1032 }
1033
1034
1035 public function mxchat_pre_chat_message_callback() {
1036 printf(
1037 '<textarea id="pre_chat_message" name="mxchat_options[pre_chat_message]" rows="5" cols="50">%s</textarea>',
1038 isset($this->options['pre_chat_message']) ? esc_textarea($this->options['pre_chat_message']) : ''
1039 );
1040 }
1041
1042 // Callback for AI Instructions textarea
1043 public function system_prompt_instructions_callback() {
1044 printf(
1045 '<textarea id="system_prompt_instructions" name="mxchat_options[system_prompt_instructions]" rows="5" cols="50">%s</textarea>',
1046 isset($this->options['system_prompt_instructions']) ? esc_textarea($this->options['system_prompt_instructions']) : ''
1047 );
1048 }
1049
1050 public function mxchat_model_callback() {
1051 $models = array(
1052 'gpt-4o' => 'gpt-4o',
1053 'gpt-4o-mini' => 'gpt-4o-mini',
1054 'gpt-4-turbo' => 'gpt-4-turbo',
1055 'gpt-4' => 'gpt-4',
1056 'gpt-3.5-turbo' => 'gpt-3.5-turbo',
1057 );
1058
1059 $selected_model = isset($this->options['model']) ? $this->options['model'] : 'gpt-3.5-turbo';
1060
1061 echo '<select id="model" name="mxchat_options[model]">';
1062 foreach ($models as $model_value => $model_label) {
1063 echo '<option value="' . esc_attr($model_value) . '" ' . selected($selected_model, $model_value, false) . '>' . esc_html($model_label) . '</option>';
1064 }
1065 echo '</select>';
1066 }
1067
1068 public function mxchat_top_bar_title_callback() {
1069 printf(
1070 '<input type="text" id="top_bar_title" name="mxchat_options[top_bar_title]" value="%s" />',
1071 isset($this->options['top_bar_title']) ? esc_attr($this->options['top_bar_title']) : ''
1072 );
1073 }
1074
1075 public function mxchat_intro_message_callback() {
1076 printf(
1077 '<textarea id="intro_message" name="mxchat_options[intro_message]" rows="5" cols="50">%s</textarea>',
1078 isset($this->options['intro_message']) ? esc_textarea($this->options['intro_message']) : 'Hello! How can I assist you today?'
1079 );
1080 }
1081
1082
1083
1084
1085
1086 public function mxchat_close_button_color_callback() {
1087 $disabled = $this->is_activated ? '' : 'disabled';
1088
1089 echo '<div class="pro-feature-wrapper">';
1090 printf(
1091 '<input type="text" id="close_button_color" name="mxchat_options[close_button_color]" value="%s" class="my-color-field" data-default-color="#4a4a4a" %s />',
1092 isset($this->options['close_button_color']) ? esc_attr($this->options['close_button_color']) : '',
1093 esc_attr($disabled)
1094 );
1095
1096 if (!$this->is_activated) {
1097 echo '<div class="pro-feature-overlay">';
1098 echo '<a href="https://mxchat.ai/" target="_blank"><img src="' . plugin_dir_url(__FILE__) . '../images/pro-only-dark.png" alt="Pro Only" /></a>';
1099 echo '</div>';
1100 }
1101
1102 echo '</div>';
1103 }
1104
1105 public function mxchat_chatbot_bg_color_callback() {
1106 $disabled = $this->is_activated ? '' : 'disabled';
1107
1108 echo '<div class="pro-feature-wrapper">';
1109 printf(
1110 '<input type="text" id="chatbot_bg_color" name="mxchat_options[chatbot_bg_color]" value="%s" class="my-color-field" data-default-color="#f9f9f9" %s />',
1111 isset($this->options['chatbot_bg_color']) ? esc_attr($this->options['chatbot_bg_color']) : '',
1112 esc_attr($disabled)
1113 );
1114
1115 if (!$this->is_activated) {
1116 echo '<div class="pro-feature-overlay">';
1117 echo '<a href="https://mxchat.ai/" target="_blank"><img src="' . plugin_dir_url(__FILE__) . '../images/pro-only-dark.png" alt="Pro Only" /></a>';
1118 echo '</div>';
1119 }
1120
1121 echo '</div>';
1122 }
1123
1124 public function mxchat_user_message_bg_color_callback() {
1125 $disabled = $this->is_activated ? '' : 'disabled';
1126
1127 echo '<div class="pro-feature-wrapper">';
1128 printf(
1129 '<input type="text" id="user_message_bg_color" name="mxchat_options[user_message_bg_color]" value="%s" class="my-color-field" data-default-color="#0078d7" %s />',
1130 isset($this->options['user_message_bg_color']) ? esc_attr($this->options['user_message_bg_color']) : '',
1131 esc_attr($disabled)
1132 );
1133
1134 if (!$this->is_activated) {
1135 echo '<div class="pro-feature-overlay">';
1136 echo '<a href="https://mxchat.ai/" target="_blank"><img src="' . plugin_dir_url(__FILE__) . '../images/pro-only-dark.png" alt="Pro Only" /></a>';
1137 echo '</div>';
1138 }
1139
1140 echo '</div>';
1141 }
1142
1143 public function mxchat_user_message_font_color_callback() {
1144 $disabled = $this->is_activated ? '' : 'disabled';
1145
1146 echo '<div class="pro-feature-wrapper">';
1147 printf(
1148 '<input type="text" id="user_message_font_color" name="mxchat_options[user_message_font_color]" value="%s" class="my-color-field" data-default-color="#ffffff" %s />',
1149 isset($this->options['user_message_font_color']) ? esc_attr($this->options['user_message_font_color']) : '',
1150 esc_attr($disabled)
1151 );
1152
1153 if (!$this->is_activated) {
1154 echo '<div class="pro-feature-overlay">';
1155 echo '<a href="https://mxchat.ai/" target="_blank"><img src="' . plugin_dir_url(__FILE__) . '../images/pro-only-dark.png" alt="Pro Only" /></a>';
1156 echo '</div>';
1157 }
1158
1159 echo '</div>';
1160 }
1161
1162 public function mxchat_bot_message_bg_color_callback() {
1163 $disabled = $this->is_activated ? '' : 'disabled';
1164
1165 echo '<div class="pro-feature-wrapper">';
1166 printf(
1167 '<input type="text" id="bot_message_bg_color" name="mxchat_options[bot_message_bg_color]" value="%s" class="my-color-field" data-default-color="#e1e1e1" %s />',
1168 isset($this->options['bot_message_bg_color']) ? esc_attr($this->options['bot_message_bg_color']) : '',
1169 esc_attr($disabled)
1170 );
1171
1172 if (!$this->is_activated) {
1173 echo '<div class="pro-feature-overlay">';
1174 echo '<a href="https://mxchat.ai/" target="_blank"><img src="' . plugin_dir_url(__FILE__) . '../images/pro-only-dark.png" alt="Pro Only" /></a>';
1175 echo '</div>';
1176 }
1177
1178 echo '</div>';
1179 }
1180
1181 public function mxchat_bot_message_font_color_callback() {
1182 $disabled = $this->is_activated ? '' : 'disabled';
1183
1184 echo '<div class="pro-feature-wrapper">';
1185 printf(
1186 '<input type="text" id="bot_message_font_color" name="mxchat_options[bot_message_font_color]" value="%s" class="my-color-field" data-default-color="#333333" %s />',
1187 isset($this->options['bot_message_font_color']) ? esc_attr($this->options['bot_message_font_color']) : '',
1188 esc_attr($disabled)
1189 );
1190
1191 if (!$this->is_activated) {
1192 echo '<div class="pro-feature-overlay">';
1193 echo '<a href="https://mxchat.ai/" target="_blank"><img src="' . plugin_dir_url(__FILE__) . '../images/pro-only-dark.png" alt="Pro Only" /></a>';
1194 echo '</div>';
1195 }
1196
1197 echo '</div>';
1198 }
1199
1200 public function mxchat_top_bar_bg_color_callback() {
1201 $disabled = $this->is_activated ? '' : 'disabled';
1202
1203 echo '<div class="pro-feature-wrapper">';
1204 printf(
1205 '<input type="text" id="top_bar_bg_color" name="mxchat_options[top_bar_bg_color]" value="%s" class="my-color-field" data-default-color="#00b294" %s />',
1206 isset($this->options['top_bar_bg_color']) ? esc_attr($this->options['top_bar_bg_color']) : '',
1207 esc_attr($disabled)
1208 );
1209
1210 if (!$this->is_activated) {
1211 echo '<div class="pro-feature-overlay">';
1212 echo '<a href="https://mxchat.ai/" target="_blank"><img src="' . plugin_dir_url(__FILE__) . '../images/pro-only-dark.png" alt="Pro Only" /></a>';
1213 echo '</div>';
1214 }
1215
1216 echo '</div>';
1217 }
1218
1219 public function mxchat_send_button_font_color_callback() {
1220 $disabled = $this->is_activated ? '' : 'disabled';
1221
1222 echo '<div class="pro-feature-wrapper">';
1223 printf(
1224 '<input type="text" id="send_button_font_color" name="mxchat_options[send_button_font_color]" value="%s" class="my-color-field" data-default-color="#ffffff" %s />',
1225 isset($this->options['send_button_font_color']) ? esc_attr($this->options['send_button_font_color']) : '',
1226 esc_attr($disabled)
1227 );
1228
1229 if (!$this->is_activated) {
1230 echo '<div class="pro-feature-overlay">';
1231 echo '<a href="https://mxchat.ai/" target="_blank"><img src="' . plugin_dir_url(__FILE__) . '../images/pro-only-dark.png" alt="Pro Only" /></a>';
1232 echo '</div>';
1233 }
1234
1235 echo '</div>';
1236 }
1237
1238 public function mxchat_chatbot_background_color_callback() {
1239 $disabled = $this->is_activated ? '' : 'disabled';
1240
1241 echo '<div class="pro-feature-wrapper">';
1242 printf(
1243 '<input type="text" id="chatbot_background_color" name="mxchat_options[chatbot_background_color]" value="%s" class="my-color-field" data-default-color="#000000" %s />',
1244 isset($this->options['chatbot_background_color']) ? esc_attr($this->options['chatbot_background_color']) : '',
1245 esc_attr($disabled)
1246 );
1247
1248 if (!$this->is_activated) {
1249 echo '<div class="pro-feature-overlay">';
1250 echo '<a href="https://mxchat.ai/" target="_blank"><img src="' . plugin_dir_url(__FILE__) . '../images/pro-only-dark.png" alt="Pro Only" /></a>';
1251 echo '</div>';
1252 }
1253
1254 echo '</div>';
1255 }
1256
1257 public function mxchat_icon_color_callback() {
1258 $disabled = $this->is_activated ? '' : 'disabled';
1259
1260 echo '<div class="pro-feature-wrapper">';
1261 printf(
1262 '<input type="text" id="icon_color" name="mxchat_options[icon_color]" value="%s" class="my-color-field" data-default-color="#ffffff" %s />',
1263 isset($this->options['icon_color']) ? esc_attr($this->options['icon_color']) : '',
1264 esc_attr($disabled)
1265 );
1266
1267 if (!$this->is_activated) {
1268 echo '<div class="pro-feature-overlay">';
1269 echo '<a href="https://mxchat.ai/" target="_blank"><img src="' . plugin_dir_url(__FILE__) . '../images/pro-only-dark.png" alt="Pro Only" /></a>';
1270 echo '</div>';
1271 }
1272
1273 echo '</div>';
1274 }
1275
1276 public function mxchat_chat_input_font_color_callback() {
1277 $disabled = $this->is_activated ? '' : 'disabled';
1278
1279 echo '<div class="pro-feature-wrapper">';
1280 printf(
1281 '<input type="text" id="chat_input_font_color" name="mxchat_options[chat_input_font_color]" value="%s" class="my-color-field" data-default-color="#555555" %s />',
1282 isset($this->options['chat_input_font_color']) ? esc_attr($this->options['chat_input_font_color']) : '',
1283 esc_attr($disabled)
1284 );
1285
1286 if (!$this->is_activated) {
1287 echo '<div class="pro-feature-overlay">';
1288 echo '<a href="https://mxchat.ai/" target="_blank"><img src="' . plugin_dir_url(__FILE__) . '../images/pro-only-dark.png" alt="Pro Only" /></a>';
1289 echo '</div>';
1290 }
1291
1292 echo '</div>';
1293 }
1294
1295
1296 public function mxchat_append_to_body_callback() {
1297 $append_to_body_checked = isset($this->options['append_to_body']) && $this->options['append_to_body'] === 'on' ? 'checked' : '';
1298 echo '<label class="toggle-switch-label" for="append_to_body">Append Chat Widget to Body:</label>';
1299 echo '<label class="toggle-switch">';
1300 printf(
1301 '<input type="checkbox" id="append_to_body" name="mxchat_options[append_to_body]" %s />',
1302 esc_attr($append_to_body_checked)
1303 );
1304 echo '<span class="slider"></span>';
1305 echo '</label>';
1306 echo '<p class="description">Enable to append the chat widget directly to the body element or use shortcode: [mxchat_chatbot floating="yes"]</p>';
1307 }
1308
1309
1310
1311
1312
1313 public function mxchat_enqueue_admin_assets() {
1314 wp_enqueue_style('wp-color-picker');
1315
1316 // Get the plugin version or file modification time for cache busting
1317 $plugin_version = '1.0.6'; // Replace this with your plugin's version
1318
1319 // File paths
1320 $color_picker_js_path = plugin_dir_path(__FILE__) . '../js/my-color-picker.js';
1321 $embedding_check_js_path = plugin_dir_path(__FILE__) . '../js/embedding-check.js';
1322 $admin_css_path = plugin_dir_path(__FILE__) . '../css/admin-style.css';
1323 $transcripts_js_path = plugin_dir_path(__FILE__) . '../js/mxchat_transcripts.js';
1324
1325 // Check if files exist and get modification times
1326 $color_picker_version = file_exists($color_picker_js_path) ? filemtime($color_picker_js_path) : $plugin_version;
1327 $embedding_check_version = file_exists($embedding_check_js_path) ? filemtime($embedding_check_js_path) : $plugin_version;
1328 $admin_css_version = file_exists($admin_css_path) ? filemtime($admin_css_path) : $plugin_version;
1329 $transcripts_js_version = file_exists($transcripts_js_path) ? filemtime($transcripts_js_path) : $plugin_version;
1330
1331 // Enqueue scripts and styles with corrected paths
1332 wp_enqueue_script(
1333 'mxchat-color-picker',
1334 plugin_dir_url(__FILE__) . '../js/my-color-picker.js',
1335 array('wp-color-picker'),
1336 $color_picker_version,
1337 true
1338 );
1339
1340 wp_enqueue_script(
1341 'mxchat-embedding-check',
1342 plugin_dir_url(__FILE__) . '../js/embedding-check.js',
1343 array(),
1344 $embedding_check_version,
1345 true
1346 );
1347
1348 wp_enqueue_script(
1349 'mxchat-transcripts-js',
1350 plugin_dir_url(__FILE__) . '../js/mxchat_transcripts.js',
1351 array('jquery'),
1352 $transcripts_js_version,
1353 true
1354 );
1355
1356 wp_enqueue_script(
1357 'mxchat-admin-js',
1358 plugin_dir_url(__FILE__) . '../js/mxchat-admin.js',
1359 array('jquery'),
1360 $plugin_version,
1361 true
1362 );
1363
1364 wp_localize_script('mxchat-admin-js', 'mxchatAdmin', array(
1365 'ajax_url' => admin_url('admin-ajax.php'),
1366 'nonce' => wp_create_nonce('mxchat_activate_license_nonce'),
1367 ));
1368
1369 wp_enqueue_style(
1370 'mxchat-admin-css',
1371 plugin_dir_url(__FILE__) . '../css/admin-style.css',
1372 array(),
1373 $admin_css_version
1374 );
1375
1376 // Use wp_json_encode for localizing script
1377 wp_localize_script('mxchat-color-picker', 'mxchatStyleSettings', array(
1378 'ajax_url' => admin_url('admin-ajax.php'),
1379 'user_message_bg_color' => $this->options['user_message_bg_color'] ?? '#fff',
1380 'user_message_font_color' => $this->options['user_message_font_color'] ?? '#212121',
1381 'bot_message_bg_color' => $this->options['bot_message_bg_color'] ?? '#212121',
1382 'bot_message_font_color' => $this->options['bot_message_font_color'] ?? '#fff',
1383 'top_bar_bg_color' => $this->options['top_bar_bg_color'] ?? '#212121',
1384 'send_button_font_color' => $this->options['send_button_font_color'] ?? '#212121',
1385 'close_button_color' => $this->options['close_button_color'] ?? '#fff',
1386 'chatbot_background_color' => $this->options['chatbot_background_color'] ?? '#212121',
1387 'icon_color' => $this->options['icon_color'] ?? '#fff',
1388 'chat_input_font_color' => $this->options['chat_input_font_color'] ?? '#212121'
1389 ));
1390 }
1391
1392 public function mxchat_sanitize($input) {
1393 $new_input = array();
1394
1395 if (isset($input['api_key'])) {
1396 $new_input['api_key'] = sanitize_text_field($input['api_key']);
1397 }
1398
1399 if (isset($input['enable_woocommerce_integration'])) {
1400 $new_input['enable_woocommerce_integration'] = isset($input['enable_woocommerce_integration']) && $input['enable_woocommerce_integration'] === '1' ? '1' : '0';
1401
1402 }
1403
1404 if (isset($input['system_prompt_instructions'])) {
1405 $new_input['system_prompt_instructions'] = sanitize_textarea_field($input['system_prompt_instructions']);
1406 }
1407
1408 if (isset($input['mxchat_pro_email'])) {
1409 $new_input['mxchat_pro_email'] = sanitize_email($input['mxchat_pro_email']);
1410 }
1411
1412 if (isset($input['mxchat_activation_key'])) {
1413 $new_input['mxchat_activation_key'] = sanitize_text_field($input['mxchat_activation_key']);
1414 }
1415
1416 if (isset($input['append_to_body'])) {
1417 $new_input['append_to_body'] = $input['append_to_body'] === 'on' ? 'on' : 'off';
1418 }
1419
1420 if (isset($input['top_bar_title'])) {
1421 $new_input['top_bar_title'] = sanitize_text_field($input['top_bar_title']);
1422 }
1423
1424 if (isset($input['intro_message'])) {
1425 $new_input['intro_message'] = sanitize_text_field($input['intro_message']);
1426 }
1427
1428 if (isset($input['rate_limit_message'])) {
1429 $new_input['rate_limit_message'] = sanitize_text_field($input['rate_limit_message']);
1430 }
1431
1432
1433 if (isset($input['pre_chat_message'])) {
1434 $new_input['pre_chat_message'] = sanitize_textarea_field($input['pre_chat_message']);
1435 }
1436
1437 if (isset($input['model'])) {
1438 $allowed_models = array(
1439 'gpt-4o',
1440 'gpt-4o-mini',
1441 'gpt-4-turbo',
1442 'gpt-4',
1443 'gpt-3.5-turbo',
1444 );
1445 if (in_array($input['model'], $allowed_models)) {
1446 $new_input['model'] = sanitize_text_field($input['model']);
1447 }
1448 }
1449
1450 // Sanitize new pro features
1451 if (isset($input['close_button_color'])) {
1452 $new_input['close_button_color'] = sanitize_hex_color($input['close_button_color']);
1453 }
1454
1455 if (isset($input['chatbot_bg_color'])) {
1456 $new_input['chatbot_bg_color'] = sanitize_hex_color($input['chatbot_bg_color']);
1457 }
1458
1459 if (isset($input['woocommerce_consumer_key'])) {
1460 $new_input['woocommerce_consumer_key'] = sanitize_text_field($input['woocommerce_consumer_key']);
1461 }
1462
1463 if (isset($input['woocommerce_consumer_secret'])) {
1464 $new_input['woocommerce_consumer_secret'] = sanitize_text_field($input['woocommerce_consumer_secret']);
1465 }
1466
1467 if (isset($input['user_message_bg_color'])) {
1468 $new_input['user_message_bg_color'] = sanitize_hex_color($input['user_message_bg_color']);
1469 }
1470
1471 if (isset($input['user_message_font_color'])) {
1472 $new_input['user_message_font_color'] = sanitize_hex_color($input['user_message_font_color']);
1473 }
1474
1475 if (isset($input['bot_message_bg_color'])) {
1476 $new_input['bot_message_bg_color'] = sanitize_hex_color($input['bot_message_bg_color']);
1477 }
1478
1479 if (isset($input['bot_message_font_color'])) {
1480 $new_input['bot_message_font_color'] = sanitize_hex_color($input['bot_message_font_color']);
1481 }
1482
1483 if (isset($input['top_bar_bg_color'])) {
1484 $new_input['top_bar_bg_color'] = sanitize_hex_color($input['top_bar_bg_color']);
1485 }
1486
1487 if (isset($input['send_button_font_color'])) {
1488 $new_input['send_button_font_color'] = sanitize_hex_color($input['send_button_font_color']);
1489 }
1490
1491 if (isset($input['chatbot_background_color'])) {
1492 $new_input['chatbot_background_color'] = sanitize_hex_color($input['chatbot_background_color']);
1493 }
1494
1495 if (isset($input['icon_color'])) {
1496 $new_input['icon_color'] = sanitize_hex_color($input['icon_color']);
1497 }
1498
1499 if (isset($input['chat_input_font_color'])) {
1500 $new_input['chat_input_font_color'] = sanitize_hex_color($input['chat_input_font_color']);
1501 }
1502
1503 return $new_input;
1504 }
1505
1506
1507 // Method to append the chatbot to the body
1508 public function mxchat_append_chatbot_to_body() {
1509 $options = get_option('mxchat_options');
1510 if (isset($options['append_to_body']) && $options['append_to_body'] === 'on') {
1511 echo do_shortcode('[mxchat_chatbot floating="yes"]');
1512 }
1513 }
1514
1515
1516
1517 private function mxchat_extract_main_content($html) {
1518 $dom = new DOMDocument;
1519 libxml_use_internal_errors(true); // Suppress HTML parsing errors
1520 @$dom->loadHTML($html);
1521 libxml_clear_errors();
1522
1523 $xpath = new DOMXPath($dom);
1524
1525 // Simplified selectors focusing on common content areas
1526 $selectors = [
1527 '//article',
1528 '//*[@id="content"]',
1529 '//*[@class="entry-content"]',
1530 '//main',
1531 ];
1532
1533 foreach ($selectors as $selector) {
1534 $nodes = $xpath->query($selector);
1535 if ($nodes->length > 0) {
1536 $content = '';
1537 foreach ($nodes as $node) {
1538 $content .= $dom->saveHTML($node);
1539 }
1540 return $content;
1541 }
1542 }
1543
1544 // Fallback: Return the entire body content if no specific selector matches
1545 $body = $dom->getElementsByTagName('body');
1546 return $body->length > 0 ? $dom->saveHTML($body->item(0)) : $html;
1547 }
1548
1549 public function mxchat_handle_sitemap_submission() {
1550 if (!isset($_POST['submit_sitemap']) || !current_user_can('manage_options')) {
1551 return;
1552 }
1553
1554 check_admin_referer('mxchat_submit_sitemap_action', 'mxchat_submit_sitemap_nonce');
1555
1556 $sitemap_url = esc_url_raw($_POST['sitemap_url']);
1557
1558 $response = wp_remote_get($sitemap_url);
1559 if (is_wp_error($response) || wp_remote_retrieve_response_code($response) !== 200) {
1560 set_transient('mxchat_admin_notice', 'Failed to fetch the sitemap. Please check the URL and try again.', 30);
1561 wp_safe_redirect(esc_url(admin_url('admin.php?page=mxchat-prompts')));
1562 exit;
1563 }
1564
1565 $sitemap_content = wp_remote_retrieve_body($response);
1566
1567 $xml = simplexml_load_string($sitemap_content);
1568 if ($xml === false) {
1569 set_transient('mxchat_admin_notice', 'Invalid sitemap XML. Please provide a valid sitemap.', 30);
1570 wp_safe_redirect(esc_url(admin_url('admin.php?page=mxchat-prompts')));
1571 exit;
1572 }
1573
1574 $embedding_success = true; // Flag to track if all embeddings are successful
1575
1576 foreach ($xml->url as $url_element) {
1577 $page_url = (string)$url_element->loc;
1578
1579 $page_response = wp_remote_get($page_url);
1580 if (is_wp_error($page_response) || wp_remote_retrieve_response_code($page_response) !== 200) {
1581 continue;
1582 }
1583
1584 $page_html = wp_remote_retrieve_body($page_response);
1585 $page_content = $this->mxchat_extract_main_content($page_html);
1586 $sanitized_content = $this->mxchat_sanitize_content_for_api($page_content);
1587
1588 if (!empty($sanitized_content)) {
1589 $embedding_vector = $this->mxchat_generate_embedding($sanitized_content);
1590 if (is_array($embedding_vector)) {
1591 MxChat_Utils::submit_content_to_db($sanitized_content, $page_url, $this->options['api_key']);
1592 } else {
1593 $embedding_success = false; // Set flag to false if any embedding fails
1594 }
1595 }
1596 }
1597
1598 if ($embedding_success) {
1599 set_transient('mxchat_admin_notice', 'Sitemap content successfully submitted!', 30);
1600 } else {
1601 set_transient('mxchat_admin_notice', 'Some content failed to embed. Please check your API key and try again.', 30);
1602 }
1603
1604 wp_safe_redirect(esc_url(admin_url('admin.php?page=mxchat-prompts')));
1605 exit;
1606 }
1607
1608
1609
1610 private function mxchat_sanitize_content_for_api($content) {
1611 // Remove script, style tags, and HTML comments
1612 $content = preg_replace('/<script\b[^>]*>(.*?)<\/script>/is', '', $content);
1613 $content = preg_replace('/<style\b[^>]*>(.*?)<\/style>/is', '', $content);
1614 $content = preg_replace('/<!--(.|\s)*?-->/', '', $content);
1615
1616 // Remove all HTML tags and decode HTML entities
1617 $content = wp_strip_all_tags($content);
1618 $content = html_entity_decode($content, ENT_QUOTES | ENT_HTML5);
1619
1620 // Trim and normalize whitespace
1621 $content = trim(preg_replace('/\s+/', ' ', $content));
1622
1623 return $content;
1624 }
1625
1626
1627 }
1628 ?>
1629