| 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 |
// Add the AJAX handler for logged-in users |
| 37 |
add_action('wp_ajax_mxchat_save_inline_prompt', array($this, 'mxchat_save_inline_prompt')); |
| 38 |
|
| 39 |
|
| 40 |
} |
| 41 |
|
| 42 |
// Method to check if the license is active |
| 43 |
private function is_license_active() { |
| 44 |
$license_status = get_option('mxchat_license_status', 'inactive'); |
| 45 |
return $license_status === 'active'; |
| 46 |
} |
| 47 |
|
| 48 |
// Initialize default options |
| 49 |
private function initialize_default_options() { |
| 50 |
$default_options = array( |
| 51 |
'api_key' => '', |
| 52 |
'xai_api_key' => '', |
| 53 |
'claude_api_key' => '', |
| 54 |
'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: |
| 55 |
- Your name is [Chatbot Name]. Always introduce yourself as this name when appropriate. |
| 56 |
- 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. |
| 57 |
- When appropriate, highlight the benefits of [insert proper subject here]. Offer to guide visitors to relevant pages or provide them with more information. |
| 58 |
- 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. |
| 59 |
- Keep your responses short, concise, and to the point. Provide clear and direct answers suitable for a chatbot interaction. |
| 60 |
- 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. |
| 61 |
- 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.', |
| 62 |
'model' => 'gpt-3.5-turbo', |
| 63 |
'rate_limit' => '100', |
| 64 |
'rate_limit_message' => 'Rate limit exceeded. Please try again later.', |
| 65 |
'top_bar_title' => 'MxChat', |
| 66 |
'intro_message' => 'Hello! How can I assist you today?', |
| 67 |
'input_copy' => 'How can I assist?', |
| 68 |
'append_to_body' => 'off', |
| 69 |
'close_button_color' => '#fff', |
| 70 |
'chatbot_bg_color' => '#fff', |
| 71 |
'user_message_bg_color' => '#fff', |
| 72 |
'user_message_font_color' => '#212121', |
| 73 |
'bot_message_bg_color' => '#212121', |
| 74 |
'bot_message_font_color' => '#fff', |
| 75 |
'top_bar_bg_color' => '#212121', |
| 76 |
'send_button_font_color' => '#212121', |
| 77 |
'chat_input_font_color' => '#212121', |
| 78 |
'chatbot_background_color' => '#212121', |
| 79 |
'icon_color' => '#fff', |
| 80 |
'enable_woocommerce_integration' => '0', |
| 81 |
'link_target_toggle' => 'off', |
| 82 |
'pre_chat_message' => 'Hey there! Ask me anything!', |
| 83 |
|
| 84 |
// New fields for Loops Integration |
| 85 |
'loops_api_key' => '', |
| 86 |
'loops_mailing_list' => '', |
| 87 |
'triggered_phrase_response' => 'Would you like to join our mailing list? Please provide your email below.', |
| 88 |
'email_capture_response' => 'Thank you for providing your email! You\'ve been added to our list.', |
| 89 |
'popular_question_1' => '', |
| 90 |
'popular_question_2' => '', |
| 91 |
'popular_question_3' => '', |
| 92 |
); |
| 93 |
|
| 94 |
|
| 95 |
// Merge existing options with defaults |
| 96 |
$existing_options = get_option('mxchat_options', array()); |
| 97 |
$merged_options = wp_parse_args($existing_options, $default_options); |
| 98 |
|
| 99 |
// Update the options if they have changed |
| 100 |
if ($existing_options !== $merged_options) { |
| 101 |
update_option('mxchat_options', $merged_options); |
| 102 |
} |
| 103 |
|
| 104 |
// Update the $this->options property |
| 105 |
$this->options = $merged_options; |
| 106 |
} |
| 107 |
|
| 108 |
|
| 109 |
|
| 110 |
public function mxchat_add_plugin_page() { |
| 111 |
// Main menu page |
| 112 |
add_menu_page( |
| 113 |
'MxChat Settings', |
| 114 |
'MxChat', |
| 115 |
'manage_options', |
| 116 |
'mxchat-max', |
| 117 |
array($this, 'mxchat_create_admin_page'), |
| 118 |
'dashicons-testimonial', |
| 119 |
6 |
| 120 |
); |
| 121 |
|
| 122 |
// Submenu page for Knowledge |
| 123 |
add_submenu_page( |
| 124 |
'mxchat-max', |
| 125 |
'Prompts', |
| 126 |
'Knowledge', |
| 127 |
'manage_options', |
| 128 |
'mxchat-prompts', |
| 129 |
array($this, 'mxchat_create_prompts_page') |
| 130 |
); |
| 131 |
|
| 132 |
// Submenu page for Chat Transcripts |
| 133 |
add_submenu_page( |
| 134 |
'mxchat-max', // Corrected parent slug to match the main menu |
| 135 |
'Chat Transcripts', |
| 136 |
'Transcripts', |
| 137 |
'manage_options', |
| 138 |
'mxchat-transcripts', |
| 139 |
array($this, 'mxchat_create_transcripts_page') // Prefixed function name with mxchat_ |
| 140 |
); |
| 141 |
|
| 142 |
// Submenu page for Intents |
| 143 |
add_submenu_page( |
| 144 |
'mxchat-max', // Parent slug |
| 145 |
'MxChat Intents', // Page title |
| 146 |
'Intents', // Menu title |
| 147 |
'manage_options', // Capability |
| 148 |
'mxchat-intents', // Menu slug |
| 149 |
array($this, 'mxchat_intents_page_html') // Callback function |
| 150 |
); |
| 151 |
|
| 152 |
// Submenu page for Activation Key |
| 153 |
add_submenu_page( |
| 154 |
'mxchat-max', |
| 155 |
'Pro Upgrade', |
| 156 |
'Pro Upgrade', |
| 157 |
'manage_options', |
| 158 |
'mxchat-activation', |
| 159 |
array($this, 'mxchat_create_activation_page') |
| 160 |
); |
| 161 |
|
| 162 |
|
| 163 |
} |
| 164 |
|
| 165 |
|
| 166 |
public function mxchat_handle_content_submission() { |
| 167 |
// Check if the form was submitted and the user has sufficient permissions |
| 168 |
if (!isset($_POST['submit_content']) || !current_user_can('manage_options')) { |
| 169 |
return; |
| 170 |
} |
| 171 |
|
| 172 |
// Verify the nonce field for security |
| 173 |
$nonce = isset($_POST['mxchat_submit_content_nonce']) ? sanitize_text_field(wp_unslash($_POST['mxchat_submit_content_nonce'])) : ''; |
| 174 |
if (!wp_verify_nonce($nonce, 'mxchat_submit_content_action')) { |
| 175 |
wp_die('Nonce verification failed.'); |
| 176 |
} |
| 177 |
|
| 178 |
// Sanitize the content input |
| 179 |
$article_content = sanitize_textarea_field($_POST['article_content']); |
| 180 |
|
| 181 |
// Sanitize the URL input (optional URL) |
| 182 |
$article_url = isset($_POST['article_url']) ? esc_url_raw($_POST['article_url']) : ''; // Default to empty if not provided |
| 183 |
|
| 184 |
// Generate the embedding vector for the content |
| 185 |
$embedding_vector = $this->mxchat_generate_embedding($article_content); |
| 186 |
|
| 187 |
global $wpdb; |
| 188 |
$table_name = $wpdb->prefix . 'mxchat_system_prompt_content'; |
| 189 |
|
| 190 |
// Check if the 'source_url' column exists in the table and add it if it doesn't |
| 191 |
if ($wpdb->get_var($wpdb->prepare("SHOW COLUMNS FROM {$table_name} LIKE %s", 'source_url')) != 'source_url') { |
| 192 |
// Use wpdb::query and a prepared statement to avoid SQL injection |
| 193 |
$wpdb->query($wpdb->prepare("ALTER TABLE {$table_name} ADD source_url VARCHAR(255) DEFAULT ''")); |
| 194 |
} |
| 195 |
|
| 196 |
if (is_array($embedding_vector)) { |
| 197 |
// Serialize the embedding vector before storing it |
| 198 |
$embedding_vector_serialized = serialize($embedding_vector); |
| 199 |
|
| 200 |
// Insert the content, embedding vector, and source URL into the database, using a prepared statement |
| 201 |
$inserted = $wpdb->insert( |
| 202 |
$table_name, |
| 203 |
array( |
| 204 |
'article_content' => $article_content, |
| 205 |
'embedding_vector' => $embedding_vector_serialized, |
| 206 |
'source_url' => $article_url, // Insert the URL, empty string if not provided |
| 207 |
), |
| 208 |
array( |
| 209 |
'%s', // Format for article_content (string) |
| 210 |
'%s', // Format for embedding_vector (serialized string) |
| 211 |
'%s', // Format for source_url (string) |
| 212 |
) |
| 213 |
); |
| 214 |
|
| 215 |
if ($inserted === false) { |
| 216 |
//error_log('Error inserting content: ' . $wpdb->last_error); |
| 217 |
set_transient('mxchat_admin_notice_error', 'Error inserting content into the database. Please try again.', 30); |
| 218 |
} else { |
| 219 |
set_transient('mxchat_admin_notice_success', 'Content successfully submitted!', 30); |
| 220 |
} |
| 221 |
|
| 222 |
} else { |
| 223 |
//error_log('Embedding generation failed for article content: ' . $article_content); |
| 224 |
set_transient('mxchat_admin_notice_error', 'Embedding generation failed. Please ensure your API key is correct and try again.', 30); |
| 225 |
} |
| 226 |
|
| 227 |
// Redirect after setting the transient |
| 228 |
wp_safe_redirect(esc_url(admin_url('admin.php?page=mxchat-prompts'))); |
| 229 |
exit; |
| 230 |
} |
| 231 |
|
| 232 |
public function mxchat_display_admin_notice() { |
| 233 |
// Success notice |
| 234 |
if ($message = get_transient('mxchat_admin_notice_success')) { |
| 235 |
?> |
| 236 |
<div class="notice notice-success is-dismissible"> |
| 237 |
<p><?php echo esc_html($message); ?></p> |
| 238 |
<button type="button" class="notice-dismiss"><span class="screen-reader-text">Dismiss this notice.</span></button> |
| 239 |
</div> |
| 240 |
<?php |
| 241 |
delete_transient('mxchat_admin_notice_success'); // Clear the transient after displaying |
| 242 |
} |
| 243 |
|
| 244 |
// Error notice |
| 245 |
if ($message = get_transient('mxchat_admin_notice_error')) { |
| 246 |
?> |
| 247 |
<div class="notice notice-error is-dismissible"> |
| 248 |
<p><?php echo esc_html($message); ?></p> |
| 249 |
<button type="button" class="notice-dismiss"><span class="screen-reader-text">Dismiss this notice.</span></button> |
| 250 |
</div> |
| 251 |
<?php |
| 252 |
delete_transient('mxchat_admin_notice_error'); // Clear the transient after displaying |
| 253 |
} |
| 254 |
} |
| 255 |
|
| 256 |
|
| 257 |
public function mxchat_handle_delete_prompt() { |
| 258 |
// Sanitize and validate nonce using wp_unslash and sanitize_text_field |
| 259 |
$nonce = isset($_GET['_wpnonce']) ? sanitize_text_field(wp_unslash($_GET['_wpnonce'])) : ''; |
| 260 |
if (empty($nonce) || !wp_verify_nonce($nonce, 'mxchat_delete_prompt_nonce')) { |
| 261 |
wp_die('Nonce verification failed.'); |
| 262 |
} |
| 263 |
|
| 264 |
// Check user permissions |
| 265 |
if (!current_user_can('manage_options')) { |
| 266 |
wp_die('You do not have sufficient permissions to delete prompts.'); |
| 267 |
} |
| 268 |
|
| 269 |
// Sanitize and validate the 'id' parameter |
| 270 |
$id = isset($_GET['id']) ? intval($_GET['id']) : 0; |
| 271 |
if ($id <= 0) { |
| 272 |
wp_die('Invalid prompt ID.'); |
| 273 |
} |
| 274 |
|
| 275 |
global $wpdb; |
| 276 |
$table_name = $wpdb->prefix . 'mxchat_system_prompt_content'; |
| 277 |
|
| 278 |
// Clear relevant cache before deletion |
| 279 |
$cache_key = 'prompt_' . $id; |
| 280 |
wp_cache_delete($cache_key, 'mxchat_prompts'); |
| 281 |
|
| 282 |
// Delete the record using a prepared statement |
| 283 |
$deleted = $wpdb->delete($table_name, array('id' => $id), array('%d')); |
| 284 |
|
| 285 |
if ($deleted !== false) { |
| 286 |
// Optionally, clear a general cache if you have one |
| 287 |
wp_cache_delete('all_prompts', 'mxchat_prompts'); |
| 288 |
} |
| 289 |
|
| 290 |
// Redirect to the prompts page with a success message |
| 291 |
$redirect_url = add_query_arg(array( |
| 292 |
'page' => 'mxchat-prompts', |
| 293 |
'deleted' => 'true' |
| 294 |
), admin_url('admin.php')); |
| 295 |
|
| 296 |
wp_safe_redirect($redirect_url); |
| 297 |
exit; |
| 298 |
} |
| 299 |
|
| 300 |
|
| 301 |
public function mxchat_create_admin_page() { |
| 302 |
?> |
| 303 |
<div class="wrap mxchat-admin"> |
| 304 |
<?php if (!$this->is_activated): ?> |
| 305 |
<div class="mxchat-pro-banner"> |
| 306 |
<p> |
| 307 |
Limited-time offer: Get a lifetime MxChat Pro license for just $49.97 until 01.01.25! After that, it switches to an annual license at $99.97/year. Purchase now and be grandfathered into the lifetime deal! |
| 308 |
<a href="https://mxchat.ai/" target="_blank">Upgrade to MxChat Pro today!</a> |
| 309 |
</p> |
| 310 |
</div> |
| 311 |
<?php endif; ?> |
| 312 |
<h2 class="admin-title">Mx<span class="admin-emphasis">Chat</span></h2> |
| 313 |
<h2 class="mxchat-nav-tab-wrapper"> |
| 314 |
<a href="#chatbot" class="mxchat-nav-tab mxchat-nav-tab-active" data-tab="chatbot">Chatbot</a> |
| 315 |
<a href="#embed" class="mxchat-nav-tab" data-tab="embed">Integrations</a> |
| 316 |
<a href="#theme" class="mxchat-nav-tab" data-tab="theme">Theme</a> |
| 317 |
<a href="#general" class="mxchat-nav-tab" data-tab="general">FAQ</a> |
| 318 |
</h2> |
| 319 |
<form method="post" action="options.php"> |
| 320 |
<?php settings_fields('mxchat_option_group'); ?> |
| 321 |
<div id="chatbot" class="mxchat-tab-content active"> |
| 322 |
<?php do_settings_sections('mxchat-chatbot'); ?> |
| 323 |
</div> |
| 324 |
|
| 325 |
|
| 326 |
|
| 327 |
<div id="embed" class="mxchat-tab-content"> |
| 328 |
<div class="mxchat-settings-section"> |
| 329 |
<h2>WooCommerce Settings</h2> |
| 330 |
<table class="form-table"> |
| 331 |
<?php do_settings_fields('mxchat-embed', 'mxchat_woocommerce_section'); ?> |
| 332 |
</table> |
| 333 |
</div> |
| 334 |
|
| 335 |
<div class="section-divider"></div> <!-- Divider --> |
| 336 |
|
| 337 |
<div class="mxchat-settings-section"> |
| 338 |
<h2>Loops Settings</h2> |
| 339 |
<table class="form-table"> |
| 340 |
<?php do_settings_fields('mxchat-embed', 'mxchat_loops_section'); ?> |
| 341 |
</table> |
| 342 |
</div> |
| 343 |
|
| 344 |
|
| 345 |
<div class="section-divider"></div> <!-- Divider --> |
| 346 |
|
| 347 |
<!-- Brave Search Settings Section --> |
| 348 |
<div class="mxchat-settings-section"> |
| 349 |
<h2>Brave Search Settings</h2> |
| 350 |
<table class="form-table"> |
| 351 |
<?php do_settings_fields('mxchat-embed', 'mxchat_brave_section'); ?> |
| 352 |
</table> |
| 353 |
</div> |
| 354 |
</div> |
| 355 |
|
| 356 |
|
| 357 |
|
| 358 |
|
| 359 |
|
| 360 |
<div id="theme" class="mxchat-tab-content"> |
| 361 |
<?php do_settings_sections('mxchat-theme'); ?> |
| 362 |
</div> |
| 363 |
<div id="general" class="mxchat-tab-content"> |
| 364 |
<?php do_settings_sections('mxchat-general'); ?> |
| 365 |
<p>If you’re having trouble with setup or getting the responses you need, we encourage you to review our <a href="https://mxchat.ai/documentation/" target="_blank" rel="noopener noreferrer">documentation</a>.</p> |
| 366 |
|
| 367 |
<div class="faq-item"> |
| 368 |
<h3>How does the Claude API integration work?</h3> |
| 369 |
<p> |
| 370 |
The Claude API, provided by Anthropic, allows for intelligent, context-aware chatbot responses in MxChat. To use it, you will need both an OpenAI API key and a Claude API key. This is necessary because the system utilizes OpenAI for vector embedding in the Retrieval-Augmented Generation (RAG) process, as Claude does not currently offer an embedding API. |
| 371 |
</p> |
| 372 |
<p> |
| 373 |
When using the Claude API, your custom content is sent to Claude for generating responses, while the embeddings are processed through OpenAI. This ensures your chatbot provides accurate and engaging responses while maintaining knowledge relevant to your website. |
| 374 |
</p> |
| 375 |
<p> |
| 376 |
You can obtain your Claude API key by signing up on the <a href="https://www.anthropic.com/api" target="_blank" rel="noopener">Anthropic API page</a>. |
| 377 |
</p> |
| 378 |
</div> |
| 379 |
|
| 380 |
<div class="faq-item"> |
| 381 |
<h3>How does the X.AI API integration work?</h3> |
| 382 |
<p> |
| 383 |
The X.AI API, released on 10.21.24, is currently in beta. To use it, you will need both an OpenAI API key and an X.AI API key. This is because OpenAI handles vector embeddings in the Retrieval-Augmented Generation (RAG) process, as X.AI does not yet provide an embedding API. |
| 384 |
</p> |
| 385 |
<p> |
| 386 |
Custom content is sent to the X.AI API for generating responses, while OpenAI processes the embeddings. This allows the chatbot to provide advanced responses while maintaining context from your website. You can get your X.AI API key from the <a href="https://docs.x.ai/docs" target="_blank" rel="noopener">X.AI API documentation</a>. |
| 387 |
</p> |
| 388 |
</div> |
| 389 |
|
| 390 |
<div class="faq-item"> |
| 391 |
<h3>Do I need an OpenAI API key to use the chatbot?</h3> |
| 392 |
<p> |
| 393 |
Yes, you will need an OpenAI API key to power the chatbot. You can obtain an API key by signing up on the <a href="https://platform.openai.com/signup" target="_blank" rel="noopener">OpenAI platform</a>. After signing up, you must add credits to your account—typically, $5 in credits is sufficient to get started. |
| 394 |
</p> |
| 395 |
<p> |
| 396 |
Once you have your API key, simply enter it in the chatbot's settings to enable functionality. The chatbot relies on OpenAI’s models for generating responses, so having sufficient credits in your OpenAI account is essential for smooth operation. |
| 397 |
</p> |
| 398 |
</div> |
| 399 |
|
| 400 |
<div class="faq-item"> |
| 401 |
<h3>How do I add the chatbot to my site?</h3> |
| 402 |
<p> |
| 403 |
You can add the chatbot using the shortcode <code>[mxchat_chatbot floating="yes"]</code> or <code>[mxchat_chatbot floating="no"]</code>. For initial testing and styling, it's best to use the shortcode on a draft or non-public page. Once you’re ready to go live, enable the “Append Chat Widget to Body” option in the settings for site-wide integration (recommended) or add shortcode to the footer. |
| 404 |
</p> |
| 405 |
</div> |
| 406 |
|
| 407 |
<div class="faq-item"> |
| 408 |
<h3>How does the chatbot use my content to generate responses?</h3> |
| 409 |
<p> |
| 410 |
The chatbot uses AI and vector embeddings to connect users with relevant information. When you submit content, it converts it into a mathematical format. When a user asks a question, the bot matches it to your stored content and generates a response based on relevance. For example, submitting "Our phone number is 910-123-4567" allows the bot to retrieve this information when asked about contact details. To ensure related information is provided together, submit it in one entry. |
| 411 |
</p> |
| 412 |
</div> |
| 413 |
|
| 414 |
<div class="faq-item"> |
| 415 |
<h3>Why does the chatbot sometimes make up links or information?</h3> |
| 416 |
<p> |
| 417 |
Occasionally, the chatbot may generate inaccurate links or information, known as "hallucinations." To minimize this, you can add system instructions to guide its behavior. For example, include an instruction like: "Only provide links you directly have access to or retrieve from the knowledge base. Do not make up links or information that you do not have direct access to." This helps the bot stay aligned with your content. |
| 418 |
</p> |
| 419 |
</div> |
| 420 |
|
| 421 |
<div class="faq-item"> |
| 422 |
<h3>How do intents work in MxChat?</h3> |
| 423 |
<p> |
| 424 |
Intents allow MxChat to recognize user requests and trigger specific actions, such as capturing emails or displaying product information. This helps provide a more interactive and responsive experience. For a detailed explanation of each intent, please refer to our <a href="https://mxchat.ai/documentation/#intents" target="_blank" rel="noopener noreferrer">Intents Documentation</a>. |
| 425 |
</p> |
| 426 |
</div> |
| 427 |
|
| 428 |
|
| 429 |
<div class="faq-item"> |
| 430 |
<h3>How does the Complianz integration work?</h3> |
| 431 |
<p> |
| 432 |
The Pro version offers direct integration with the Complianz GDPR plugin, making it easy to stay compliant with GDPR. If Complianz is enabled on your website, users must accept consent before the chatbot widget appears. The chatbot will only display once the user has accepted, ensuring compliance with data privacy regulations. |
| 433 |
</p> |
| 434 |
</div> |
| 435 |
|
| 436 |
<div class="faq-item"> |
| 437 |
<h3>How does the WooCommerce integration work?</h3> |
| 438 |
<p> |
| 439 |
With WooCommerce integration, the chatbot automatically embeds new products and updates existing ones. For already-published products, you can click update or submit the product sitemap. The “Order History Access” setting allows the bot to access users' order history (requires login) and assist with order inquiries. To enable the “Add to Cart” feature, add this system instruction: “After discussing a product, ask if the user wants to add it to their cart. The user must say 'Add to cart' exactly.” Currently, this feature supports English only, with more languages coming soon. |
| 440 |
</p> |
| 441 |
</div> |
| 442 |
|
| 443 |
<div class="faq-item"> |
| 444 |
<h3>Why isn't my chatbot responding as expected?</h3> |
| 445 |
<p> |
| 446 |
AI chatbots can sometimes behave in unexpected ways, especially if you're new to configuring AI for specific tasks. We're committed to helping you get the most out of your chatbot experience. While we’re working on comprehensive guides and video tutorials, our team is here to assist you directly. If your chatbot isn't delivering the responses you need, please don’t hesitate to <a href="https://mxchat.ai/contact/" target="_blank" rel="noopener noreferrer">contact us</a> for personalized support. |
| 447 |
</p> |
| 448 |
<p> |
| 449 |
We’re dedicated to your success and ready to guide you in aligning the AI's behavior to meet your goals. |
| 450 |
</p> |
| 451 |
</div> |
| 452 |
|
| 453 |
<div class="faq-item"> |
| 454 |
<h3>What is Loops, and how do I get an API key?</h3> |
| 455 |
<p> |
| 456 |
Loops is a powerful SaaS email service that helps you automate and enhance your email marketing campaigns, making it easy to reach and engage with your audience. To integrate Loops with MxChat, you’ll need an API key from Loops. You can obtain this key by logging into your Loops account and navigating to the API settings. Visit the <a href="https://loops.so" target="_blank" rel="noopener noreferrer">Loops website</a> to get started or to sign up for an account. |
| 457 |
</p> |
| 458 |
</div> |
| 459 |
|
| 460 |
|
| 461 |
</div> |
| 462 |
<?php submit_button(); ?> |
| 463 |
</form> |
| 464 |
</div> |
| 465 |
<?php |
| 466 |
} |
| 467 |
|
| 468 |
|
| 469 |
public function mxchat_create_transcripts_page() { |
| 470 |
?> |
| 471 |
<div class="wrap mxchat-admin"> |
| 472 |
<h2><?php esc_html_e('Chat Transcripts', 'mxchat'); ?></h2> |
| 473 |
<form id="mxchat-delete-form" method="post"> |
| 474 |
<?php wp_nonce_field('mxchat_delete_chat_history', 'mxchat_delete_chat_nonce'); ?> |
| 475 |
<div class="mxchat-controls"> |
| 476 |
<label for="mxchat-select-all-transcripts" class="mxchat-select-all-label"> |
| 477 |
<input type="checkbox" id="mxchat-select-all-transcripts" /> <?php esc_html_e('Select All', 'mxchat'); ?> |
| 478 |
</label> |
| 479 |
<input type="submit" value="<?php esc_attr_e('Delete Selected', 'mxchat'); ?>" class="button button-primary delete-chats-button" /> |
| 480 |
</div> |
| 481 |
<div id="mxchat-transcripts"> |
| 482 |
<!-- Transcripts will be loaded here --> |
| 483 |
</div> |
| 484 |
</form> |
| 485 |
</div> |
| 486 |
<?php |
| 487 |
} |
| 488 |
|
| 489 |
|
| 490 |
|
| 491 |
|
| 492 |
public function mxchat_create_prompts_page() { |
| 493 |
global $wpdb; |
| 494 |
$table_name = $wpdb->prefix . 'mxchat_system_prompt_content'; |
| 495 |
|
| 496 |
// Verify the nonce before processing the request |
| 497 |
$nonce = isset($_GET['_wpnonce']) ? sanitize_text_field($_GET['_wpnonce']) : ''; |
| 498 |
|
| 499 |
if (!empty($nonce) && wp_verify_nonce($nonce, 'mxchat_prompts_search_nonce')) { |
| 500 |
// Sanitize input data |
| 501 |
$search_query = isset($_GET['search']) ? sanitize_text_field($_GET['search']) : ''; |
| 502 |
$current_page = isset($_GET['paged']) ? absint($_GET['paged']) : 1; |
| 503 |
} else { |
| 504 |
$search_query = ''; |
| 505 |
$current_page = 1; |
| 506 |
} |
| 507 |
|
| 508 |
$per_page = 10; |
| 509 |
|
| 510 |
// Create cache keys |
| 511 |
$cache_key_total = 'total_prompts_' . md5($search_query); |
| 512 |
$cache_key_prompts = 'prompts_' . md5($search_query . '_' . $current_page); |
| 513 |
|
| 514 |
// Retrieve total number of prompts from cache or database |
| 515 |
$total_prompts = wp_cache_get($cache_key_total, 'mxchat_prompts'); |
| 516 |
if ($total_prompts === false) { |
| 517 |
if (!empty($search_query)) { |
| 518 |
$total_prompts = $wpdb->get_var( |
| 519 |
$wpdb->prepare( |
| 520 |
"SELECT COUNT(*) FROM {$table_name} WHERE article_content LIKE %s", |
| 521 |
'%' . $wpdb->esc_like($search_query) . '%' |
| 522 |
) |
| 523 |
); |
| 524 |
} else { |
| 525 |
$total_prompts = $wpdb->get_var("SELECT COUNT(*) FROM {$table_name}"); |
| 526 |
} |
| 527 |
wp_cache_set($cache_key_total, $total_prompts, 'mxchat_prompts', 3600); // Cache for 1 hour |
| 528 |
} |
| 529 |
|
| 530 |
$total_pages = ceil($total_prompts / $per_page); |
| 531 |
$offset = ($current_page - 1) * $per_page; |
| 532 |
|
| 533 |
// Retrieve prompts from cache or database |
| 534 |
$prompts = wp_cache_get($cache_key_prompts, 'mxchat_prompts'); |
| 535 |
if ($prompts === false) { |
| 536 |
if (!empty($search_query)) { |
| 537 |
$prompts = $wpdb->get_results( |
| 538 |
$wpdb->prepare( |
| 539 |
"SELECT * FROM {$table_name} WHERE article_content LIKE %s ORDER BY timestamp DESC LIMIT %d OFFSET %d", |
| 540 |
'%' . $wpdb->esc_like($search_query) . '%', |
| 541 |
$per_page, |
| 542 |
$offset |
| 543 |
) |
| 544 |
); |
| 545 |
} else { |
| 546 |
$prompts = $wpdb->get_results( |
| 547 |
$wpdb->prepare( |
| 548 |
"SELECT * FROM {$table_name} ORDER BY timestamp DESC LIMIT %d OFFSET %d", |
| 549 |
$per_page, |
| 550 |
$offset |
| 551 |
) |
| 552 |
); |
| 553 |
} |
| 554 |
wp_cache_set($cache_key_prompts, $prompts, 'mxchat_prompts', 3600); // Cache for 1 hour |
| 555 |
} |
| 556 |
|
| 557 |
?> |
| 558 |
|
| 559 |
<div class="wrap mxchat-admin"> |
| 560 |
<div class="mxchat-grid-container"> |
| 561 |
|
| 562 |
<!-- Submit Content --> |
| 563 |
<div class="mxchat-grid-item full-width"> |
| 564 |
<h2>Submit Content</h2> |
| 565 |
<form method="post" action="<?php echo esc_url(admin_url('admin-post.php?action=mxchat_submit_content')); ?>"> |
| 566 |
<?php wp_nonce_field('mxchat_submit_content_action', 'mxchat_submit_content_nonce'); ?> |
| 567 |
<div class="mxchat-form-group"> |
| 568 |
<label for="article_content">Article Content:</label> |
| 569 |
<textarea name="article_content" id="article_content" required></textarea> |
| 570 |
</div> |
| 571 |
<div class="mxchat-form-group"> |
| 572 |
<label for="article_url">Article URL (Optional):</label> |
| 573 |
<input type="url" name="article_url" id="article_url" placeholder="Enter related URL for the content"> |
| 574 |
</div> |
| 575 |
<input type="submit" name="submit_content" value="Submit Content" class="button button-primary submit-content-button" /> |
| 576 |
</form> |
| 577 |
</div> |
| 578 |
|
| 579 |
|
| 580 |
<!-- Submit Sitemap --> |
| 581 |
<div class="mxchat-grid-item"> |
| 582 |
<h2>Submit Sitemap or Page URL</h2> |
| 583 |
<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')); ?>"> |
| 584 |
<?php wp_nonce_field('mxchat_submit_sitemap_action', 'mxchat_submit_sitemap_nonce'); ?> |
| 585 |
<div class="mxchat-search-group"> |
| 586 |
<input type="url" name="sitemap_url" id="sitemap_url" placeholder="Sitemap or URL" required /> |
| 587 |
<input type="submit" name="submit_sitemap" value="Submit" class="button button-primary" /> |
| 588 |
</div> |
| 589 |
</form> |
| 590 |
<div id="mxchat-sitemap-loading" class="mxchat-spinner" style="display: none;"></div> |
| 591 |
<div id="mxchat-loading-text" style="display: none; margin-top: 10px; color: #333;">Loading sitemap content into database, please wait...</div> |
| 592 |
</div> |
| 593 |
|
| 594 |
<!-- Search Knowledge --> |
| 595 |
<div class="mxchat-grid-item"> |
| 596 |
<h2>Search Knowledge</h2> |
| 597 |
<form method="get" id="knowledge-search"> |
| 598 |
<?php wp_nonce_field('mxchat_prompts_search_nonce'); ?> |
| 599 |
<input type="hidden" name="page" value="mxchat-prompts" /> |
| 600 |
<div class="mxchat-search-group"> |
| 601 |
<input type="text" name="search" placeholder="Search Knowledge" value="<?php echo esc_attr($search_query); ?>" /> |
| 602 |
<input type="submit" value="Search" class="button button-primary" /> |
| 603 |
</div> |
| 604 |
</form> |
| 605 |
</div> |
| 606 |
</div> |
| 607 |
|
| 608 |
<!-- Table below the forms --> |
| 609 |
<div class="tablenav"> |
| 610 |
<div class="tablenav-pages"> |
| 611 |
<span class="displaying-num"><?php echo esc_html($total_prompts); ?> items</span> |
| 612 |
<?php |
| 613 |
$page_links = paginate_links(array( |
| 614 |
'base' => add_query_arg('paged', '%#%', admin_url('admin.php?page=mxchat-prompts')), |
| 615 |
'format' => '', |
| 616 |
'prev_text' => __('« Previous'), |
| 617 |
'next_text' => __('Next »'), |
| 618 |
'total' => $total_pages, |
| 619 |
'current' => $current_page, |
| 620 |
'add_args' => array( |
| 621 |
'search' => $search_query, |
| 622 |
'_wpnonce' => wp_create_nonce('mxchat_prompts_search_nonce') |
| 623 |
), |
| 624 |
)); |
| 625 |
|
| 626 |
if ($page_links) { |
| 627 |
echo '<div class="tablenav-pages">' . wp_kses_post($page_links) . '</div>'; |
| 628 |
} |
| 629 |
?> |
| 630 |
</div> |
| 631 |
</div> |
| 632 |
<table class="mxchat-table"> |
| 633 |
<thead> |
| 634 |
<tr> |
| 635 |
<th>ID</th> |
| 636 |
<th>Article Content</th> |
| 637 |
<th>URL</th> |
| 638 |
<th>Actions</th> |
| 639 |
</tr> |
| 640 |
</thead> |
| 641 |
<tbody> |
| 642 |
<?php if ($prompts) : ?> |
| 643 |
<?php foreach ($prompts as $prompt) : ?> |
| 644 |
<tr id="prompt-<?php echo esc_attr($prompt->id); ?>"> |
| 645 |
<td><?php echo esc_html($prompt->id); ?></td> |
| 646 |
<td class="mxchat_article_content_dashboard"> |
| 647 |
<span class="content-view"><?php echo wp_kses_post(wpautop(esc_textarea($prompt->article_content))); ?></span> |
| 648 |
<textarea class="content-edit" style="display:none;"><?php echo esc_textarea($prompt->article_content); ?></textarea> |
| 649 |
</td> |
| 650 |
<td class="mxchat_article_url_dashboard"> |
| 651 |
<span class="url-view"> |
| 652 |
<?php if (!empty($prompt->source_url)) : ?> |
| 653 |
<a href="<?php echo esc_url($prompt->source_url); ?>" target="_blank"><?php echo esc_html($prompt->source_url); ?></a> |
| 654 |
<?php else : ?> |
| 655 |
N/A |
| 656 |
<?php endif; ?> |
| 657 |
</span> |
| 658 |
<input type="url" class="url-edit" value="<?php echo esc_attr($prompt->source_url); ?>" style="display:none;" /> |
| 659 |
</td> |
| 660 |
<td> |
| 661 |
<button class="button edit-button" data-id="<?php echo esc_attr($prompt->id); ?>">Edit</button> |
| 662 |
<button class="button save-button" data-id="<?php echo esc_attr($prompt->id); ?>" style="display:none;">Save</button> |
| 663 |
<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'))); ?>" class="button delete-button">Delete</a> |
| 664 |
</td> |
| 665 |
</tr> |
| 666 |
<?php endforeach; ?> |
| 667 |
<?php else : ?> |
| 668 |
<tr> |
| 669 |
<td colspan="4">No prompts found.</td> |
| 670 |
</tr> |
| 671 |
<?php endif; ?> |
| 672 |
</tbody> |
| 673 |
</table> |
| 674 |
|
| 675 |
</div> |
| 676 |
|
| 677 |
<?php |
| 678 |
} |
| 679 |
|
| 680 |
public function mxchat_generate_embedding($text) { |
| 681 |
$options = get_option('mxchat_options'); |
| 682 |
$api_key = $options['api_key'] ?? 'default_api_key'; |
| 683 |
|
| 684 |
$response = wp_remote_post('https://api.openai.com/v1/embeddings', array( |
| 685 |
'body' => wp_json_encode(array( |
| 686 |
'model' => 'text-embedding-ada-002', |
| 687 |
'input' => $text |
| 688 |
)), |
| 689 |
'headers' => array( |
| 690 |
'Authorization' => 'Bearer ' . $api_key, |
| 691 |
'Content-Type' => 'application/json' |
| 692 |
), |
| 693 |
)); |
| 694 |
|
| 695 |
if (is_wp_error($response)) { |
| 696 |
return null; |
| 697 |
} |
| 698 |
|
| 699 |
$response_data = json_decode(wp_remote_retrieve_body($response), true); |
| 700 |
return $response_data['data'][0]['embedding'] ?? null; |
| 701 |
} |
| 702 |
|
| 703 |
public function mxchat_delete_chat_history() { |
| 704 |
if (!current_user_can('manage_options')) { |
| 705 |
echo wp_json_encode(['error' => 'You do not have sufficient permissions.']); |
| 706 |
wp_die(); |
| 707 |
} |
| 708 |
|
| 709 |
check_ajax_referer('mxchat_delete_chat_history', 'security'); |
| 710 |
|
| 711 |
global $wpdb; |
| 712 |
$table_name = $wpdb->prefix . 'mxchat_chat_transcripts'; |
| 713 |
|
| 714 |
if (isset($_POST['delete_session_ids']) && is_array($_POST['delete_session_ids'])) { |
| 715 |
foreach ($_POST['delete_session_ids'] as $session_id) { |
| 716 |
$session_id_sanitized = sanitize_text_field($session_id); |
| 717 |
|
| 718 |
// Clear relevant cache before deletion |
| 719 |
$cache_key = 'chat_session_' . $session_id_sanitized; |
| 720 |
wp_cache_delete($cache_key, 'mxchat_chat_sessions'); |
| 721 |
|
| 722 |
// Perform the deletion |
| 723 |
$wpdb->delete($table_name, ['session_id' => $session_id_sanitized]); |
| 724 |
} |
| 725 |
|
| 726 |
// Optionally, clear a general cache if you have one |
| 727 |
wp_cache_delete('all_chat_sessions', 'mxchat_chat_sessions'); |
| 728 |
|
| 729 |
echo wp_json_encode(['success' => 'Selected chat sessions have been deleted.']); |
| 730 |
} else { |
| 731 |
echo wp_json_encode(['error' => 'No chat sessions selected for deletion.']); |
| 732 |
} |
| 733 |
|
| 734 |
wp_die(); |
| 735 |
} |
| 736 |
|
| 737 |
|
| 738 |
public function mxchat_save_inline_prompt() { |
| 739 |
// Check for nonce security |
| 740 |
check_ajax_referer('mxchat_save_inline_nonce'); |
| 741 |
|
| 742 |
// Verify permissions |
| 743 |
if (!current_user_can('manage_options')) { |
| 744 |
wp_send_json_error('Permission denied.'); |
| 745 |
return; |
| 746 |
} |
| 747 |
|
| 748 |
global $wpdb; |
| 749 |
$table_name = $wpdb->prefix . 'mxchat_system_prompt_content'; |
| 750 |
|
| 751 |
// Validate and sanitize input data |
| 752 |
$prompt_id = isset($_POST['id']) ? absint($_POST['id']) : 0; |
| 753 |
$article_content = isset($_POST['article_content']) ? sanitize_textarea_field($_POST['article_content']) : ''; |
| 754 |
$article_url = isset($_POST['article_url']) ? esc_url_raw($_POST['article_url']) : ''; |
| 755 |
|
| 756 |
if ($prompt_id > 0 && !empty($article_content)) { |
| 757 |
// Re-generate the embedding vector for the updated content |
| 758 |
$embedding_vector = $this->mxchat_generate_embedding($article_content); |
| 759 |
|
| 760 |
if (is_array($embedding_vector)) { |
| 761 |
// Serialize the embedding vector before storing it |
| 762 |
$embedding_vector_serialized = serialize($embedding_vector); |
| 763 |
|
| 764 |
// Update the prompt in the database |
| 765 |
$updated = $wpdb->update( |
| 766 |
$table_name, |
| 767 |
array( |
| 768 |
'article_content' => $article_content, |
| 769 |
'embedding_vector' => $embedding_vector_serialized, |
| 770 |
'source_url' => $article_url, |
| 771 |
), |
| 772 |
array('id' => $prompt_id), |
| 773 |
array('%s', '%s', '%s'), |
| 774 |
array('%d') |
| 775 |
); |
| 776 |
|
| 777 |
if ($updated !== false) { |
| 778 |
wp_send_json_success(); |
| 779 |
} else { |
| 780 |
wp_send_json_error('Database update failed.'); |
| 781 |
} |
| 782 |
} else { |
| 783 |
wp_send_json_error('Embedding generation failed.'); |
| 784 |
} |
| 785 |
} else { |
| 786 |
wp_send_json_error('Invalid data.'); |
| 787 |
} |
| 788 |
} |
| 789 |
|
| 790 |
|
| 791 |
public function mxchat_fetch_chat_history() { |
| 792 |
global $wpdb; |
| 793 |
$table_name = $wpdb->prefix . 'mxchat_chat_transcripts'; |
| 794 |
|
| 795 |
// Check if the current user has sufficient permissions |
| 796 |
if (!current_user_can('manage_options')) { |
| 797 |
echo esc_html__('You do not have sufficient permissions to view this page.', 'mxchat'); |
| 798 |
wp_die(); |
| 799 |
} |
| 800 |
|
| 801 |
// Fetch chat transcripts from the database, ordered by timestamp |
| 802 |
$chat_transcripts = $wpdb->get_results( |
| 803 |
$wpdb->prepare("SELECT * FROM {$table_name} ORDER BY timestamp ASC") |
| 804 |
); |
| 805 |
|
| 806 |
// If no transcripts are available, display a message |
| 807 |
if (empty($chat_transcripts)) { |
| 808 |
echo esc_html__('No chat history available.', 'mxchat'); |
| 809 |
wp_die(); |
| 810 |
} |
| 811 |
|
| 812 |
ob_start(); |
| 813 |
$current_session_id = ''; |
| 814 |
|
| 815 |
foreach ($chat_transcripts as $transcript) { |
| 816 |
// Start a new session block if session ID changes |
| 817 |
if ($current_session_id !== $transcript->session_id) { |
| 818 |
if ($current_session_id !== '') { |
| 819 |
echo '</div>'; // Close the previous session block |
| 820 |
} |
| 821 |
$current_session_id = sanitize_text_field($transcript->session_id); |
| 822 |
echo '<div class="chat-session">'; |
| 823 |
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>'; |
| 824 |
} |
| 825 |
|
| 826 |
// Format the timestamp for display |
| 827 |
$formatted_timestamp = date_i18n('F j, Y g:i a', strtotime($transcript->timestamp)); |
| 828 |
|
| 829 |
// Determine the role to display (user identifier or email for users, bot for the AI) |
| 830 |
$role = $transcript->role; |
| 831 |
if ($role === 'user') { |
| 832 |
// Sanitize email if available |
| 833 |
if (!empty($transcript->user_email)) { |
| 834 |
$role = sanitize_email($transcript->user_email); |
| 835 |
} else { |
| 836 |
// Sanitize user identifier, anonymize if it's an IP address |
| 837 |
$user_identifier = sanitize_text_field($transcript->user_identifier); |
| 838 |
|
| 839 |
// Check if the user identifier is an IP address and anonymize it |
| 840 |
if (filter_var($user_identifier, FILTER_VALIDATE_IP)) { |
| 841 |
$role = preg_replace('/\.\d+$/', '.xxx', $user_identifier); // Mask the last octet |
| 842 |
} else { |
| 843 |
$role = $user_identifier; // If it's not an IP, just display the identifier |
| 844 |
} |
| 845 |
} |
| 846 |
} |
| 847 |
|
| 848 |
// Output the chat message |
| 849 |
echo '<div class="chat-message">'; |
| 850 |
echo '<strong>' . esc_html($role) . ' (' . esc_html($formatted_timestamp) . '):</strong> '; |
| 851 |
echo wp_kses_post($transcript->message); |
| 852 |
echo '</div>'; |
| 853 |
} |
| 854 |
|
| 855 |
// Close the final session block |
| 856 |
echo '</div>'; |
| 857 |
|
| 858 |
$output = ob_get_clean(); |
| 859 |
|
| 860 |
echo $output; |
| 861 |
wp_die(); |
| 862 |
} |
| 863 |
|
| 864 |
|
| 865 |
public function mxchat_create_activation_page() { |
| 866 |
$license_status = get_option('mxchat_license_status', 'inactive'); |
| 867 |
$license_error = get_option('mxchat_license_error', ''); |
| 868 |
|
| 869 |
?> |
| 870 |
<div class="wrap mxchat-admin"> |
| 871 |
<h2>MxChat Pro: Activation</h2> |
| 872 |
<?php if ($license_status === 'inactive' && !empty($license_error)): ?> |
| 873 |
<div class="error notice"> |
| 874 |
<p><?php echo esc_html($license_error); ?></p> |
| 875 |
</div> |
| 876 |
<?php endif; ?> |
| 877 |
<form id="mxchat-activation-form"> |
| 878 |
<table class="form-table"> |
| 879 |
<tr valign="top"> |
| 880 |
<th scope="row">Email Address</th> |
| 881 |
<td> |
| 882 |
<input type="email" id="mxchat_pro_email" name="mxchat_pro_email" value="<?php echo esc_attr(get_option('mxchat_pro_email')); ?>" class="regular-text" /> |
| 883 |
</td> |
| 884 |
</tr> |
| 885 |
<tr valign="top"> |
| 886 |
<th scope="row">Activation Key</th> |
| 887 |
<td> |
| 888 |
<input type="text" id="mxchat_activation_key" name="mxchat_activation_key" value="<?php echo esc_attr(get_option('mxchat_activation_key')); ?>" class="regular-text" /> |
| 889 |
</td> |
| 890 |
</tr> |
| 891 |
</table> |
| 892 |
<?php if ($license_status !== 'active'): ?> |
| 893 |
<?php submit_button('Activate License', 'primary', 'activate_license'); ?> |
| 894 |
<?php else: ?> |
| 895 |
<h3>MxChat Pro</h3> |
| 896 |
<?php endif; ?> |
| 897 |
</form> |
| 898 |
<h3>License Status: <span id="mxchat-license-status"><?php echo $license_status === 'active' ? 'Active' : 'Inactive'; ?></span></h3> |
| 899 |
</div> |
| 900 |
<?php |
| 901 |
} |
| 902 |
|
| 903 |
public function mxchat_intents_page_html() { |
| 904 |
if (!current_user_can('manage_options')) { |
| 905 |
return; |
| 906 |
} |
| 907 |
|
| 908 |
// Handle form submissions |
| 909 |
if (isset($_POST['mxchat_add_intent']) && check_admin_referer('mxchat_add_intent_nonce')) { |
| 910 |
$this->mxchat_handle_add_intent(); |
| 911 |
} elseif (isset($_POST['mxchat_delete_intent']) && check_admin_referer('mxchat_delete_intent_nonce')) { |
| 912 |
$this->mxchat_handle_delete_intent(); |
| 913 |
} |
| 914 |
|
| 915 |
// Fetch existing intents with pagination and filtering |
| 916 |
global $wpdb; |
| 917 |
$table_name = $wpdb->prefix . 'mxchat_intents'; |
| 918 |
$page = isset($_GET['paged']) ? max(1, intval($_GET['paged'])) : 1; |
| 919 |
$per_page = 20; |
| 920 |
$offset = ($page - 1) * $per_page; |
| 921 |
|
| 922 |
// Build the WHERE clause based on filters |
| 923 |
$where = '1=1'; |
| 924 |
$search_term = isset($_GET['s']) ? trim($_GET['s']) : ''; |
| 925 |
$callback_filter = isset($_GET['callback_filter']) ? sanitize_text_field($_GET['callback_filter']) : ''; |
| 926 |
|
| 927 |
if ($search_term) { |
| 928 |
$search_term_like = '%' . $wpdb->esc_like($search_term) . '%'; |
| 929 |
$where .= $wpdb->prepare(' AND (intent_label LIKE %s OR phrases LIKE %s)', $search_term_like, $search_term_like); |
| 930 |
} |
| 931 |
|
| 932 |
if ($callback_filter) { |
| 933 |
$where .= $wpdb->prepare(' AND callback_function = %s', $callback_filter); |
| 934 |
} |
| 935 |
|
| 936 |
// Get total count for pagination |
| 937 |
$total_intents = $wpdb->get_var("SELECT COUNT(*) FROM $table_name WHERE $where"); |
| 938 |
$total_pages = ceil($total_intents / $per_page); |
| 939 |
|
| 940 |
// Fetch intents with pagination and filters |
| 941 |
$intents = $wpdb->get_results($wpdb->prepare("SELECT * FROM $table_name WHERE $where LIMIT %d OFFSET %d", $per_page, $offset)); |
| 942 |
|
| 943 |
// Get available callback functions with 'pro_only' flag |
| 944 |
$available_callbacks = $this->mxchat_get_available_callbacks(); |
| 945 |
|
| 946 |
?> |
| 947 |
|
| 948 |
<div class="wrap mxchat-admin"> |
| 949 |
<form method="post"> |
| 950 |
<?php wp_nonce_field('mxchat_add_intent_nonce'); ?> |
| 951 |
<h2><?php esc_html_e('Add New Intent', 'mxchat'); ?></h2> |
| 952 |
<!-- Documentation encouragement message --> |
| 953 |
<p class="description"> |
| 954 |
<?php esc_html_e('We highly encourage users to quickly read our ', 'mxchat'); ?> |
| 955 |
<a href="https://mxchat.ai/documentation/#intents" target="_blank" rel="noopener noreferrer"> |
| 956 |
<?php esc_html_e('documentation', 'mxchat'); ?> |
| 957 |
</a> |
| 958 |
<?php esc_html_e(' to better understand intents. Some intents require setup in the Integration tab.', 'mxchat'); ?> |
| 959 |
</p> |
| 960 |
|
| 961 |
<div class="mxchat-form-group"> |
| 962 |
<label for="intent_label"><?php esc_html_e('Intent Label', 'mxchat'); ?></label> |
| 963 |
<input name="intent_label" type="text" id="intent_label" class="regular-text" required> |
| 964 |
</div> |
| 965 |
<div class="mxchat-form-group"> |
| 966 |
<label for="phrases"><?php esc_html_e('Phrases (comma-separated)', 'mxchat'); ?></label> |
| 967 |
<textarea name="phrases" id="phrases" rows="5" class="large-text" required></textarea> |
| 968 |
</div> |
| 969 |
<div class="mxchat-form-group"> |
| 970 |
<label for="callback_function"><?php esc_html_e('Callback Function', 'mxchat'); ?></label> |
| 971 |
<select name="callback_function" id="callback_function" required> |
| 972 |
<option value=""><?php esc_html_e('Select a Callback', 'mxchat'); ?></option> |
| 973 |
<?php foreach ($available_callbacks as $function => $callback_data): ?> |
| 974 |
<?php |
| 975 |
$label = $callback_data['label']; |
| 976 |
$pro_only = $callback_data['pro_only']; |
| 977 |
// Disable if intent is Pro-only and user is not activated |
| 978 |
$disabled = (!$this->is_activated && $pro_only) ? 'disabled' : ''; |
| 979 |
$label_suffix = (!$this->is_activated && $pro_only) ? ' (Pro Only)' : ''; |
| 980 |
?> |
| 981 |
<option value="<?php echo esc_attr($function); ?>" <?php echo $disabled; ?>> |
| 982 |
<?php echo esc_html($label . $label_suffix); ?> |
| 983 |
</option> |
| 984 |
<?php endforeach; ?> |
| 985 |
</select> |
| 986 |
</div> |
| 987 |
<button type="submit" name="mxchat_add_intent" class="button button-primary submit-content-button"> |
| 988 |
<?php esc_html_e('Add Intent', 'mxchat'); ?> |
| 989 |
</button> |
| 990 |
|
| 991 |
<!-- Loader and loading text (initially hidden) --> |
| 992 |
<div id="mxchat-intent-loading" class="mxchat-spinner" style="display: none;"></div> |
| 993 |
<div id="mxchat-loading-text-intent" style="display: none; margin-top: 10px; color: #333;"> |
| 994 |
<?php esc_html_e('Loading, please wait...', 'mxchat'); ?> |
| 995 |
</div> |
| 996 |
</form> |
| 997 |
|
| 998 |
<!-- Filter Form --> |
| 999 |
<form method="get" action=""> |
| 1000 |
<input type="hidden" name="page" value="mxchat-intents"> |
| 1001 |
<div class="mxchat-search-group"> |
| 1002 |
<input type="text" name="s" id="mxchat-intent-search" placeholder="<?php esc_attr_e('Search Intents', 'mxchat'); ?>" value="<?php echo esc_attr($search_term); ?>"> |
| 1003 |
<select name="callback_filter" id="mxchat-callback-filter"> |
| 1004 |
<option value=""><?php esc_html_e('All Callbacks', 'mxchat'); ?></option> |
| 1005 |
<?php foreach ($available_callbacks as $function => $callback_data): ?> |
| 1006 |
<?php $label = $callback_data['label']; ?> |
| 1007 |
<option value="<?php echo esc_attr($function); ?>" <?php selected($callback_filter, $function); ?>><?php echo esc_html($label); ?></option> |
| 1008 |
<?php endforeach; ?> |
| 1009 |
</select> |
| 1010 |
<button type="submit" class="button"><?php esc_html_e('Filter', 'mxchat'); ?></button> |
| 1011 |
</div> |
| 1012 |
</form> |
| 1013 |
|
| 1014 |
<!-- Intents Table --> |
| 1015 |
<table class="wp-list-table mxchat-table widefat fixed striped"> |
| 1016 |
<thead> |
| 1017 |
<tr> |
| 1018 |
<th><?php esc_html_e('Intent Label', 'mxchat'); ?></th> |
| 1019 |
<th><?php esc_html_e('Phrases', 'mxchat'); ?></th> |
| 1020 |
<th><?php esc_html_e('Callback Function', 'mxchat'); ?></th> |
| 1021 |
<th><?php esc_html_e('Actions', 'mxchat'); ?></th> |
| 1022 |
</tr> |
| 1023 |
</thead> |
| 1024 |
<tbody> |
| 1025 |
<?php if ($intents): ?> |
| 1026 |
<?php foreach ($intents as $intent): ?> |
| 1027 |
<?php |
| 1028 |
$callback_function = $intent->callback_function; |
| 1029 |
$callback_label = isset($available_callbacks[$callback_function]['label']) ? $available_callbacks[$callback_function]['label'] : $callback_function; |
| 1030 |
?> |
| 1031 |
<tr> |
| 1032 |
<td><?php echo esc_html($intent->intent_label); ?></td> |
| 1033 |
<td><?php echo esc_html($intent->phrases); ?></td> |
| 1034 |
<td><?php echo esc_html($callback_label); ?></td> |
| 1035 |
<td> |
| 1036 |
<form method="post" onsubmit="return confirm('<?php esc_attr_e('Are you sure you want to delete this intent?', 'mxchat'); ?>');"> |
| 1037 |
<?php wp_nonce_field('mxchat_delete_intent_nonce'); ?> |
| 1038 |
<input type="hidden" name="intent_id" value="<?php echo esc_attr($intent->id); ?>"> |
| 1039 |
<button type="submit" name="mxchat_delete_intent" class="button button-secondary"><?php esc_html_e('Delete', 'mxchat'); ?></button> |
| 1040 |
</form> |
| 1041 |
</td> |
| 1042 |
</tr> |
| 1043 |
<?php endforeach; ?> |
| 1044 |
<?php else: ?> |
| 1045 |
<tr> |
| 1046 |
<td colspan="4"><?php esc_html_e('No intents found.', 'mxchat'); ?></td> |
| 1047 |
</tr> |
| 1048 |
<?php endif; ?> |
| 1049 |
</tbody> |
| 1050 |
</table> |
| 1051 |
|
| 1052 |
<!-- Pagination Links --> |
| 1053 |
<?php if ($total_pages > 1): ?> |
| 1054 |
<div class="pagination mxchat-pagination"> |
| 1055 |
<?php |
| 1056 |
$base_url = admin_url('admin.php?page=mxchat-intents'); |
| 1057 |
$query_args = []; |
| 1058 |
if ($search_term) { |
| 1059 |
$query_args['s'] = $search_term; |
| 1060 |
} |
| 1061 |
if ($callback_filter) { |
| 1062 |
$query_args['callback_filter'] = $callback_filter; |
| 1063 |
} |
| 1064 |
|
| 1065 |
for ($i = 1; $i <= $total_pages; $i++): |
| 1066 |
$query_args['paged'] = $i; |
| 1067 |
$page_url = add_query_arg($query_args, $base_url); |
| 1068 |
?> |
| 1069 |
<a href="<?php echo esc_url($page_url); ?>" class="page-number <?php if ($i == $page) echo 'current-page'; ?>"><?php echo $i; ?></a> |
| 1070 |
<?php endfor; ?> |
| 1071 |
</div> |
| 1072 |
<?php endif; ?> |
| 1073 |
|
| 1074 |
</div> |
| 1075 |
|
| 1076 |
<?php |
| 1077 |
} |
| 1078 |
|
| 1079 |
public function mxchat_handle_add_intent() { |
| 1080 |
ob_start(); // Start output buffering |
| 1081 |
|
| 1082 |
check_admin_referer('mxchat_add_intent_nonce'); |
| 1083 |
|
| 1084 |
global $wpdb; |
| 1085 |
$table_name = $wpdb->prefix . 'mxchat_intents'; |
| 1086 |
|
| 1087 |
// Get the form input |
| 1088 |
$intent_label = isset($_POST['intent_label']) ? sanitize_text_field($_POST['intent_label']) : ''; |
| 1089 |
$phrases_input = isset($_POST['phrases']) ? $_POST['phrases'] : ''; |
| 1090 |
$callback_function = isset($_POST['callback_function']) ? sanitize_text_field($_POST['callback_function']) : ''; |
| 1091 |
|
| 1092 |
if (empty($intent_label) || empty($callback_function) || empty($phrases_input)) { |
| 1093 |
ob_end_clean(); // End output buffering and discard output |
| 1094 |
wp_die(esc_html__('Invalid input. Please ensure all fields are filled out.', 'mxchat')); |
| 1095 |
} |
| 1096 |
|
| 1097 |
// Get available callback functions |
| 1098 |
$available_callbacks = $this->mxchat_get_available_callbacks(); |
| 1099 |
|
| 1100 |
// Validate callback function |
| 1101 |
if (!array_key_exists($callback_function, $available_callbacks)) { |
| 1102 |
ob_end_clean(); // End output buffering and discard output |
| 1103 |
wp_die(esc_html__('Invalid callback function selected.', 'mxchat')); |
| 1104 |
} |
| 1105 |
|
| 1106 |
// Check if the callback is Pro-only and the user is not activated |
| 1107 |
$is_pro_only = $available_callbacks[$callback_function]['pro_only']; |
| 1108 |
if ($is_pro_only && !$this->is_activated) { |
| 1109 |
ob_end_clean(); // End output buffering and discard output |
| 1110 |
wp_die(esc_html__('This callback function is available in the Pro version only.', 'mxchat')); |
| 1111 |
} |
| 1112 |
|
| 1113 |
// Split and sanitize phrases |
| 1114 |
$phrases_array = array_map('trim', explode(',', $phrases_input)); |
| 1115 |
$phrases_array = array_filter($phrases_array); // Remove empty phrases |
| 1116 |
$phrases_array = array_map('sanitize_text_field', $phrases_array); |
| 1117 |
|
| 1118 |
if (empty($phrases_array)) { |
| 1119 |
ob_end_clean(); // End output buffering and discard output |
| 1120 |
wp_die(esc_html__('Please enter at least one valid phrase.', 'mxchat')); |
| 1121 |
} |
| 1122 |
|
| 1123 |
// Generate and collect embeddings for each phrase |
| 1124 |
$vectors = []; |
| 1125 |
foreach ($phrases_array as $phrase) { |
| 1126 |
$embedding_vector = $this->mxchat_generate_embedding($phrase, $this->options['api_key']); |
| 1127 |
if (is_array($embedding_vector)) { |
| 1128 |
$vectors[] = $embedding_vector; |
| 1129 |
} else { |
| 1130 |
ob_end_clean(); // End output buffering and discard output |
| 1131 |
wp_die(esc_html__('Error generating embedding for phrase: ', 'mxchat') . esc_html($phrase)); |
| 1132 |
} |
| 1133 |
} |
| 1134 |
|
| 1135 |
// Average the vectors to create a single embedding vector for the intent |
| 1136 |
if (!empty($vectors)) { |
| 1137 |
$combined_vector = $this->mxchat_average_vectors($vectors); |
| 1138 |
$serialized_vector = maybe_serialize($combined_vector); |
| 1139 |
|
| 1140 |
// Insert the combined vector as a single entry for the intent |
| 1141 |
$result = $wpdb->insert($table_name, [ |
| 1142 |
'intent_label' => $intent_label, |
| 1143 |
'phrases' => implode(', ', $phrases_array), |
| 1144 |
'embedding_vector' => $serialized_vector, |
| 1145 |
'callback_function' => $callback_function, |
| 1146 |
]); |
| 1147 |
|
| 1148 |
if ($result === false) { |
| 1149 |
ob_end_clean(); // End output buffering and discard output |
| 1150 |
wp_die(esc_html__('Database error: ', 'mxchat') . esc_html($wpdb->last_error)); |
| 1151 |
} |
| 1152 |
|
| 1153 |
ob_end_clean(); // End output buffering and discard output |
| 1154 |
|
| 1155 |
// Set a transient to handle the redirect after output processing |
| 1156 |
set_transient('mxchat_intent_added_redirect', true, 5 * MINUTE_IN_SECONDS); |
| 1157 |
return; // Stop the function without a redirect |
| 1158 |
} else { |
| 1159 |
ob_end_clean(); // End output buffering and discard output |
| 1160 |
wp_die(esc_html__('No valid embeddings generated. Please check your phrases.', 'mxchat')); |
| 1161 |
} |
| 1162 |
} |
| 1163 |
|
| 1164 |
|
| 1165 |
|
| 1166 |
private function mxchat_get_available_callbacks() { |
| 1167 |
return [ |
| 1168 |
'mxchat_handle_email_capture' => [ |
| 1169 |
'label' => 'Email Capture', |
| 1170 |
'pro_only' => false, |
| 1171 |
], |
| 1172 |
'mxchat_handle_product_inquiry' => [ |
| 1173 |
'label' => 'Show Product Card', |
| 1174 |
'pro_only' => true, |
| 1175 |
], |
| 1176 |
'mxchat_handle_order_history' => [ |
| 1177 |
'label' => 'Order History', |
| 1178 |
'pro_only' => true, |
| 1179 |
], |
| 1180 |
'mxchat_generate_image' => [ |
| 1181 |
'label' => 'Generate Image', |
| 1182 |
'pro_only' => true, |
| 1183 |
], |
| 1184 |
'mxchat_handle_search_request' => [ |
| 1185 |
'label' => 'Brave Web Search', |
| 1186 |
'pro_only' => false, |
| 1187 |
], |
| 1188 |
'mxchat_handle_image_search_request' => [ |
| 1189 |
'label' => 'Brave Image Search', |
| 1190 |
'pro_only' => false, |
| 1191 |
], |
| 1192 |
'mxchat_handle_add_to_cart_intent' => [ |
| 1193 |
'label' => 'Add to Cart', |
| 1194 |
'pro_only' => true, |
| 1195 |
], |
| 1196 |
'mxchat_handle_checkout_intent' => [ |
| 1197 |
'label' => 'Proceed to Checkout', |
| 1198 |
'pro_only' => true, |
| 1199 |
], |
| 1200 |
]; |
| 1201 |
} |
| 1202 |
|
| 1203 |
|
| 1204 |
private function mxchat_average_vectors($vectors) { |
| 1205 |
$vector_length = count($vectors[0]); |
| 1206 |
$sum_vector = array_fill(0, $vector_length, 0); |
| 1207 |
|
| 1208 |
foreach ($vectors as $vector) { |
| 1209 |
for ($i = 0; $i < $vector_length; $i++) { |
| 1210 |
$sum_vector[$i] += $vector[$i]; |
| 1211 |
} |
| 1212 |
} |
| 1213 |
|
| 1214 |
// Divide each component by the number of vectors to get the average |
| 1215 |
$num_vectors = count($vectors); |
| 1216 |
for ($i = 0; $i < $vector_length; $i++) { |
| 1217 |
$sum_vector[$i] /= $num_vectors; |
| 1218 |
} |
| 1219 |
|
| 1220 |
return $sum_vector; |
| 1221 |
} |
| 1222 |
|
| 1223 |
public function mxchat_handle_delete_intent() { |
| 1224 |
check_admin_referer('mxchat_delete_intent_nonce'); |
| 1225 |
|
| 1226 |
if (isset($_POST['intent_id'])) { |
| 1227 |
global $wpdb; |
| 1228 |
$table_name = $wpdb->prefix . 'mxchat_intents'; |
| 1229 |
$intent_id = intval($_POST['intent_id']); |
| 1230 |
|
| 1231 |
// Delete the intent from the database |
| 1232 |
$wpdb->delete($table_name, ['id' => $intent_id], ['%d']); |
| 1233 |
} |
| 1234 |
} |
| 1235 |
|
| 1236 |
public function mxchat_page_init() { |
| 1237 |
// Register settings |
| 1238 |
register_setting( |
| 1239 |
'mxchat_option_group', |
| 1240 |
'mxchat_options', |
| 1241 |
array($this, 'mxchat_sanitize') |
| 1242 |
); |
| 1243 |
|
| 1244 |
// Chatbot Settings Section |
| 1245 |
add_settings_section( |
| 1246 |
'mxchat_chatbot_section', |
| 1247 |
'Chatbot Settings', |
| 1248 |
null, |
| 1249 |
'mxchat-chatbot' |
| 1250 |
); |
| 1251 |
|
| 1252 |
// Registering fields for the Chatbot Settings section |
| 1253 |
add_settings_field( |
| 1254 |
'api_key', |
| 1255 |
'OpenAI API Key', |
| 1256 |
array($this, 'api_key_callback'), |
| 1257 |
'mxchat-chatbot', |
| 1258 |
'mxchat_chatbot_section' |
| 1259 |
); |
| 1260 |
|
| 1261 |
add_settings_field( |
| 1262 |
'xai_api_key', |
| 1263 |
'X.AI API Key', |
| 1264 |
array($this, 'xai_api_key_callback'), |
| 1265 |
'mxchat-chatbot', |
| 1266 |
'mxchat_chatbot_section' |
| 1267 |
); |
| 1268 |
|
| 1269 |
add_settings_field( |
| 1270 |
'claude_api_key', |
| 1271 |
'Claude API Key', |
| 1272 |
array($this, 'claude_api_key_callback'), |
| 1273 |
'mxchat-chatbot', |
| 1274 |
'mxchat_chatbot_section' |
| 1275 |
); |
| 1276 |
|
| 1277 |
|
| 1278 |
add_settings_field( |
| 1279 |
'system_prompt_instructions', |
| 1280 |
'AI Instructions', |
| 1281 |
array($this, 'system_prompt_instructions_callback'), |
| 1282 |
'mxchat-chatbot', |
| 1283 |
'mxchat_chatbot_section' |
| 1284 |
); |
| 1285 |
|
| 1286 |
add_settings_field( |
| 1287 |
'model', |
| 1288 |
'Model', |
| 1289 |
array($this, 'mxchat_model_callback'), |
| 1290 |
'mxchat-chatbot', |
| 1291 |
'mxchat_chatbot_section' |
| 1292 |
); |
| 1293 |
|
| 1294 |
add_settings_field( |
| 1295 |
'top_bar_title', |
| 1296 |
'Top Bar Title', |
| 1297 |
array($this, 'mxchat_top_bar_title_callback'), |
| 1298 |
'mxchat-chatbot', |
| 1299 |
'mxchat_chatbot_section' |
| 1300 |
); |
| 1301 |
|
| 1302 |
add_settings_field( |
| 1303 |
'intro_message', |
| 1304 |
'Introductory Message', |
| 1305 |
array($this, 'mxchat_intro_message_callback'), |
| 1306 |
'mxchat-chatbot', |
| 1307 |
'mxchat_chatbot_section' |
| 1308 |
); |
| 1309 |
|
| 1310 |
add_settings_field( |
| 1311 |
'input_copy', |
| 1312 |
'Input Copy', |
| 1313 |
array($this, 'mxchat_input_copy_callback'), |
| 1314 |
'mxchat-chatbot', |
| 1315 |
'mxchat_chatbot_section' |
| 1316 |
); |
| 1317 |
|
| 1318 |
add_settings_field( |
| 1319 |
'rate_limit', |
| 1320 |
'Rate Limit', |
| 1321 |
array($this, 'mxchat_rate_limit_callback'), |
| 1322 |
'mxchat-chatbot', |
| 1323 |
'mxchat_chatbot_section' |
| 1324 |
); |
| 1325 |
|
| 1326 |
add_settings_field( |
| 1327 |
'rate_limit_message', |
| 1328 |
'Rate Limit Message', |
| 1329 |
array($this, 'mxchat_rate_limit_message_callback'), |
| 1330 |
'mxchat-chatbot', |
| 1331 |
'mxchat_chatbot_section' |
| 1332 |
); |
| 1333 |
|
| 1334 |
add_settings_field( |
| 1335 |
'pre_chat_message', |
| 1336 |
'Pre-Chat Message', |
| 1337 |
array($this, 'mxchat_pre_chat_message_callback'), |
| 1338 |
'mxchat-chatbot', |
| 1339 |
'mxchat_chatbot_section' |
| 1340 |
); |
| 1341 |
|
| 1342 |
add_settings_field( |
| 1343 |
'append_to_body', |
| 1344 |
'Append Chat Widget to Body', |
| 1345 |
array($this, 'mxchat_append_to_body_callback'), |
| 1346 |
'mxchat-chatbot', |
| 1347 |
'mxchat_chatbot_section' |
| 1348 |
); |
| 1349 |
|
| 1350 |
add_settings_field( |
| 1351 |
'privacy_toggle', |
| 1352 |
'Toggle Privacy Notice', |
| 1353 |
array($this, 'mxchat_privacy_toggle_callback'), |
| 1354 |
'mxchat-chatbot', |
| 1355 |
'mxchat_chatbot_section' |
| 1356 |
); |
| 1357 |
|
| 1358 |
add_settings_field( |
| 1359 |
'complianz_toggle', |
| 1360 |
'Enable Complianz', |
| 1361 |
array($this, 'mxchat_complianz_toggle_callback'), |
| 1362 |
'mxchat-chatbot', |
| 1363 |
'mxchat_chatbot_section' |
| 1364 |
); |
| 1365 |
|
| 1366 |
add_settings_field( |
| 1367 |
'link_target_toggle', |
| 1368 |
'Open Links in a New Tab', |
| 1369 |
array($this, 'mxchat_link_target_toggle_callback'), |
| 1370 |
'mxchat-chatbot', |
| 1371 |
'mxchat_chatbot_section' |
| 1372 |
); |
| 1373 |
|
| 1374 |
add_settings_field( |
| 1375 |
'chat_persistence_toggle', |
| 1376 |
'Enable Chat Persistence', |
| 1377 |
array($this, 'mxchat_chat_persistence_toggle_callback'), |
| 1378 |
'mxchat-chatbot', |
| 1379 |
'mxchat_chatbot_section' |
| 1380 |
); |
| 1381 |
|
| 1382 |
add_settings_field( |
| 1383 |
'popular_question_1', |
| 1384 |
'Popular Question 1', |
| 1385 |
array($this, 'mxchat_popular_question_1_callback'), |
| 1386 |
'mxchat-chatbot', |
| 1387 |
'mxchat_chatbot_section' |
| 1388 |
); |
| 1389 |
|
| 1390 |
add_settings_field( |
| 1391 |
'popular_question_2', |
| 1392 |
'Popular Question 2', |
| 1393 |
array($this, 'mxchat_popular_question_2_callback'), |
| 1394 |
'mxchat-chatbot', |
| 1395 |
'mxchat_chatbot_section' |
| 1396 |
); |
| 1397 |
|
| 1398 |
add_settings_field( |
| 1399 |
'popular_question_3', |
| 1400 |
'Popular Question 3', |
| 1401 |
array($this, 'mxchat_popular_question_3_callback'), |
| 1402 |
'mxchat-chatbot', |
| 1403 |
'mxchat_chatbot_section' |
| 1404 |
); |
| 1405 |
|
| 1406 |
|
| 1407 |
|
| 1408 |
// WooCommerce Settings Section |
| 1409 |
add_settings_section( |
| 1410 |
'mxchat_woocommerce_section', |
| 1411 |
'WooCommerce Settings', |
| 1412 |
null, |
| 1413 |
'mxchat-embed' |
| 1414 |
); |
| 1415 |
|
| 1416 |
// Loops Settings Section |
| 1417 |
add_settings_section( |
| 1418 |
'mxchat_loops_section', |
| 1419 |
'Loops Settings', |
| 1420 |
null, |
| 1421 |
'mxchat-embed' |
| 1422 |
); |
| 1423 |
|
| 1424 |
// WooCommerce Settings Fields |
| 1425 |
add_settings_field( |
| 1426 |
'enable_woocommerce_integration', |
| 1427 |
'Automatically Embed Products', |
| 1428 |
array($this, 'mxchat_enable_woocommerce_integration_callback'), |
| 1429 |
'mxchat-embed', |
| 1430 |
'mxchat_woocommerce_section' |
| 1431 |
); |
| 1432 |
|
| 1433 |
|
| 1434 |
add_settings_field( |
| 1435 |
'woocommerce_consumer_key', |
| 1436 |
'WooCommerce Consumer Key', |
| 1437 |
array($this, 'mxchat_woocommerce_consumer_key_callback'), |
| 1438 |
'mxchat-embed', |
| 1439 |
'mxchat_woocommerce_section' |
| 1440 |
); |
| 1441 |
|
| 1442 |
add_settings_field( |
| 1443 |
'woocommerce_consumer_secret', |
| 1444 |
'WooCommerce Consumer Secret', |
| 1445 |
array($this, 'mxchat_woocommerce_consumer_secret_callback'), |
| 1446 |
'mxchat-embed', |
| 1447 |
'mxchat_woocommerce_section' |
| 1448 |
); |
| 1449 |
|
| 1450 |
// Loops Settings Fields |
| 1451 |
add_settings_field( |
| 1452 |
'loops_api_key', |
| 1453 |
'Loops API Key', |
| 1454 |
array($this, 'mxchat_loops_api_key_callback'), |
| 1455 |
'mxchat-embed', |
| 1456 |
'mxchat_loops_section' |
| 1457 |
); |
| 1458 |
|
| 1459 |
add_settings_field( |
| 1460 |
'loops_mailing_list', |
| 1461 |
'Loops Mailing List', |
| 1462 |
array($this, 'mxchat_loops_mailing_list_callback'), |
| 1463 |
'mxchat-embed', |
| 1464 |
'mxchat_loops_section' |
| 1465 |
); |
| 1466 |
|
| 1467 |
add_settings_field( |
| 1468 |
'triggered_phrase_response', |
| 1469 |
'Triggered Phrase Response', |
| 1470 |
array($this, 'mxchat_triggered_phrase_response_callback'), |
| 1471 |
'mxchat-embed', |
| 1472 |
'mxchat_loops_section' |
| 1473 |
); |
| 1474 |
|
| 1475 |
add_settings_field( |
| 1476 |
'email_capture_response', |
| 1477 |
'Email Capture Response', |
| 1478 |
array($this, 'mxchat_email_capture_response_callback'), |
| 1479 |
'mxchat-embed', |
| 1480 |
'mxchat_loops_section' |
| 1481 |
); |
| 1482 |
|
| 1483 |
|
| 1484 |
// Brave Search Settings Fields |
| 1485 |
add_settings_section( |
| 1486 |
'mxchat_brave_section', |
| 1487 |
__('Brave Search Settings', 'mxchat'), |
| 1488 |
array($this, 'mxchat_brave_section_callback'), |
| 1489 |
'mxchat-embed' |
| 1490 |
); |
| 1491 |
|
| 1492 |
add_settings_field( |
| 1493 |
'brave_api_key', |
| 1494 |
__('Brave API Key', 'mxchat'), |
| 1495 |
array($this, 'mxchat_brave_api_key_callback'), |
| 1496 |
'mxchat-embed', |
| 1497 |
'mxchat_brave_section' |
| 1498 |
); |
| 1499 |
|
| 1500 |
add_settings_field( |
| 1501 |
'brave_image_count', |
| 1502 |
__('Number of Images to Return', 'mxchat'), |
| 1503 |
array($this, 'mxchat_brave_image_count_callback'), |
| 1504 |
'mxchat-embed', |
| 1505 |
'mxchat_brave_section' |
| 1506 |
); |
| 1507 |
|
| 1508 |
add_settings_field( |
| 1509 |
'brave_safe_search', |
| 1510 |
__('Safe Search', 'mxchat'), |
| 1511 |
array($this, 'mxchat_brave_safe_search_callback'), |
| 1512 |
'mxchat-embed', |
| 1513 |
'mxchat_brave_section' |
| 1514 |
); |
| 1515 |
|
| 1516 |
add_settings_field( |
| 1517 |
'brave_news_count', |
| 1518 |
__('Number of News Articles', 'mxchat'), |
| 1519 |
array($this, 'mxchat_brave_news_count_callback'), |
| 1520 |
'mxchat-embed', |
| 1521 |
'mxchat_brave_section' |
| 1522 |
); |
| 1523 |
|
| 1524 |
add_settings_field( |
| 1525 |
'brave_country', |
| 1526 |
__('Country', 'mxchat'), |
| 1527 |
array($this, 'mxchat_brave_country_callback'), |
| 1528 |
'mxchat-embed', |
| 1529 |
'mxchat_brave_section' |
| 1530 |
); |
| 1531 |
|
| 1532 |
add_settings_field( |
| 1533 |
'brave_language', |
| 1534 |
__('Language', 'mxchat'), |
| 1535 |
array($this, 'mxchat_brave_language_callback'), |
| 1536 |
'mxchat-embed', |
| 1537 |
'mxchat_brave_section' |
| 1538 |
); |
| 1539 |
|
| 1540 |
|
| 1541 |
|
| 1542 |
// Theme Settings Section |
| 1543 |
add_settings_section( |
| 1544 |
'mxchat_theme_section', |
| 1545 |
'Theme Settings', |
| 1546 |
null, |
| 1547 |
'mxchat-theme' |
| 1548 |
); |
| 1549 |
|
| 1550 |
add_settings_field( |
| 1551 |
'close_button_color', |
| 1552 |
'Close Button & Title Color', |
| 1553 |
array($this, 'mxchat_close_button_color_callback'), |
| 1554 |
'mxchat-theme', |
| 1555 |
'mxchat_theme_section' |
| 1556 |
); |
| 1557 |
|
| 1558 |
add_settings_field( |
| 1559 |
'chatbot_bg_color', |
| 1560 |
'Chatbot Background Color', |
| 1561 |
array($this, 'mxchat_chatbot_bg_color_callback'), |
| 1562 |
'mxchat-theme', |
| 1563 |
'mxchat_theme_section' |
| 1564 |
); |
| 1565 |
|
| 1566 |
add_settings_field( |
| 1567 |
'user_message_bg_color', |
| 1568 |
'User Message Background Color', |
| 1569 |
array($this, 'mxchat_user_message_bg_color_callback'), |
| 1570 |
'mxchat-theme', |
| 1571 |
'mxchat_theme_section' |
| 1572 |
); |
| 1573 |
|
| 1574 |
add_settings_field( |
| 1575 |
'user_message_font_color', |
| 1576 |
'User Message Font Color', |
| 1577 |
array($this, 'mxchat_user_message_font_color_callback'), |
| 1578 |
'mxchat-theme', |
| 1579 |
'mxchat_theme_section' |
| 1580 |
); |
| 1581 |
|
| 1582 |
add_settings_field( |
| 1583 |
'bot_message_bg_color', |
| 1584 |
'Bot Message Background Color', |
| 1585 |
array($this, 'mxchat_bot_message_bg_color_callback'), |
| 1586 |
'mxchat-theme', |
| 1587 |
'mxchat_theme_section' |
| 1588 |
); |
| 1589 |
|
| 1590 |
add_settings_field( |
| 1591 |
'bot_message_font_color', |
| 1592 |
'Bot Message Font Color', |
| 1593 |
array($this, 'mxchat_bot_message_font_color_callback'), |
| 1594 |
'mxchat-theme', |
| 1595 |
'mxchat_theme_section' |
| 1596 |
); |
| 1597 |
|
| 1598 |
add_settings_field( |
| 1599 |
'top_bar_bg_color', |
| 1600 |
'Top Bar Background Color', |
| 1601 |
array($this, 'mxchat_top_bar_bg_color_callback'), |
| 1602 |
'mxchat-theme', |
| 1603 |
'mxchat_theme_section' |
| 1604 |
); |
| 1605 |
|
| 1606 |
add_settings_field( |
| 1607 |
'send_button_font_color', |
| 1608 |
'Send Button Color', |
| 1609 |
array($this, 'mxchat_send_button_font_color_callback'), |
| 1610 |
'mxchat-theme', |
| 1611 |
'mxchat_theme_section' |
| 1612 |
); |
| 1613 |
|
| 1614 |
add_settings_field( |
| 1615 |
'chat_input_font_color', |
| 1616 |
'Chat Input Font Color', |
| 1617 |
array($this, 'mxchat_chat_input_font_color_callback'), |
| 1618 |
'mxchat-theme', |
| 1619 |
'mxchat_theme_section' |
| 1620 |
); |
| 1621 |
|
| 1622 |
add_settings_field( |
| 1623 |
'chatbot_background_color', |
| 1624 |
'Floating Widget Background Color', |
| 1625 |
array($this, 'mxchat_chatbot_background_color_callback'), |
| 1626 |
'mxchat-theme', |
| 1627 |
'mxchat_theme_section' |
| 1628 |
); |
| 1629 |
|
| 1630 |
add_settings_field( |
| 1631 |
'icon_color', |
| 1632 |
'Chatbot Icon Color', |
| 1633 |
array($this, 'mxchat_icon_color_callback'), |
| 1634 |
'mxchat-theme', |
| 1635 |
'mxchat_theme_section' |
| 1636 |
); |
| 1637 |
|
| 1638 |
// General Settings Section |
| 1639 |
add_settings_section( |
| 1640 |
'mxchat_general_section', |
| 1641 |
'Frequently Asked Questions (FAQ)', |
| 1642 |
null, |
| 1643 |
'mxchat-general' |
| 1644 |
); |
| 1645 |
|
| 1646 |
|
| 1647 |
} |
| 1648 |
|
| 1649 |
public function mxchat_handle_activate_license() { |
| 1650 |
check_ajax_referer('mxchat_activate_license_nonce', 'security'); |
| 1651 |
|
| 1652 |
$license_key = isset($_POST['key']) ? sanitize_text_field($_POST['key']) : ''; |
| 1653 |
$customer_email = isset($_POST['email']) ? sanitize_email($_POST['email']) : ''; |
| 1654 |
|
| 1655 |
if (empty($license_key) || empty($customer_email)) { |
| 1656 |
wp_send_json_error('Email or License Key is missing'); |
| 1657 |
} |
| 1658 |
|
| 1659 |
$product_id = 'MxChatPRO'; |
| 1660 |
|
| 1661 |
$response = wp_remote_get("http://mxchat.ai/?wc-api=software-api&request=activation&email={$customer_email}&license_key={$license_key}&product_id={$product_id}"); |
| 1662 |
|
| 1663 |
if (is_wp_error($response)) { |
| 1664 |
wp_send_json_error('Activation failed due to a server error'); |
| 1665 |
} |
| 1666 |
|
| 1667 |
$body = wp_remote_retrieve_body($response); |
| 1668 |
$data = json_decode($body); |
| 1669 |
|
| 1670 |
if ($data && isset($data->activated) && $data->activated) { |
| 1671 |
update_option('mxchat_license_status', 'active'); |
| 1672 |
wp_send_json_success(); |
| 1673 |
} else { |
| 1674 |
$error_message = isset($data->error) ? $data->error : 'Activation failed'; |
| 1675 |
update_option('mxchat_license_status', 'inactive'); |
| 1676 |
update_option('mxchat_license_error', $error_message); |
| 1677 |
wp_send_json_error($error_message); |
| 1678 |
} |
| 1679 |
} |
| 1680 |
|
| 1681 |
public function mxchat_rate_limit_callback() { |
| 1682 |
$rate_limits = array('5', '10', '15', '20', '100', 'unlimited'); // Add 'unlimited' here |
| 1683 |
$selected_rate_limit = isset($this->options['rate_limit']) ? $this->options['rate_limit'] : '100'; |
| 1684 |
|
| 1685 |
echo '<div class="pro-feature-wrapper active">'; |
| 1686 |
echo '<select id="rate_limit" name="mxchat_options[rate_limit]">'; |
| 1687 |
foreach ($rate_limits as $limit) { |
| 1688 |
echo '<option value="' . esc_attr($limit) . '" ' . selected($selected_rate_limit, $limit, false) . '>' . esc_html($limit) . '</option>'; |
| 1689 |
} |
| 1690 |
echo '</select>'; |
| 1691 |
echo '</div>'; |
| 1692 |
} |
| 1693 |
|
| 1694 |
public function mxchat_rate_limit_message_callback() { |
| 1695 |
// Remove the is_activated check and make it always enabled |
| 1696 |
echo '<div class="pro-feature-wrapper active">'; |
| 1697 |
printf( |
| 1698 |
'<textarea id="rate_limit_message" name="mxchat_options[rate_limit_message]" rows="3" cols="50">%s</textarea>', |
| 1699 |
isset($this->options['rate_limit_message']) ? esc_textarea($this->options['rate_limit_message']) : 'Rate limit exceeded. Please try again later.' |
| 1700 |
); |
| 1701 |
echo '</div>'; |
| 1702 |
} |
| 1703 |
|
| 1704 |
|
| 1705 |
public function mxchat_enable_woocommerce_integration_callback() { |
| 1706 |
$checked = isset($this->options['enable_woocommerce_integration']) && $this->options['enable_woocommerce_integration'] === '1' ? 'checked' : ''; |
| 1707 |
$disabled = $this->is_activated ? '' : 'disabled'; |
| 1708 |
$class = $this->is_activated ? 'pro-feature-wrapper active' : 'pro-feature-wrapper inactive'; |
| 1709 |
|
| 1710 |
echo '<div class="' . esc_attr($class) . '">'; |
| 1711 |
echo '<label class="toggle-switch">'; |
| 1712 |
echo '<input type="checkbox" id="enable_woocommerce_integration" name="mxchat_options[enable_woocommerce_integration]" value="1" ' . $checked . ' ' . $disabled . '>'; |
| 1713 |
echo '<span class="slider"></span>'; |
| 1714 |
echo '</label>'; |
| 1715 |
|
| 1716 |
if (!$this->is_activated) { |
| 1717 |
echo '<div class="pro-feature-overlay">'; |
| 1718 |
echo '<a href="https://mxchat.ai/" target="_blank"><img src="' . plugin_dir_url(__FILE__) . '../images/pro-only-dark.png" alt="Pro Only" /></a>'; |
| 1719 |
echo '</div>'; |
| 1720 |
} |
| 1721 |
|
| 1722 |
echo '</div>'; |
| 1723 |
} |
| 1724 |
|
| 1725 |
|
| 1726 |
|
| 1727 |
|
| 1728 |
private function mxchat_add_option_field($id, $title, $callback = '') { |
| 1729 |
add_settings_field( |
| 1730 |
$id, |
| 1731 |
$title, |
| 1732 |
$callback ? array($this, $callback) : array($this, $id . '_callback'), |
| 1733 |
'mxchat-max', |
| 1734 |
'mxchat_setting_section_id', |
| 1735 |
$id === 'model' ? ['label_for' => 'model'] : [] |
| 1736 |
); |
| 1737 |
} |
| 1738 |
|
| 1739 |
|
| 1740 |
public function api_key_callback() { |
| 1741 |
$apiKey = isset($this->options['api_key']) ? esc_attr($this->options['api_key']) : ''; |
| 1742 |
echo '<input type="password" id="api_key" name="mxchat_options[api_key]" value="' . $apiKey . '" class="regular-text" />'; |
| 1743 |
echo '<button type="button" id="toggleApiKeyVisibility">Show</button>'; |
| 1744 |
} |
| 1745 |
|
| 1746 |
public function xai_api_key_callback() { |
| 1747 |
// Check if the feature is activated (paid feature) |
| 1748 |
$disabled = $this->is_activated ? '' : 'disabled'; // Disable input if not activated |
| 1749 |
$class = $this->is_activated ? 'pro-feature-wrapper active' : 'pro-feature-wrapper inactive'; // CSS class to style the wrapper based on activation status |
| 1750 |
|
| 1751 |
// Render the input field for the X.AI API key |
| 1752 |
echo '<div class="' . esc_attr($class) . '">'; |
| 1753 |
printf( |
| 1754 |
'<input type="password" id="xai_api_key" name="mxchat_options[xai_api_key]" value="%s" class="regular-text" %s />', |
| 1755 |
isset($this->options['xai_api_key']) ? esc_attr($this->options['xai_api_key']) : '', |
| 1756 |
$disabled |
| 1757 |
); |
| 1758 |
echo '<button type="button" id="toggleXaiApiKeyVisibility">Show</button>'; |
| 1759 |
|
| 1760 |
// If the feature is not activated, show the overlay with a "Pro Only" message |
| 1761 |
if (!$this->is_activated) { |
| 1762 |
echo '<div class="pro-feature-overlay">'; |
| 1763 |
echo '<a href="https://mxchat.ai/" target="_blank"><img src="' . plugin_dir_url(__FILE__) . '../images/pro-only-dark.png" alt="Pro Only" /></a>'; |
| 1764 |
echo '</div>'; |
| 1765 |
} |
| 1766 |
|
| 1767 |
echo '</div>'; |
| 1768 |
} |
| 1769 |
|
| 1770 |
public function claude_api_key_callback() { |
| 1771 |
// Check if the feature is activated (paid feature) |
| 1772 |
$disabled = $this->is_activated ? '' : 'disabled'; // Disable input if not activated |
| 1773 |
$class = $this->is_activated ? 'pro-feature-wrapper active' : 'pro-feature-wrapper inactive'; // CSS class to style the wrapper based on activation status |
| 1774 |
|
| 1775 |
// Render the input field for the Claude API key |
| 1776 |
echo '<div class="' . esc_attr($class) . '">'; |
| 1777 |
printf( |
| 1778 |
'<input type="password" id="claude_api_key" name="mxchat_options[claude_api_key]" value="%s" class="regular-text" %s />', |
| 1779 |
isset($this->options['claude_api_key']) ? esc_attr($this->options['claude_api_key']) : '', |
| 1780 |
$disabled |
| 1781 |
); |
| 1782 |
echo '<button type="button" id="toggleClaudeApiKeyVisibility">Show</button>'; |
| 1783 |
|
| 1784 |
// If the feature is not activated, show the overlay with a "Pro Only" message |
| 1785 |
if (!$this->is_activated) { |
| 1786 |
echo '<div class="pro-feature-overlay">'; |
| 1787 |
echo '<a href="https://mxchat.ai/" target="_blank"><img src="' . plugin_dir_url(__FILE__) . '../images/pro-only-dark.png" alt="Pro Only" /></a>'; |
| 1788 |
echo '</div>'; |
| 1789 |
} |
| 1790 |
|
| 1791 |
echo '</div>'; |
| 1792 |
} |
| 1793 |
|
| 1794 |
public function mxchat_woocommerce_consumer_key_callback() { |
| 1795 |
$disabled = $this->is_activated ? '' : 'disabled'; |
| 1796 |
$class = $this->is_activated ? 'pro-feature-wrapper active' : 'pro-feature-wrapper inactive'; |
| 1797 |
|
| 1798 |
echo '<div class="' . esc_attr($class) . '">'; |
| 1799 |
printf( |
| 1800 |
'<input type="text" id="woocommerce_consumer_key" name="mxchat_options[woocommerce_consumer_key]" value="%s" class="regular-text" %s />', |
| 1801 |
isset($this->options['woocommerce_consumer_key']) ? esc_attr($this->options['woocommerce_consumer_key']) : '', |
| 1802 |
$disabled |
| 1803 |
); |
| 1804 |
|
| 1805 |
if (!$this->is_activated) { |
| 1806 |
echo '<div class="pro-feature-overlay">'; |
| 1807 |
echo '<a href="https://mxchat.ai/" target="_blank"><img src="' . plugin_dir_url(__FILE__) . '../images/pro-only-dark.png" alt="Pro Only" /></a>'; |
| 1808 |
echo '</div>'; |
| 1809 |
} |
| 1810 |
|
| 1811 |
echo '</div>'; |
| 1812 |
} |
| 1813 |
|
| 1814 |
public function mxchat_woocommerce_consumer_secret_callback() { |
| 1815 |
$disabled = $this->is_activated ? '' : 'disabled'; |
| 1816 |
$class = $this->is_activated ? 'pro-feature-wrapper active' : 'pro-feature-wrapper inactive'; |
| 1817 |
|
| 1818 |
echo '<div class="' . esc_attr($class) . '">'; |
| 1819 |
printf( |
| 1820 |
'<input type="password" id="woocommerce_consumer_secret" name="mxchat_options[woocommerce_consumer_secret]" value="%s" class="regular-text" %s />', |
| 1821 |
isset($this->options['woocommerce_consumer_secret']) ? esc_attr($this->options['woocommerce_consumer_secret']) : '', |
| 1822 |
$disabled |
| 1823 |
); |
| 1824 |
echo '<button type="button" id="toggleWooCommerceSecretVisibility">Show</button>'; |
| 1825 |
|
| 1826 |
if (!$this->is_activated) { |
| 1827 |
echo '<div class="pro-feature-overlay">'; |
| 1828 |
echo '<a href="https://mxchat.ai/" target="_blank"><img src="' . plugin_dir_url(__FILE__) . '../images/pro-only-dark.png" alt="Pro Only" /></a>'; |
| 1829 |
echo '</div>'; |
| 1830 |
} |
| 1831 |
|
| 1832 |
echo '</div>'; |
| 1833 |
} |
| 1834 |
|
| 1835 |
public function mxchat_loops_api_key_callback() { |
| 1836 |
$loops_api_key = isset($this->options['loops_api_key']) ? esc_attr($this->options['loops_api_key']) : ''; |
| 1837 |
|
| 1838 |
echo '<div class="api-key-wrapper">'; |
| 1839 |
printf( |
| 1840 |
'<input type="password" id="loops_api_key" name="mxchat_options[loops_api_key]" value="%s" class="regular-text" />', |
| 1841 |
$loops_api_key |
| 1842 |
); |
| 1843 |
echo '<button type="button" id="toggleLoopsApiKeyVisibility">Show</button>'; |
| 1844 |
echo '</div>'; |
| 1845 |
echo '<p class="description">Enter your Loops API Key here. (See FAQ for details)</p>'; |
| 1846 |
} |
| 1847 |
|
| 1848 |
public function mxchat_loops_mailing_list_callback() { |
| 1849 |
// Retrieve Loops API key and lists |
| 1850 |
$loops_api_key = isset($this->options['loops_api_key']) ? $this->options['loops_api_key'] : ''; |
| 1851 |
$selected_list = isset($this->options['loops_mailing_list']) ? $this->options['loops_mailing_list'] : ''; |
| 1852 |
|
| 1853 |
if ($loops_api_key) { |
| 1854 |
// Fetch lists from Loops API |
| 1855 |
$lists = $this->mxchat_fetch_loops_mailing_lists($loops_api_key); |
| 1856 |
|
| 1857 |
if ($lists) { |
| 1858 |
echo '<select id="loops_mailing_list" name="mxchat_options[loops_mailing_list]">'; |
| 1859 |
foreach ($lists as $list) { |
| 1860 |
echo '<option value="' . esc_attr($list['id']) . '" ' . selected($selected_list, $list['id'], false) . '>' . esc_html($list['name']) . '</option>'; |
| 1861 |
} |
| 1862 |
echo '</select>'; |
| 1863 |
} else { |
| 1864 |
echo '<p class="description">No lists found. Please verify your API Key.</p>'; |
| 1865 |
} |
| 1866 |
} else { |
| 1867 |
echo '<p class="description">Enter a valid Loops API Key to load mailing lists.</p>'; |
| 1868 |
} |
| 1869 |
} |
| 1870 |
|
| 1871 |
public function mxchat_triggered_phrase_response_callback() { |
| 1872 |
$triggered_response = isset($this->options['triggered_phrase_response']) ? $this->options['triggered_phrase_response'] : ''; |
| 1873 |
echo '<textarea id="triggered_phrase_response" name="mxchat_options[triggered_phrase_response]" rows="3" cols="50">' . esc_textarea($triggered_response) . '</textarea>'; |
| 1874 |
echo '<p class="description">Enter the chatbot response when a trigger keyword is detected, prompting the user to share their email.</p>'; |
| 1875 |
} |
| 1876 |
|
| 1877 |
public function mxchat_email_capture_response_callback() { |
| 1878 |
$email_capture_response = isset($this->options['email_capture_response']) ? $this->options['email_capture_response'] : 'Thank you for providing your email! You\'ve been added to our list.'; |
| 1879 |
echo '<textarea id="email_capture_response" name="mxchat_options[email_capture_response]" rows="3" cols="50">' . esc_textarea($email_capture_response) . '</textarea>'; |
| 1880 |
echo '<p class="description">Enter the message to send when a user provides their email.</p>'; |
| 1881 |
} |
| 1882 |
|
| 1883 |
|
| 1884 |
public function mxchat_pre_chat_message_callback() { |
| 1885 |
printf( |
| 1886 |
'<textarea id="pre_chat_message" name="mxchat_options[pre_chat_message]" rows="5" cols="50">%s</textarea>', |
| 1887 |
isset($this->options['pre_chat_message']) ? esc_textarea($this->options['pre_chat_message']) : '' |
| 1888 |
); |
| 1889 |
} |
| 1890 |
|
| 1891 |
// Callback for AI Instructions textarea |
| 1892 |
public function system_prompt_instructions_callback() { |
| 1893 |
printf( |
| 1894 |
'<textarea id="system_prompt_instructions" name="mxchat_options[system_prompt_instructions]" rows="5" cols="50">%s</textarea>', |
| 1895 |
isset($this->options['system_prompt_instructions']) ? esc_textarea($this->options['system_prompt_instructions']) : '' |
| 1896 |
); |
| 1897 |
} |
| 1898 |
|
| 1899 |
public function mxchat_model_callback() { |
| 1900 |
$models = array( |
| 1901 |
'X.AI Models' => array( |
| 1902 |
'grok-beta' => 'grok-beta (Early Beta)' |
| 1903 |
), |
| 1904 |
'Claude Models' => array( |
| 1905 |
'claude-3-5-sonnet-20241022' => 'Claude 3.5 Sonnet (Most Intelligent)', |
| 1906 |
'claude-3-opus-20240229' => 'Claude 3 Opus (Highly Complex Tasks)', |
| 1907 |
'claude-3-sonnet-20240229' => 'Claude 3 Sonnet (Balanced)', |
| 1908 |
'claude-3-haiku-20240307' => 'Claude 3 Haiku (Fastest)' |
| 1909 |
), |
| 1910 |
'OpenAI Models' => array( |
| 1911 |
'gpt-4o' => 'GPT-4o (Recommended)', |
| 1912 |
'gpt-4o-mini' => 'GPT-4o Mini (Fast and Lightweight)', |
| 1913 |
'gpt-4-turbo' => 'GPT-4 Turbo (High-Performance)', |
| 1914 |
'gpt-4' => 'GPT-4 (High Intelligence)', |
| 1915 |
'gpt-3.5-turbo' => 'GPT-3.5 Turbo (Affordable and Fast)' |
| 1916 |
) |
| 1917 |
); |
| 1918 |
|
| 1919 |
$selected_model = isset($this->options['model']) ? $this->options['model'] : 'gpt-3.5-turbo'; |
| 1920 |
|
| 1921 |
echo '<select id="model" name="mxchat_options[model]">'; |
| 1922 |
|
| 1923 |
foreach ($models as $group_label => $group_models) { |
| 1924 |
echo '<optgroup label="' . esc_attr($group_label) . '">'; |
| 1925 |
|
| 1926 |
foreach ($group_models as $model_value => $model_label) { |
| 1927 |
// Disable if not activated for paid models (Claude or X.AI) |
| 1928 |
$disabled = (!$this->is_activated && ($group_label === 'X.AI Models' || $group_label === 'Claude Models')) ? 'disabled' : ''; |
| 1929 |
$label_suffix = (!$this->is_activated && ($group_label === 'X.AI Models' || $group_label === 'Claude Models')) ? ' (Pro Only)' : ''; |
| 1930 |
|
| 1931 |
// Output the <option> element |
| 1932 |
echo '<option value="' . esc_attr($model_value) . '" ' . selected($selected_model, $model_value, false) . ' ' . $disabled . '>' . esc_html($model_label . $label_suffix) . '</option>'; |
| 1933 |
} |
| 1934 |
|
| 1935 |
echo '</optgroup>'; |
| 1936 |
} |
| 1937 |
|
| 1938 |
echo '</select>'; |
| 1939 |
} |
| 1940 |
|
| 1941 |
|
| 1942 |
|
| 1943 |
public function mxchat_top_bar_title_callback() { |
| 1944 |
printf( |
| 1945 |
'<input type="text" id="top_bar_title" name="mxchat_options[top_bar_title]" value="%s" />', |
| 1946 |
isset($this->options['top_bar_title']) ? esc_attr($this->options['top_bar_title']) : '' |
| 1947 |
); |
| 1948 |
} |
| 1949 |
|
| 1950 |
public function mxchat_intro_message_callback() { |
| 1951 |
printf( |
| 1952 |
'<textarea id="intro_message" name="mxchat_options[intro_message]" rows="5" cols="50">%s</textarea>', |
| 1953 |
isset($this->options['intro_message']) ? esc_textarea($this->options['intro_message']) : 'Hello! How can I assist you today?' |
| 1954 |
); |
| 1955 |
} |
| 1956 |
|
| 1957 |
public function mxchat_input_copy_callback() { |
| 1958 |
printf( |
| 1959 |
'<input type="text" id="input_copy" name="mxchat_options[input_copy]" value="%s" placeholder="How can I assist?" />', |
| 1960 |
isset($this->options['input_copy']) ? esc_attr($this->options['input_copy']) : 'How can I assist?' |
| 1961 |
); |
| 1962 |
echo '<p class="description">This is the placeholder text for the chat input field.</p>'; |
| 1963 |
} |
| 1964 |
|
| 1965 |
|
| 1966 |
|
| 1967 |
|
| 1968 |
|
| 1969 |
|
| 1970 |
public function mxchat_close_button_color_callback() { |
| 1971 |
$disabled = $this->is_activated ? '' : 'disabled'; |
| 1972 |
|
| 1973 |
echo '<div class="pro-feature-wrapper">'; |
| 1974 |
printf( |
| 1975 |
'<input type="text" id="close_button_color" name="mxchat_options[close_button_color]" value="%s" class="my-color-field" data-default-color="#4a4a4a" %s />', |
| 1976 |
isset($this->options['close_button_color']) ? esc_attr($this->options['close_button_color']) : '', |
| 1977 |
esc_attr($disabled) |
| 1978 |
); |
| 1979 |
|
| 1980 |
if (!$this->is_activated) { |
| 1981 |
echo '<div class="pro-feature-overlay">'; |
| 1982 |
echo '<a href="https://mxchat.ai/" target="_blank"><img src="' . plugin_dir_url(__FILE__) . '../images/pro-only-dark.png" alt="Pro Only" /></a>'; |
| 1983 |
echo '</div>'; |
| 1984 |
} |
| 1985 |
|
| 1986 |
echo '</div>'; |
| 1987 |
} |
| 1988 |
|
| 1989 |
public function mxchat_chatbot_bg_color_callback() { |
| 1990 |
$disabled = $this->is_activated ? '' : 'disabled'; |
| 1991 |
|
| 1992 |
echo '<div class="pro-feature-wrapper">'; |
| 1993 |
printf( |
| 1994 |
'<input type="text" id="chatbot_bg_color" name="mxchat_options[chatbot_bg_color]" value="%s" class="my-color-field" data-default-color="#f9f9f9" %s />', |
| 1995 |
isset($this->options['chatbot_bg_color']) ? esc_attr($this->options['chatbot_bg_color']) : '', |
| 1996 |
esc_attr($disabled) |
| 1997 |
); |
| 1998 |
|
| 1999 |
if (!$this->is_activated) { |
| 2000 |
echo '<div class="pro-feature-overlay">'; |
| 2001 |
echo '<a href="https://mxchat.ai/" target="_blank"><img src="' . plugin_dir_url(__FILE__) . '../images/pro-only-dark.png" alt="Pro Only" /></a>'; |
| 2002 |
echo '</div>'; |
| 2003 |
} |
| 2004 |
|
| 2005 |
echo '</div>'; |
| 2006 |
} |
| 2007 |
|
| 2008 |
public function mxchat_user_message_bg_color_callback() { |
| 2009 |
$disabled = $this->is_activated ? '' : 'disabled'; |
| 2010 |
|
| 2011 |
echo '<div class="pro-feature-wrapper">'; |
| 2012 |
printf( |
| 2013 |
'<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 />', |
| 2014 |
isset($this->options['user_message_bg_color']) ? esc_attr($this->options['user_message_bg_color']) : '', |
| 2015 |
esc_attr($disabled) |
| 2016 |
); |
| 2017 |
|
| 2018 |
if (!$this->is_activated) { |
| 2019 |
echo '<div class="pro-feature-overlay">'; |
| 2020 |
echo '<a href="https://mxchat.ai/" target="_blank"><img src="' . plugin_dir_url(__FILE__) . '../images/pro-only-dark.png" alt="Pro Only" /></a>'; |
| 2021 |
echo '</div>'; |
| 2022 |
} |
| 2023 |
|
| 2024 |
echo '</div>'; |
| 2025 |
} |
| 2026 |
|
| 2027 |
public function mxchat_user_message_font_color_callback() { |
| 2028 |
$disabled = $this->is_activated ? '' : 'disabled'; |
| 2029 |
|
| 2030 |
echo '<div class="pro-feature-wrapper">'; |
| 2031 |
printf( |
| 2032 |
'<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 />', |
| 2033 |
isset($this->options['user_message_font_color']) ? esc_attr($this->options['user_message_font_color']) : '', |
| 2034 |
esc_attr($disabled) |
| 2035 |
); |
| 2036 |
|
| 2037 |
if (!$this->is_activated) { |
| 2038 |
echo '<div class="pro-feature-overlay">'; |
| 2039 |
echo '<a href="https://mxchat.ai/" target="_blank"><img src="' . plugin_dir_url(__FILE__) . '../images/pro-only-dark.png" alt="Pro Only" /></a>'; |
| 2040 |
echo '</div>'; |
| 2041 |
} |
| 2042 |
|
| 2043 |
echo '</div>'; |
| 2044 |
} |
| 2045 |
|
| 2046 |
public function mxchat_bot_message_bg_color_callback() { |
| 2047 |
$disabled = $this->is_activated ? '' : 'disabled'; |
| 2048 |
|
| 2049 |
echo '<div class="pro-feature-wrapper">'; |
| 2050 |
printf( |
| 2051 |
'<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 />', |
| 2052 |
isset($this->options['bot_message_bg_color']) ? esc_attr($this->options['bot_message_bg_color']) : '', |
| 2053 |
esc_attr($disabled) |
| 2054 |
); |
| 2055 |
|
| 2056 |
if (!$this->is_activated) { |
| 2057 |
echo '<div class="pro-feature-overlay">'; |
| 2058 |
echo '<a href="https://mxchat.ai/" target="_blank"><img src="' . plugin_dir_url(__FILE__) . '../images/pro-only-dark.png" alt="Pro Only" /></a>'; |
| 2059 |
echo '</div>'; |
| 2060 |
} |
| 2061 |
|
| 2062 |
echo '</div>'; |
| 2063 |
} |
| 2064 |
|
| 2065 |
public function mxchat_bot_message_font_color_callback() { |
| 2066 |
$disabled = $this->is_activated ? '' : 'disabled'; |
| 2067 |
|
| 2068 |
echo '<div class="pro-feature-wrapper">'; |
| 2069 |
printf( |
| 2070 |
'<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 />', |
| 2071 |
isset($this->options['bot_message_font_color']) ? esc_attr($this->options['bot_message_font_color']) : '', |
| 2072 |
esc_attr($disabled) |
| 2073 |
); |
| 2074 |
|
| 2075 |
if (!$this->is_activated) { |
| 2076 |
echo '<div class="pro-feature-overlay">'; |
| 2077 |
echo '<a href="https://mxchat.ai/" target="_blank"><img src="' . plugin_dir_url(__FILE__) . '../images/pro-only-dark.png" alt="Pro Only" /></a>'; |
| 2078 |
echo '</div>'; |
| 2079 |
} |
| 2080 |
|
| 2081 |
echo '</div>'; |
| 2082 |
} |
| 2083 |
|
| 2084 |
public function mxchat_top_bar_bg_color_callback() { |
| 2085 |
$disabled = $this->is_activated ? '' : 'disabled'; |
| 2086 |
|
| 2087 |
echo '<div class="pro-feature-wrapper">'; |
| 2088 |
printf( |
| 2089 |
'<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 />', |
| 2090 |
isset($this->options['top_bar_bg_color']) ? esc_attr($this->options['top_bar_bg_color']) : '', |
| 2091 |
esc_attr($disabled) |
| 2092 |
); |
| 2093 |
|
| 2094 |
if (!$this->is_activated) { |
| 2095 |
echo '<div class="pro-feature-overlay">'; |
| 2096 |
echo '<a href="https://mxchat.ai/" target="_blank"><img src="' . plugin_dir_url(__FILE__) . '../images/pro-only-dark.png" alt="Pro Only" /></a>'; |
| 2097 |
echo '</div>'; |
| 2098 |
} |
| 2099 |
|
| 2100 |
echo '</div>'; |
| 2101 |
} |
| 2102 |
|
| 2103 |
public function mxchat_send_button_font_color_callback() { |
| 2104 |
$disabled = $this->is_activated ? '' : 'disabled'; |
| 2105 |
|
| 2106 |
echo '<div class="pro-feature-wrapper">'; |
| 2107 |
printf( |
| 2108 |
'<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 />', |
| 2109 |
isset($this->options['send_button_font_color']) ? esc_attr($this->options['send_button_font_color']) : '', |
| 2110 |
esc_attr($disabled) |
| 2111 |
); |
| 2112 |
|
| 2113 |
if (!$this->is_activated) { |
| 2114 |
echo '<div class="pro-feature-overlay">'; |
| 2115 |
echo '<a href="https://mxchat.ai/" target="_blank"><img src="' . plugin_dir_url(__FILE__) . '../images/pro-only-dark.png" alt="Pro Only" /></a>'; |
| 2116 |
echo '</div>'; |
| 2117 |
} |
| 2118 |
|
| 2119 |
echo '</div>'; |
| 2120 |
} |
| 2121 |
|
| 2122 |
public function mxchat_chatbot_background_color_callback() { |
| 2123 |
$disabled = $this->is_activated ? '' : 'disabled'; |
| 2124 |
|
| 2125 |
echo '<div class="pro-feature-wrapper">'; |
| 2126 |
printf( |
| 2127 |
'<input type="text" id="chatbot_background_color" name="mxchat_options[chatbot_background_color]" value="%s" class="my-color-field" data-default-color="#000000" %s />', |
| 2128 |
isset($this->options['chatbot_background_color']) ? esc_attr($this->options['chatbot_background_color']) : '', |
| 2129 |
esc_attr($disabled) |
| 2130 |
); |
| 2131 |
|
| 2132 |
if (!$this->is_activated) { |
| 2133 |
echo '<div class="pro-feature-overlay">'; |
| 2134 |
echo '<a href="https://mxchat.ai/" target="_blank"><img src="' . plugin_dir_url(__FILE__) . '../images/pro-only-dark.png" alt="Pro Only" /></a>'; |
| 2135 |
echo '</div>'; |
| 2136 |
} |
| 2137 |
|
| 2138 |
echo '</div>'; |
| 2139 |
} |
| 2140 |
|
| 2141 |
public function mxchat_icon_color_callback() { |
| 2142 |
$disabled = $this->is_activated ? '' : 'disabled'; |
| 2143 |
|
| 2144 |
echo '<div class="pro-feature-wrapper">'; |
| 2145 |
printf( |
| 2146 |
'<input type="text" id="icon_color" name="mxchat_options[icon_color]" value="%s" class="my-color-field" data-default-color="#ffffff" %s />', |
| 2147 |
isset($this->options['icon_color']) ? esc_attr($this->options['icon_color']) : '', |
| 2148 |
esc_attr($disabled) |
| 2149 |
); |
| 2150 |
|
| 2151 |
if (!$this->is_activated) { |
| 2152 |
echo '<div class="pro-feature-overlay">'; |
| 2153 |
echo '<a href="https://mxchat.ai/" target="_blank"><img src="' . plugin_dir_url(__FILE__) . '../images/pro-only-dark.png" alt="Pro Only" /></a>'; |
| 2154 |
echo '</div>'; |
| 2155 |
} |
| 2156 |
|
| 2157 |
echo '</div>'; |
| 2158 |
} |
| 2159 |
|
| 2160 |
public function mxchat_chat_input_font_color_callback() { |
| 2161 |
$disabled = $this->is_activated ? '' : 'disabled'; |
| 2162 |
|
| 2163 |
echo '<div class="pro-feature-wrapper">'; |
| 2164 |
printf( |
| 2165 |
'<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 />', |
| 2166 |
isset($this->options['chat_input_font_color']) ? esc_attr($this->options['chat_input_font_color']) : '', |
| 2167 |
esc_attr($disabled) |
| 2168 |
); |
| 2169 |
|
| 2170 |
if (!$this->is_activated) { |
| 2171 |
echo '<div class="pro-feature-overlay">'; |
| 2172 |
echo '<a href="https://mxchat.ai/" target="_blank"><img src="' . plugin_dir_url(__FILE__) . '../images/pro-only-dark.png" alt="Pro Only" /></a>'; |
| 2173 |
echo '</div>'; |
| 2174 |
} |
| 2175 |
|
| 2176 |
echo '</div>'; |
| 2177 |
} |
| 2178 |
|
| 2179 |
|
| 2180 |
public function mxchat_append_to_body_callback() { |
| 2181 |
$append_to_body_checked = isset($this->options['append_to_body']) && $this->options['append_to_body'] === 'on' ? 'checked' : ''; |
| 2182 |
echo '<label class="toggle-switch">'; |
| 2183 |
printf( |
| 2184 |
'<input type="checkbox" id="append_to_body" name="mxchat_options[append_to_body]" %s />', |
| 2185 |
esc_attr($append_to_body_checked) |
| 2186 |
); |
| 2187 |
echo '<span class="slider"></span>'; |
| 2188 |
echo '</label>'; |
| 2189 |
echo '<p class="description">Enable this option to automatically append the chat widget to the body of every page (recommended). No need to manually use the shortcode [mxchat_chatbot floating="yes"].</p>'; |
| 2190 |
} |
| 2191 |
|
| 2192 |
|
| 2193 |
public function mxchat_privacy_toggle_callback() { |
| 2194 |
// Check if the privacy toggle is enabled |
| 2195 |
$privacy_toggle_checked = isset($this->options['privacy_toggle']) && $this->options['privacy_toggle'] === 'on' ? 'checked' : ''; |
| 2196 |
|
| 2197 |
// Retrieve the stored privacy text if it exists |
| 2198 |
$privacy_text = isset($this->options['privacy_text']) ? wp_kses_post($this->options['privacy_text']) : 'By chatting, you agree to our <a href="https://example.com/privacy-policy" target="_blank">privacy policy</a>.'; |
| 2199 |
|
| 2200 |
// Output the toggle switch |
| 2201 |
echo '<label class="toggle-switch">'; |
| 2202 |
printf( |
| 2203 |
'<input type="checkbox" id="privacy_toggle" name="mxchat_options[privacy_toggle]" %s />', |
| 2204 |
esc_attr($privacy_toggle_checked) |
| 2205 |
); |
| 2206 |
echo '<span class="slider"></span>'; |
| 2207 |
echo '</label>'; |
| 2208 |
echo '<p class="description">Enable this option to display a privacy notice below the chat widget.</p>'; |
| 2209 |
|
| 2210 |
// Output the custom text input field |
| 2211 |
printf( |
| 2212 |
'<textarea id="privacy_text" name="mxchat_options[privacy_text]" rows="5" cols="50" class="regular-text">%s</textarea>', |
| 2213 |
esc_textarea($privacy_text) |
| 2214 |
); |
| 2215 |
echo '<p class="description">Enter the privacy policy text. You can include HTML links.</p>'; |
| 2216 |
} |
| 2217 |
|
| 2218 |
|
| 2219 |
public function mxchat_complianz_toggle_callback() { |
| 2220 |
// Check if the Complianz toggle is enabled |
| 2221 |
$complianz_toggle_checked = isset($this->options['complianz_toggle']) && $this->options['complianz_toggle'] === 'on' ? 'checked' : ''; |
| 2222 |
|
| 2223 |
// Check if the plugin is activated (paid feature) |
| 2224 |
$disabled = $this->is_activated ? '' : 'disabled'; |
| 2225 |
$class = $this->is_activated ? 'pro-feature-wrapper active' : 'pro-feature-wrapper inactive'; |
| 2226 |
|
| 2227 |
echo '<div class="' . esc_attr($class) . '">'; |
| 2228 |
|
| 2229 |
// Output the toggle switch |
| 2230 |
echo '<label class="toggle-switch">'; |
| 2231 |
printf( |
| 2232 |
'<input type="checkbox" id="complianz_toggle" name="mxchat_options[complianz_toggle]" %s %s />', |
| 2233 |
esc_attr($complianz_toggle_checked), |
| 2234 |
esc_attr($disabled) |
| 2235 |
); |
| 2236 |
echo '<span class="slider"></span>'; |
| 2237 |
echo '</label>'; |
| 2238 |
echo '<p class="description">Enable this option to apply Complianz consent logic to the chatbot.</p>'; |
| 2239 |
|
| 2240 |
// If the feature is not activated, show the Pro feature overlay |
| 2241 |
if (!$this->is_activated) { |
| 2242 |
echo '<div class="pro-feature-overlay">'; |
| 2243 |
echo '<a href="https://mxchat.ai/" target="_blank"><img src="' . plugin_dir_url(__FILE__) . '../images/pro-only-dark.png" alt="Pro Only" /></a>'; |
| 2244 |
echo '</div>'; |
| 2245 |
} |
| 2246 |
|
| 2247 |
echo '</div>'; |
| 2248 |
} |
| 2249 |
|
| 2250 |
|
| 2251 |
|
| 2252 |
|
| 2253 |
|
| 2254 |
public function mxchat_link_target_toggle_callback() { |
| 2255 |
// Check if the toggle is enabled in the options |
| 2256 |
$link_target_toggle = isset($this->options['link_target_toggle']) && $this->options['link_target_toggle'] === 'on' ? 'checked' : ''; |
| 2257 |
|
| 2258 |
// Output the toggle switch |
| 2259 |
echo '<label class="toggle-switch">'; |
| 2260 |
printf( |
| 2261 |
'<input type="checkbox" id="link_target_toggle" name="mxchat_options[link_target_toggle]" %s />', |
| 2262 |
esc_attr($link_target_toggle) |
| 2263 |
); |
| 2264 |
echo '<span class="slider"></span>'; |
| 2265 |
echo '</label>'; |
| 2266 |
echo '<p class="description">Enable to open links in a new tab (default is to open in the same tab).</p>'; |
| 2267 |
} |
| 2268 |
|
| 2269 |
public function mxchat_chat_persistence_toggle_callback() { |
| 2270 |
// Check if chat persistence toggle is enabled |
| 2271 |
$chat_persistence_toggle_checked = isset($this->options['chat_persistence_toggle']) && $this->options['chat_persistence_toggle'] === 'on' ? 'checked' : ''; |
| 2272 |
|
| 2273 |
// Check if the plugin is activated (paid feature) |
| 2274 |
$disabled = $this->is_activated ? '' : 'disabled'; |
| 2275 |
$class = $this->is_activated ? 'pro-feature-wrapper active' : 'pro-feature-wrapper inactive'; |
| 2276 |
|
| 2277 |
echo '<div class="' . esc_attr($class) . '">'; |
| 2278 |
|
| 2279 |
// Output the toggle switch |
| 2280 |
echo '<label class="toggle-switch">'; |
| 2281 |
printf( |
| 2282 |
'<input type="checkbox" id="chat_persistence_toggle" name="mxchat_options[chat_persistence_toggle]" %s %s />', |
| 2283 |
esc_attr($chat_persistence_toggle_checked), |
| 2284 |
esc_attr($disabled) |
| 2285 |
); |
| 2286 |
echo '<span class="slider"></span>'; |
| 2287 |
echo '</label>'; |
| 2288 |
echo '<p class="description">Enable to keep chat history when users navigate tabs or return to the site within 24 hours.</p>'; |
| 2289 |
|
| 2290 |
// If not activated, show Pro feature overlay |
| 2291 |
if (!$this->is_activated) { |
| 2292 |
echo '<div class="pro-feature-overlay">'; |
| 2293 |
echo '<a href="https://mxchat.ai/" target="_blank"><img src="' . plugin_dir_url(__FILE__) . '../images/pro-only-dark.png" alt="Pro Only" /></a>'; |
| 2294 |
echo '</div>'; |
| 2295 |
} |
| 2296 |
|
| 2297 |
echo '</div>'; |
| 2298 |
} |
| 2299 |
|
| 2300 |
|
| 2301 |
public function mxchat_popular_question_1_callback() { |
| 2302 |
printf( |
| 2303 |
'<input type="text" id="popular_question_1" name="mxchat_options[popular_question_1]" value="%s" placeholder="Enter Popular Question 1" />', |
| 2304 |
isset($this->options['popular_question_1']) ? esc_attr($this->options['popular_question_1']) : '' |
| 2305 |
); |
| 2306 |
echo '<p class="description">This will be the first popular question in the chatbot.</p>'; |
| 2307 |
} |
| 2308 |
|
| 2309 |
public function mxchat_popular_question_2_callback() { |
| 2310 |
// Check if the plugin is activated (paid feature) |
| 2311 |
$disabled = $this->is_activated ? '' : 'disabled'; |
| 2312 |
$class = $this->is_activated ? 'pro-feature-wrapper active' : 'pro-feature-wrapper inactive'; |
| 2313 |
|
| 2314 |
echo '<div class="' . esc_attr($class) . '">'; |
| 2315 |
|
| 2316 |
printf( |
| 2317 |
'<input type="text" id="popular_question_2" name="mxchat_options[popular_question_2]" value="%s" placeholder="Enter Popular Question 2" %s />', |
| 2318 |
isset($this->options['popular_question_2']) ? esc_attr($this->options['popular_question_2']) : '', |
| 2319 |
esc_attr($disabled) |
| 2320 |
); |
| 2321 |
echo '<p class="description">This will be the second popular question in the chatbot.</p>'; |
| 2322 |
|
| 2323 |
// If not activated, show Pro feature overlay |
| 2324 |
if (!$this->is_activated) { |
| 2325 |
echo '<div class="pro-feature-overlay">'; |
| 2326 |
echo '<a href="https://mxchat.ai/" target="_blank"><img src="' . plugin_dir_url(__FILE__) . '../images/pro-only-dark.png" alt="Pro Only" /></a>'; |
| 2327 |
echo '</div>'; |
| 2328 |
} |
| 2329 |
|
| 2330 |
echo '</div>'; |
| 2331 |
} |
| 2332 |
|
| 2333 |
public function mxchat_popular_question_3_callback() { |
| 2334 |
// Check if the plugin is activated (paid feature) |
| 2335 |
$disabled = $this->is_activated ? '' : 'disabled'; |
| 2336 |
$class = $this->is_activated ? 'pro-feature-wrapper active' : 'pro-feature-wrapper inactive'; |
| 2337 |
|
| 2338 |
echo '<div class="' . esc_attr($class) . '">'; |
| 2339 |
|
| 2340 |
printf( |
| 2341 |
'<input type="text" id="popular_question_3" name="mxchat_options[popular_question_3]" value="%s" placeholder="Enter Popular Question 3" %s />', |
| 2342 |
isset($this->options['popular_question_3']) ? esc_attr($this->options['popular_question_3']) : '', |
| 2343 |
esc_attr($disabled) |
| 2344 |
); |
| 2345 |
echo '<p class="description">This will be the third popular question in the chatbot.</p>'; |
| 2346 |
|
| 2347 |
// If not activated, show Pro feature overlay |
| 2348 |
if (!$this->is_activated) { |
| 2349 |
echo '<div class="pro-feature-overlay">'; |
| 2350 |
echo '<a href="https://mxchat.ai/" target="_blank"><img src="' . plugin_dir_url(__FILE__) . '../images/pro-only-dark.png" alt="Pro Only" /></a>'; |
| 2351 |
echo '</div>'; |
| 2352 |
} |
| 2353 |
|
| 2354 |
echo '</div>'; |
| 2355 |
} |
| 2356 |
|
| 2357 |
|
| 2358 |
/** |
| 2359 |
* Callback for Brave API Key field. |
| 2360 |
*/ |
| 2361 |
public function mxchat_brave_api_key_callback() { |
| 2362 |
$options = get_option('mxchat_options'); |
| 2363 |
$brave_api_key = isset($options['brave_api_key']) ? esc_attr($options['brave_api_key']) : ''; |
| 2364 |
|
| 2365 |
echo '<div class="api-key-wrapper">'; |
| 2366 |
printf( |
| 2367 |
'<input type="password" id="brave_api_key" name="mxchat_options[brave_api_key]" value="%s" class="regular-text" />', |
| 2368 |
$brave_api_key |
| 2369 |
); |
| 2370 |
echo '<button type="button" id="toggleBraveApiKeyVisibility" class="button-secondary">Show</button>'; |
| 2371 |
echo '</div>'; |
| 2372 |
echo '<p class="description">' . __('Enter your Brave Search API Key here. (See FAQ for details)', 'mxchat') . '</p>'; |
| 2373 |
|
| 2374 |
?> |
| 2375 |
<?php |
| 2376 |
} |
| 2377 |
|
| 2378 |
/** |
| 2379 |
* Callback for Number of Images to Return field. |
| 2380 |
*/ |
| 2381 |
public function mxchat_brave_image_count_callback() { |
| 2382 |
$options = get_option('mxchat_options'); |
| 2383 |
$brave_image_count = isset($options['brave_image_count']) ? intval($options['brave_image_count']) : 4; |
| 2384 |
|
| 2385 |
printf( |
| 2386 |
'<input type="number" id="brave_image_count" name="mxchat_options[brave_image_count]" value="%d" min="1" max="6" />', |
| 2387 |
$brave_image_count |
| 2388 |
); |
| 2389 |
echo '<p class="description">' . __('Select the number of images to return (1-6).', 'mxchat') . '</p>'; |
| 2390 |
} |
| 2391 |
|
| 2392 |
/** |
| 2393 |
* Callback for Safe Search field. |
| 2394 |
*/ |
| 2395 |
public function mxchat_brave_safe_search_callback() { |
| 2396 |
$options = get_option('mxchat_options'); |
| 2397 |
$brave_safe_search = isset($options['brave_safe_search']) ? esc_attr($options['brave_safe_search']) : 'strict'; |
| 2398 |
|
| 2399 |
?> |
| 2400 |
<select id="brave_safe_search" name="mxchat_options[brave_safe_search]"> |
| 2401 |
<option value="strict" <?php selected($brave_safe_search, 'strict'); ?>><?php _e('Strict', 'mxchat'); ?></option> |
| 2402 |
<option value="off" <?php selected($brave_safe_search, 'off'); ?>><?php _e('Off', 'mxchat'); ?></option> |
| 2403 |
</select> |
| 2404 |
<p class="description"><?php _e('Set the Safe Search level for image searches. Brave Search only supports "Strict" and "Off" options.', 'mxchat'); ?></p> |
| 2405 |
<?php |
| 2406 |
} |
| 2407 |
|
| 2408 |
|
| 2409 |
/** |
| 2410 |
* Callback for Number of News Articles field. |
| 2411 |
*/ |
| 2412 |
public function mxchat_brave_news_count_callback() { |
| 2413 |
$options = get_option('mxchat_options'); |
| 2414 |
$brave_news_count = isset($options['brave_news_count']) ? intval($options['brave_news_count']) : 3; |
| 2415 |
|
| 2416 |
printf( |
| 2417 |
'<input type="number" id="brave_news_count" name="mxchat_options[brave_news_count]" value="%d" min="1" max="10" />', |
| 2418 |
$brave_news_count |
| 2419 |
); |
| 2420 |
echo '<p class="description">' . __('Select the number of news articles to retrieve (1-10).', 'mxchat') . '</p>'; |
| 2421 |
} |
| 2422 |
|
| 2423 |
/** |
| 2424 |
* Callback for Country field. |
| 2425 |
*/ |
| 2426 |
public function mxchat_brave_country_callback() { |
| 2427 |
$options = get_option('mxchat_options'); |
| 2428 |
$brave_country = isset($options['brave_country']) ? esc_attr($options['brave_country']) : 'us'; |
| 2429 |
|
| 2430 |
printf( |
| 2431 |
'<input type="text" id="brave_country" name="mxchat_options[brave_country]" value="%s" maxlength="2" class="small-text" />', |
| 2432 |
$brave_country |
| 2433 |
); |
| 2434 |
echo '<p class="description">' . __('Enter the country code (e.g., "us" for United States).', 'mxchat') . '</p>'; |
| 2435 |
} |
| 2436 |
|
| 2437 |
/** |
| 2438 |
* Callback for Language field. |
| 2439 |
*/ |
| 2440 |
public function mxchat_brave_language_callback() { |
| 2441 |
$options = get_option('mxchat_options'); |
| 2442 |
$brave_language = isset($options['brave_language']) ? esc_attr($options['brave_language']) : 'en'; |
| 2443 |
|
| 2444 |
printf( |
| 2445 |
'<input type="text" id="brave_language" name="mxchat_options[brave_language]" value="%s" maxlength="2" class="small-text" />', |
| 2446 |
$brave_language |
| 2447 |
); |
| 2448 |
echo '<p class="description">' . __('Enter the language code (e.g., "en" for English).', 'mxchat') . '</p>'; |
| 2449 |
} |
| 2450 |
|
| 2451 |
|
| 2452 |
|
| 2453 |
|
| 2454 |
|
| 2455 |
|
| 2456 |
|
| 2457 |
|
| 2458 |
|
| 2459 |
public function mxchat_enqueue_admin_assets() { |
| 2460 |
wp_enqueue_style('wp-color-picker'); |
| 2461 |
|
| 2462 |
// Get the plugin version or file modification time for cache busting |
| 2463 |
$plugin_version = '1.3'; // Replace this with your plugin's version |
| 2464 |
|
| 2465 |
// File paths |
| 2466 |
$color_picker_js_path = plugin_dir_path(__FILE__) . '../js/my-color-picker.js'; |
| 2467 |
$embedding_check_js_path = plugin_dir_path(__FILE__) . '../js/embedding-check.js'; |
| 2468 |
$admin_css_path = plugin_dir_path(__FILE__) . '../css/admin-style.css'; |
| 2469 |
$transcripts_js_path = plugin_dir_path(__FILE__) . '../js/mxchat_transcripts.js'; |
| 2470 |
|
| 2471 |
// Check if files exist and get modification times |
| 2472 |
$color_picker_version = file_exists($color_picker_js_path) ? filemtime($color_picker_js_path) : $plugin_version; |
| 2473 |
$embedding_check_version = file_exists($embedding_check_js_path) ? filemtime($embedding_check_js_path) : $plugin_version; |
| 2474 |
$admin_css_version = file_exists($admin_css_path) ? filemtime($admin_css_path) : $plugin_version; |
| 2475 |
$transcripts_js_version = file_exists($transcripts_js_path) ? filemtime($transcripts_js_path) : $plugin_version; |
| 2476 |
|
| 2477 |
// Enqueue scripts and styles with corrected paths |
| 2478 |
wp_enqueue_script( |
| 2479 |
'mxchat-color-picker', |
| 2480 |
plugin_dir_url(__FILE__) . '../js/my-color-picker.js', |
| 2481 |
array('wp-color-picker'), |
| 2482 |
$color_picker_version, |
| 2483 |
true |
| 2484 |
); |
| 2485 |
|
| 2486 |
wp_enqueue_script( |
| 2487 |
'mxchat-embedding-check', |
| 2488 |
plugin_dir_url(__FILE__) . '../js/embedding-check.js', |
| 2489 |
array(), |
| 2490 |
$embedding_check_version, |
| 2491 |
true |
| 2492 |
); |
| 2493 |
|
| 2494 |
wp_enqueue_script( |
| 2495 |
'mxchat-transcripts-js', |
| 2496 |
plugin_dir_url(__FILE__) . '../js/mxchat_transcripts.js', |
| 2497 |
array('jquery'), |
| 2498 |
$transcripts_js_version, |
| 2499 |
true |
| 2500 |
); |
| 2501 |
|
| 2502 |
wp_enqueue_script( |
| 2503 |
'mxchat-admin-js', |
| 2504 |
plugin_dir_url(__FILE__) . '../js/mxchat-admin.js', |
| 2505 |
array('jquery'), |
| 2506 |
$plugin_version, |
| 2507 |
true |
| 2508 |
); |
| 2509 |
|
| 2510 |
wp_localize_script('mxchat-admin-js', 'mxchatAdmin', array( |
| 2511 |
'ajax_url' => admin_url('admin-ajax.php'), |
| 2512 |
'nonce' => wp_create_nonce('mxchat_activate_license_nonce'), |
| 2513 |
)); |
| 2514 |
|
| 2515 |
wp_enqueue_style( |
| 2516 |
'mxchat-admin-css', |
| 2517 |
plugin_dir_url(__FILE__) . '../css/admin-style.css', |
| 2518 |
array(), |
| 2519 |
$admin_css_version |
| 2520 |
); |
| 2521 |
|
| 2522 |
wp_localize_script('mxchat-color-picker', 'mxchatStyleSettings', array( |
| 2523 |
'ajax_url' => admin_url('admin-ajax.php'), |
| 2524 |
'link_target_toggle' => $this->options['link_target_toggle'] ?? 'off', |
| 2525 |
'user_message_bg_color' => $this->options['user_message_bg_color'] ?? '#fff', |
| 2526 |
'user_message_font_color' => $this->options['user_message_font_color'] ?? '#212121', |
| 2527 |
'bot_message_bg_color' => $this->options['bot_message_bg_color'] ?? '#212121', |
| 2528 |
'bot_message_font_color' => $this->options['bot_message_font_color'] ?? '#fff', |
| 2529 |
'top_bar_bg_color' => $this->options['top_bar_bg_color'] ?? '#212121', |
| 2530 |
'send_button_font_color' => $this->options['send_button_font_color'] ?? '#212121', |
| 2531 |
'close_button_color' => $this->options['close_button_color'] ?? '#fff', |
| 2532 |
'chatbot_background_color' => $this->options['chatbot_background_color'] ?? '#212121', |
| 2533 |
'icon_color' => $this->options['icon_color'] ?? '#fff', |
| 2534 |
'chat_input_font_color' => $this->options['chat_input_font_color'] ?? '#212121', |
| 2535 |
'pre_chat_message' => $this->options['pre_chat_message'] ?? 'Hey there! Ask me anything!', |
| 2536 |
'rate_limit_message' => $this->options['rate_limit_message'] ?? 'Rate limit exceeded. Please try again later.', |
| 2537 |
|
| 2538 |
// New fields for Loops Integration |
| 2539 |
'loops_api_key' => $this->options['loops_api_key'] ?? '', |
| 2540 |
'loops_mailing_list' => $this->options['loops_mailing_list'] ?? '', |
| 2541 |
'triggered_phrase_response' => $this->options['triggered_phrase_response'] ?? 'Would you like to join our mailing list? Please provide your email below.', |
| 2542 |
'email_capture_response' => $this->options['email_capture_response'] ?? 'Thank you for providing your email! You\'ve been added to our list.' |
| 2543 |
)); |
| 2544 |
|
| 2545 |
// Localize the script to pass the nonce and other data to JavaScript |
| 2546 |
wp_localize_script('mxchat-admin-js', 'mxchatInlineEdit', array( |
| 2547 |
'nonce' => wp_create_nonce('mxchat_save_inline_nonce'), |
| 2548 |
'ajax_url' => admin_url('admin-ajax.php') |
| 2549 |
)); |
| 2550 |
|
| 2551 |
|
| 2552 |
} |
| 2553 |
|
| 2554 |
public function mxchat_sanitize($input) { |
| 2555 |
$new_input = array(); |
| 2556 |
|
| 2557 |
if (isset($input['api_key'])) { |
| 2558 |
$new_input['api_key'] = sanitize_text_field($input['api_key']); |
| 2559 |
} |
| 2560 |
|
| 2561 |
if (isset($input['xai_api_key'])) { |
| 2562 |
$new_input['xai_api_key'] = sanitize_text_field($input['xai_api_key']); |
| 2563 |
} |
| 2564 |
|
| 2565 |
if (isset($input['claude_api_key'])) { |
| 2566 |
$new_input['claude_api_key'] = sanitize_text_field($input['claude_api_key']); |
| 2567 |
} |
| 2568 |
|
| 2569 |
if (isset($input['enable_woocommerce_integration'])) { |
| 2570 |
$new_input['enable_woocommerce_integration'] = isset($input['enable_woocommerce_integration']) && $input['enable_woocommerce_integration'] === '1' ? '1' : '0'; |
| 2571 |
|
| 2572 |
} |
| 2573 |
|
| 2574 |
if (isset($input['privacy_toggle'])) { |
| 2575 |
$new_input['privacy_toggle'] = $input['privacy_toggle']; |
| 2576 |
} |
| 2577 |
|
| 2578 |
if (isset($input['complianz_toggle'])) { |
| 2579 |
$new_input['complianz_toggle'] = $input['complianz_toggle']; |
| 2580 |
} |
| 2581 |
|
| 2582 |
// Handle custom privacy text input |
| 2583 |
if (isset($input['privacy_text'])) { |
| 2584 |
// Allow basic HTML for links |
| 2585 |
$new_input['privacy_text'] = wp_kses_post($input['privacy_text']); |
| 2586 |
} |
| 2587 |
|
| 2588 |
if (isset($input['system_prompt_instructions'])) { |
| 2589 |
$new_input['system_prompt_instructions'] = sanitize_textarea_field($input['system_prompt_instructions']); |
| 2590 |
} |
| 2591 |
|
| 2592 |
if (isset($input['mxchat_pro_email'])) { |
| 2593 |
$new_input['mxchat_pro_email'] = sanitize_email($input['mxchat_pro_email']); |
| 2594 |
} |
| 2595 |
|
| 2596 |
if (isset($input['mxchat_activation_key'])) { |
| 2597 |
$new_input['mxchat_activation_key'] = sanitize_text_field($input['mxchat_activation_key']); |
| 2598 |
} |
| 2599 |
|
| 2600 |
if (isset($input['append_to_body'])) { |
| 2601 |
$new_input['append_to_body'] = $input['append_to_body'] === 'on' ? 'on' : 'off'; |
| 2602 |
} |
| 2603 |
|
| 2604 |
if (isset($input['top_bar_title'])) { |
| 2605 |
$new_input['top_bar_title'] = sanitize_text_field($input['top_bar_title']); |
| 2606 |
} |
| 2607 |
|
| 2608 |
if (isset($input['intro_message'])) { |
| 2609 |
$new_input['intro_message'] = sanitize_text_field($input['intro_message']); |
| 2610 |
} |
| 2611 |
|
| 2612 |
if (isset($input['input_copy'])) { |
| 2613 |
$new_input['input_copy'] = sanitize_text_field($input['input_copy']); |
| 2614 |
} |
| 2615 |
|
| 2616 |
|
| 2617 |
if (isset($input['rate_limit_message'])) { |
| 2618 |
$new_input['rate_limit_message'] = sanitize_text_field($input['rate_limit_message']); |
| 2619 |
} |
| 2620 |
|
| 2621 |
if (isset($input['rate_limit'])) { |
| 2622 |
$allowed_limits = array('5', '10', '15', '20', '100', 'unlimited'); // Add 'unlimited' to allowed values |
| 2623 |
$rate_limit = sanitize_text_field($input['rate_limit']); |
| 2624 |
|
| 2625 |
if (in_array($rate_limit, $allowed_limits, true)) { |
| 2626 |
$new_input['rate_limit'] = $rate_limit; |
| 2627 |
} else { |
| 2628 |
// Set a default or fallback value in case of an invalid entry |
| 2629 |
$new_input['rate_limit'] = '100'; |
| 2630 |
} |
| 2631 |
} |
| 2632 |
|
| 2633 |
|
| 2634 |
if (isset($input['pre_chat_message'])) { |
| 2635 |
$new_input['pre_chat_message'] = sanitize_textarea_field($input['pre_chat_message']); |
| 2636 |
} |
| 2637 |
|
| 2638 |
if (isset($input['model'])) { |
| 2639 |
$allowed_models = array( |
| 2640 |
'grok-beta', |
| 2641 |
'claude-3-5-sonnet-20241022', |
| 2642 |
'claude-3-opus-20240229', |
| 2643 |
'claude-3-sonnet-20240229', |
| 2644 |
'claude-3-haiku-20240307', |
| 2645 |
'gpt-4o', |
| 2646 |
'gpt-4o-mini', |
| 2647 |
'gpt-4-turbo', |
| 2648 |
'gpt-4', |
| 2649 |
'gpt-3.5-turbo', |
| 2650 |
); |
| 2651 |
if (in_array($input['model'], $allowed_models)) { |
| 2652 |
$new_input['model'] = sanitize_text_field($input['model']); |
| 2653 |
} |
| 2654 |
} |
| 2655 |
|
| 2656 |
// Sanitize new pro features |
| 2657 |
if (isset($input['close_button_color'])) { |
| 2658 |
$new_input['close_button_color'] = sanitize_hex_color($input['close_button_color']); |
| 2659 |
} |
| 2660 |
|
| 2661 |
if (isset($input['chatbot_bg_color'])) { |
| 2662 |
$new_input['chatbot_bg_color'] = sanitize_hex_color($input['chatbot_bg_color']); |
| 2663 |
} |
| 2664 |
|
| 2665 |
if (isset($input['woocommerce_consumer_key'])) { |
| 2666 |
$new_input['woocommerce_consumer_key'] = sanitize_text_field($input['woocommerce_consumer_key']); |
| 2667 |
} |
| 2668 |
|
| 2669 |
if (isset($input['woocommerce_consumer_secret'])) { |
| 2670 |
$new_input['woocommerce_consumer_secret'] = sanitize_text_field($input['woocommerce_consumer_secret']); |
| 2671 |
} |
| 2672 |
|
| 2673 |
if (isset($input['user_message_bg_color'])) { |
| 2674 |
$new_input['user_message_bg_color'] = sanitize_hex_color($input['user_message_bg_color']); |
| 2675 |
} |
| 2676 |
|
| 2677 |
if (isset($input['user_message_font_color'])) { |
| 2678 |
$new_input['user_message_font_color'] = sanitize_hex_color($input['user_message_font_color']); |
| 2679 |
} |
| 2680 |
|
| 2681 |
if (isset($input['bot_message_bg_color'])) { |
| 2682 |
$new_input['bot_message_bg_color'] = sanitize_hex_color($input['bot_message_bg_color']); |
| 2683 |
} |
| 2684 |
|
| 2685 |
if (isset($input['bot_message_font_color'])) { |
| 2686 |
$new_input['bot_message_font_color'] = sanitize_hex_color($input['bot_message_font_color']); |
| 2687 |
} |
| 2688 |
|
| 2689 |
if (isset($input['top_bar_bg_color'])) { |
| 2690 |
$new_input['top_bar_bg_color'] = sanitize_hex_color($input['top_bar_bg_color']); |
| 2691 |
} |
| 2692 |
|
| 2693 |
if (isset($input['send_button_font_color'])) { |
| 2694 |
$new_input['send_button_font_color'] = sanitize_hex_color($input['send_button_font_color']); |
| 2695 |
} |
| 2696 |
|
| 2697 |
if (isset($input['chatbot_background_color'])) { |
| 2698 |
$new_input['chatbot_background_color'] = sanitize_hex_color($input['chatbot_background_color']); |
| 2699 |
} |
| 2700 |
|
| 2701 |
if (isset($input['icon_color'])) { |
| 2702 |
$new_input['icon_color'] = sanitize_hex_color($input['icon_color']); |
| 2703 |
} |
| 2704 |
|
| 2705 |
if (isset($input['chat_input_font_color'])) { |
| 2706 |
$new_input['chat_input_font_color'] = sanitize_hex_color($input['chat_input_font_color']); |
| 2707 |
} |
| 2708 |
|
| 2709 |
// Sanitize link_target_toggle |
| 2710 |
if (isset($input['link_target_toggle'])) { |
| 2711 |
$new_input['link_target_toggle'] = $input['link_target_toggle'] === 'on' ? 'on' : 'off'; |
| 2712 |
} |
| 2713 |
|
| 2714 |
// Sanitize Loops API Key |
| 2715 |
if (isset($input['loops_api_key'])) { |
| 2716 |
$new_input['loops_api_key'] = sanitize_text_field($input['loops_api_key']); |
| 2717 |
} |
| 2718 |
|
| 2719 |
if (isset($input['chat_persistence_toggle'])) { |
| 2720 |
$new_input['chat_persistence_toggle'] = $input['chat_persistence_toggle'] === 'on' ? 'on' : 'off'; |
| 2721 |
} |
| 2722 |
|
| 2723 |
|
| 2724 |
|
| 2725 |
if (isset($input['popular_question_1'])) { |
| 2726 |
$new_input['popular_question_1'] = sanitize_text_field($input['popular_question_1']); |
| 2727 |
} |
| 2728 |
|
| 2729 |
if (isset($input['popular_question_2'])) { |
| 2730 |
$new_input['popular_question_2'] = sanitize_text_field($input['popular_question_2']); |
| 2731 |
} |
| 2732 |
|
| 2733 |
if (isset($input['popular_question_3'])) { |
| 2734 |
$new_input['popular_question_3'] = sanitize_text_field($input['popular_question_3']); |
| 2735 |
} |
| 2736 |
|
| 2737 |
|
| 2738 |
// Sanitize Loops Mailing List |
| 2739 |
if (isset($input['loops_mailing_list'])) { |
| 2740 |
$new_input['loops_mailing_list'] = sanitize_text_field($input['loops_mailing_list']); |
| 2741 |
} |
| 2742 |
|
| 2743 |
// Sanitize Triggered Phrase Response |
| 2744 |
if (isset($input['triggered_phrase_response'])) { |
| 2745 |
$new_input['triggered_phrase_response'] = wp_kses_post($input['triggered_phrase_response']); |
| 2746 |
} |
| 2747 |
|
| 2748 |
if (isset($input['email_capture_response'])) { |
| 2749 |
$new_input['email_capture_response'] = sanitize_textarea_field($input['email_capture_response']); |
| 2750 |
} |
| 2751 |
|
| 2752 |
|
| 2753 |
// Sanitize Brave Search Settings |
| 2754 |
if (isset($input['brave_api_key'])) { |
| 2755 |
$new_input['brave_api_key'] = sanitize_text_field($input['brave_api_key']); |
| 2756 |
} |
| 2757 |
|
| 2758 |
if (isset($input['brave_image_count'])) { |
| 2759 |
$image_count = intval($input['brave_image_count']); |
| 2760 |
$new_input['brave_image_count'] = ($image_count >=1 && $image_count <=6) ? $image_count : 4; |
| 2761 |
} |
| 2762 |
|
| 2763 |
if (isset($input['brave_safe_search'])) { |
| 2764 |
$allowed = array('strict', 'off'); |
| 2765 |
$new_input['brave_safe_search'] = in_array($input['brave_safe_search'], $allowed, true) ? $input['brave_safe_search'] : 'strict'; |
| 2766 |
} |
| 2767 |
|
| 2768 |
if (isset($input['brave_news_count'])) { |
| 2769 |
$news_count = intval($input['brave_news_count']); |
| 2770 |
$new_input['brave_news_count'] = ($news_count >=1 && $news_count <=10) ? $news_count : 3; |
| 2771 |
} |
| 2772 |
|
| 2773 |
if (isset($input['brave_country'])) { |
| 2774 |
$new_input['brave_country'] = sanitize_text_field($input['brave_country']); |
| 2775 |
} |
| 2776 |
|
| 2777 |
if (isset($input['brave_language'])) { |
| 2778 |
$new_input['brave_language'] = sanitize_text_field($input['brave_language']); |
| 2779 |
} |
| 2780 |
|
| 2781 |
|
| 2782 |
|
| 2783 |
|
| 2784 |
|
| 2785 |
|
| 2786 |
|
| 2787 |
return $new_input; |
| 2788 |
} |
| 2789 |
|
| 2790 |
|
| 2791 |
// Method to append the chatbot to the body |
| 2792 |
public function mxchat_append_chatbot_to_body() { |
| 2793 |
$options = get_option('mxchat_options'); |
| 2794 |
if (isset($options['append_to_body']) && $options['append_to_body'] === 'on') { |
| 2795 |
echo do_shortcode('[mxchat_chatbot floating="yes"]'); |
| 2796 |
} |
| 2797 |
} |
| 2798 |
|
| 2799 |
|
| 2800 |
|
| 2801 |
private function mxchat_extract_main_content($html) { |
| 2802 |
$dom = new DOMDocument; |
| 2803 |
libxml_use_internal_errors(true); // Suppress HTML parsing errors |
| 2804 |
@$dom->loadHTML($html); |
| 2805 |
libxml_clear_errors(); |
| 2806 |
|
| 2807 |
$xpath = new DOMXPath($dom); |
| 2808 |
|
| 2809 |
// Simplified selectors focusing on common content areas |
| 2810 |
$selectors = [ |
| 2811 |
'//article', |
| 2812 |
'//*[@id="content"]', |
| 2813 |
'//*[@class="entry-content"]', |
| 2814 |
'//main', |
| 2815 |
]; |
| 2816 |
|
| 2817 |
foreach ($selectors as $selector) { |
| 2818 |
$nodes = $xpath->query($selector); |
| 2819 |
if ($nodes->length > 0) { |
| 2820 |
$content = ''; |
| 2821 |
foreach ($nodes as $node) { |
| 2822 |
$content .= $dom->saveHTML($node); |
| 2823 |
} |
| 2824 |
return $content; |
| 2825 |
} |
| 2826 |
} |
| 2827 |
|
| 2828 |
// Fallback: Return the entire body content if no specific selector matches |
| 2829 |
$body = $dom->getElementsByTagName('body'); |
| 2830 |
return $body->length > 0 ? $dom->saveHTML($body->item(0)) : $html; |
| 2831 |
} |
| 2832 |
|
| 2833 |
public function mxchat_handle_sitemap_submission() { |
| 2834 |
// Check if the form was submitted and the user has sufficient permissions |
| 2835 |
if (!isset($_POST['submit_sitemap']) || !current_user_can('manage_options')) { |
| 2836 |
return; |
| 2837 |
} |
| 2838 |
|
| 2839 |
// Verify the nonce field for security |
| 2840 |
check_admin_referer('mxchat_submit_sitemap_action', 'mxchat_submit_sitemap_nonce'); |
| 2841 |
|
| 2842 |
// Sanitize and retrieve the submitted URL |
| 2843 |
$submitted_url = esc_url_raw($_POST['sitemap_url']); // Accept either a sitemap URL or a regular URL |
| 2844 |
|
| 2845 |
// Fetch the content of the submitted URL |
| 2846 |
$response = wp_remote_get($submitted_url); |
| 2847 |
if (is_wp_error($response) || wp_remote_retrieve_response_code($response) !== 200) { |
| 2848 |
set_transient('mxchat_admin_notice_error', 'Failed to fetch the URL. Please check the URL and try again.', 30); |
| 2849 |
wp_safe_redirect(esc_url(admin_url('admin.php?page=mxchat-prompts'))); |
| 2850 |
exit; |
| 2851 |
} |
| 2852 |
|
| 2853 |
$content_type = wp_remote_retrieve_header($response, 'content-type'); |
| 2854 |
$body_content = wp_remote_retrieve_body($response); |
| 2855 |
|
| 2856 |
// Check if the URL points to a sitemap (XML) or a regular HTML page |
| 2857 |
if (strpos($content_type, 'xml') !== false || strpos($body_content, '<urlset') !== false) { |
| 2858 |
// Handle Sitemap XML |
| 2859 |
$xml = simplexml_load_string($body_content); |
| 2860 |
if ($xml === false) { |
| 2861 |
set_transient('mxchat_admin_notice_error', 'Invalid sitemap XML. Please provide a valid sitemap.', 30); |
| 2862 |
wp_safe_redirect(esc_url(admin_url('admin.php?page=mxchat-prompts'))); |
| 2863 |
exit; |
| 2864 |
} |
| 2865 |
|
| 2866 |
$embedding_success = true; // Flag to track if all embeddings are successful |
| 2867 |
|
| 2868 |
foreach ($xml->url as $url_element) { |
| 2869 |
$page_url = (string)$url_element->loc; |
| 2870 |
|
| 2871 |
$page_response = wp_remote_get($page_url); |
| 2872 |
if (is_wp_error($page_response) || wp_remote_retrieve_response_code($page_response) !== 200) { |
| 2873 |
continue; |
| 2874 |
} |
| 2875 |
|
| 2876 |
$page_html = wp_remote_retrieve_body($page_response); |
| 2877 |
$page_content = $this->mxchat_extract_main_content($page_html); |
| 2878 |
$sanitized_content = $this->mxchat_sanitize_content_for_api($page_content); |
| 2879 |
|
| 2880 |
if (!empty($sanitized_content)) { |
| 2881 |
$embedding_vector = $this->mxchat_generate_embedding($sanitized_content); |
| 2882 |
if (is_array($embedding_vector)) { |
| 2883 |
MxChat_Utils::submit_content_to_db($sanitized_content, $page_url, $this->options['api_key']); |
| 2884 |
} else { |
| 2885 |
$embedding_success = false; // Set flag to false if any embedding fails |
| 2886 |
} |
| 2887 |
} |
| 2888 |
} |
| 2889 |
|
| 2890 |
if ($embedding_success) { |
| 2891 |
set_transient('mxchat_admin_notice_success', 'Sitemap content successfully submitted!', 30); |
| 2892 |
} else { |
| 2893 |
set_transient('mxchat_admin_notice_error', 'Some content failed to embed. Please check your API key and try again.', 30); |
| 2894 |
} |
| 2895 |
|
| 2896 |
} else { |
| 2897 |
// Handle Regular URL (HTML Page) |
| 2898 |
$page_content = $this->mxchat_extract_main_content($body_content); |
| 2899 |
$sanitized_content = $this->mxchat_sanitize_content_for_api($page_content); |
| 2900 |
|
| 2901 |
if (!empty($sanitized_content)) { |
| 2902 |
$embedding_vector = $this->mxchat_generate_embedding($sanitized_content); |
| 2903 |
if (is_array($embedding_vector)) { |
| 2904 |
MxChat_Utils::submit_content_to_db($sanitized_content, $submitted_url, $this->options['api_key']); |
| 2905 |
set_transient('mxchat_admin_notice_success', 'URL content successfully submitted!', 30); |
| 2906 |
} else { |
| 2907 |
set_transient('mxchat_admin_notice_error', 'Failed to generate embedding for the URL content. Please check your API key and try again.', 30); |
| 2908 |
} |
| 2909 |
} else { |
| 2910 |
set_transient('mxchat_admin_notice_error', 'No valid content found on the provided URL.', 30); |
| 2911 |
} |
| 2912 |
} |
| 2913 |
|
| 2914 |
// Redirect after setting the transient |
| 2915 |
wp_safe_redirect(esc_url(admin_url('admin.php?page=mxchat-prompts'))); |
| 2916 |
exit; |
| 2917 |
} |
| 2918 |
|
| 2919 |
|
| 2920 |
|
| 2921 |
private function mxchat_sanitize_content_for_api($content) { |
| 2922 |
// Remove script, style tags, and HTML comments |
| 2923 |
$content = preg_replace('/<script\b[^>]*>(.*?)<\/script>/is', '', $content); |
| 2924 |
$content = preg_replace('/<style\b[^>]*>(.*?)<\/style>/is', '', $content); |
| 2925 |
$content = preg_replace('/<!--(.|\s)*?-->/', '', $content); |
| 2926 |
|
| 2927 |
// Remove all HTML tags and decode HTML entities |
| 2928 |
$content = wp_strip_all_tags($content); |
| 2929 |
$content = html_entity_decode($content, ENT_QUOTES | ENT_HTML5); |
| 2930 |
|
| 2931 |
// Trim and normalize whitespace |
| 2932 |
$content = trim(preg_replace('/\s+/', ' ', $content)); |
| 2933 |
|
| 2934 |
return $content; |
| 2935 |
} |
| 2936 |
|
| 2937 |
|
| 2938 |
|
| 2939 |
private function mxchat_fetch_loops_mailing_lists($api_key) { |
| 2940 |
$url = 'https://app.loops.so/api/v1/lists'; |
| 2941 |
$response = wp_remote_get($url, array( |
| 2942 |
'headers' => array( |
| 2943 |
'Authorization' => 'Bearer ' . $api_key, |
| 2944 |
'Content-Type' => 'application/json' |
| 2945 |
) |
| 2946 |
)); |
| 2947 |
|
| 2948 |
if (is_wp_error($response)) { |
| 2949 |
return array(); |
| 2950 |
} |
| 2951 |
|
| 2952 |
$body = wp_remote_retrieve_body($response); |
| 2953 |
$lists = json_decode($body, true); |
| 2954 |
|
| 2955 |
return isset($lists) && is_array($lists) ? $lists : array(); |
| 2956 |
} |
| 2957 |
|
| 2958 |
|
| 2959 |
|
| 2960 |
|
| 2961 |
|
| 2962 |
function mxchat_calculate_cosine_similarity($vec1, $vec2) { |
| 2963 |
if (empty($vec1) || empty($vec2)) { |
| 2964 |
return 0.0; |
| 2965 |
} |
| 2966 |
|
| 2967 |
$dot_product = 0.0; |
| 2968 |
$norm_a = 0.0; |
| 2969 |
$norm_b = 0.0; |
| 2970 |
|
| 2971 |
for ($i = 0; $i < count($vec1); $i++) { |
| 2972 |
$dot_product += $vec1[$i] * $vec2[$i]; |
| 2973 |
$norm_a += pow($vec1[$i], 2); |
| 2974 |
$norm_b += pow($vec2[$i], 2); |
| 2975 |
} |
| 2976 |
|
| 2977 |
if ($norm_a == 0.0 || $norm_b == 0.0) { |
| 2978 |
return 0.0; |
| 2979 |
} else { |
| 2980 |
return $dot_product / (sqrt($norm_a) * sqrt($norm_b)); |
| 2981 |
} |
| 2982 |
} |
| 2983 |
|
| 2984 |
|
| 2985 |
|
| 2986 |
|
| 2987 |
} |
| 2988 |
?> |
| 2989 |
|