options = get_option('mxchat_options'); $this->chat_count = get_option('mxchat_chat_count', 0); $this->is_activated = $this->is_license_active(); // Initialize default options if they are not set if (!$this->options) { $this->initialize_default_options(); } // Add admin menu and initialize settings add_action('admin_menu', array($this, 'mxchat_add_plugin_page')); add_action('admin_init', array($this, 'mxchat_page_init')); add_action('admin_init', array($this, 'mxchat_prompts_page_init')); // Add this line add_action('admin_enqueue_scripts', array($this, 'mxchat_enqueue_admin_assets')); add_action('wp_ajax_mxchat_delete_chat_history', array($this, 'mxchat_delete_chat_history')); add_action('admin_post_mxchat_submit_content', array($this, 'mxchat_handle_content_submission')); add_action('admin_post_mxchat_delete_prompt', array($this, 'mxchat_handle_delete_prompt')); add_action('wp_ajax_mxchat_fetch_chat_history', array($this, 'mxchat_fetch_chat_history')); add_action('wp_ajax_nopriv_mxchat_fetch_chat_history', array($this, 'mxchat_fetch_chat_history')); add_action('admin_post_mxchat_submit_sitemap', array($this, 'mxchat_handle_sitemap_submission')); add_action('wp_footer', array($this, 'mxchat_append_chatbot_to_body')); add_action('admin_head-mxchat-prompts', array($this, 'mxchat_enqueue_admin_assets')); add_action('admin_head-toplevel_page_mxchat-max', array($this, 'mxchat_enqueue_admin_assets')); add_action('wp_ajax_mxchat_activate_license', array($this, 'mxchat_handle_activate_license')); add_action('admin_notices', array($this, 'mxchat_display_admin_notice')); // Add the AJAX handler for logged-in users add_action('wp_ajax_mxchat_save_inline_prompt', array($this, 'mxchat_save_inline_prompt')); add_action('admin_post_mxchat_delete_all_prompts', array($this, 'mxchat_handle_delete_all_prompts')); // Define admin_post actions for form submission handling add_action('admin_post_mxchat_add_intent', array($this, 'mxchat_handle_add_intent')); add_action('admin_post_mxchat_delete_intent', array($this, 'mxchat_handle_delete_intent')); add_action('admin_post_mxchat_update_intent_threshold', array($this, 'mxchat_handle_update_intent_threshold')); add_action('admin_post_mxchat_stop_processing', array($this, 'mxchat_stop_processing')); add_action('admin_post_mxchat_edit_intent', array($this, 'handle_edit_intent')); add_action('save_post', array($this, 'handle_post_update'), 10, 3); add_action('post_updated', array($this, 'handle_post_update'), 10, 3); add_action('wp_ajax_mxchat_save_setting', array($this, 'mxchat_save_setting_callback')); } // Method to check if the license is active private function is_license_active() { $license_status = get_option('mxchat_license_status', esc_html__('inactive', 'mxchat')); return $license_status === esc_html__('active', 'mxchat'); } // Initialize default options private function initialize_default_options() { $default_options = array( 'api_key' => '', 'xai_api_key' => '', 'claude_api_key' => '', 'deepseek_api_key' => '', 'system_prompt_instructions' => esc_html__('[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: - Your name is [Chatbot Name]. - 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. - Do not make up links to pages. Only use specific links you see in your knowledgebase. - Keep your responses short, concise, and to the point. Provide clear and direct answers suitable for a chatbot interaction. - 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.', 'mxchat'), 'model' => esc_html__('gpt-4o', 'mxchat'), 'rate_limit_logged_out' => esc_html__('100', 'mxchat'), 'role_rate_limits' => array(), 'rate_limit_message' => esc_html__('Rate limit exceeded. Please try again later.', 'mxchat'), 'enable_email_block' => '', 'email_blocker_header_content' => esc_html__("

Welcome to Our Chat!

\n

Let's get started. Enter your email to begin chatting with us.

", 'mxchat'), 'email_blocker_button_text' => esc_html__('Start Chat', 'mxchat'), 'top_bar_title' => esc_html__('MxChat', 'mxchat'), 'intro_message' => esc_html__('Hello! How can I assist you today?', 'mxchat'), 'input_copy' => esc_html__('How can I assist?', 'mxchat'), 'append_to_body' => esc_html__('off', 'mxchat'), 'close_button_color' => esc_html__('#fff', 'mxchat'), 'chatbot_bg_color' => esc_html__('#fff', 'mxchat'), 'user_message_bg_color' => esc_html__('#fff', 'mxchat'), 'user_message_font_color' => esc_html__('#212121', 'mxchat'), 'bot_message_bg_color' => esc_html__('#212121', 'mxchat'), 'bot_message_font_color' => esc_html__('#fff', 'mxchat'), 'top_bar_bg_color' => esc_html__('#212121', 'mxchat'), 'send_button_font_color' => esc_html__('#212121', 'mxchat'), 'chat_input_font_color' => esc_html__('#212121', 'mxchat'), 'chatbot_background_color' => esc_html__('#212121', 'mxchat'), 'icon_color' => esc_html__('#fff', 'mxchat'), 'enable_woocommerce_integration' => esc_html__('0', 'mxchat'), 'link_target_toggle' => esc_html__('off', 'mxchat'), 'pre_chat_message' => esc_html__('Hey there! Ask me anything!', 'mxchat'), // New fields for Loops Integration 'loops_api_key' => '', 'loops_mailing_list' => '', 'triggered_phrase_response' => esc_html__('Would you like to join our mailing list? Please provide your email below.', 'mxchat'), 'email_capture_response' => esc_html__('Thank you for providing your email! You\'ve been added to our list.', 'mxchat'), 'popular_question_1' => '', 'popular_question_2' => '', 'popular_question_3' => '', 'pdf_intent_trigger_text' => esc_html__("Please provide the URL to the PDF you'd like to discuss.", 'mxchat'), 'pdf_intent_success_text' => esc_html__("I've processed the PDF. What questions do you have about it?", 'mxchat'), 'pdf_intent_error_text' => esc_html__("Sorry, I couldn't process the PDF. Please ensure it's a valid file.", 'mxchat'), 'pdf_max_pages' => 69, // Live Agent Integration 'live_agent_webhook_url' => '', 'live_agent_secret_key' => '', 'live_agent_bot_token' => '', 'live_agent_message_bg_color' => esc_html__('#ffffff', 'mxchat'), 'live_agent_message_font_color' => esc_html__('#333333', 'mxchat'), 'chat_toolbar_toggle' => esc_html__('off', 'mxchat'), 'mode_indicator_bg_color' => esc_html__('#767676', 'mxchat'), 'mode_indicator_font_color' => esc_html__('#ffffff', 'mxchat'), 'toolbar_icon_color' => esc_html__('#212121', 'mxchat'), ); // Merge existing options with defaults $existing_options = get_option('mxchat_options', array()); $merged_options = wp_parse_args($existing_options, $default_options); // Update the options if they have changed if ($existing_options !== $merged_options) { update_option('mxchat_options', $merged_options); } // Add default limits for each role $roles = wp_roles()->get_names(); foreach ($roles as $role_id => $role_name) { $default_options['role_rate_limits'][$role_id] = esc_html__('100', 'mxchat'); } return $default_options; // Update the $this->options property $this->options = $merged_options; } public function mxchat_add_plugin_page() { // Main menu page add_menu_page( esc_html__('MxChat Settings', 'mxchat'), esc_html__('MxChat', 'mxchat'), 'manage_options', 'mxchat-max', array($this, 'mxchat_create_admin_page'), 'dashicons-testimonial', 6 ); // Submenu page for Knowledge add_submenu_page( 'mxchat-max', esc_html__('Prompts', 'mxchat'), esc_html__('Knowledge', 'mxchat'), 'manage_options', 'mxchat-prompts', array($this, 'mxchat_create_prompts_page') ); // Submenu page for Chat Transcripts add_submenu_page( 'mxchat-max', // Corrected parent slug to match the main menu esc_html__('Chat Transcripts', 'mxchat'), esc_html__('Transcripts', 'mxchat'), 'manage_options', 'mxchat-transcripts', array($this, 'mxchat_create_transcripts_page') // Prefixed function name with mxchat_ ); // Submenu page for Intents add_submenu_page( 'mxchat-max', // Parent slug esc_html__('MxChat Intents', 'mxchat'), // Page title esc_html__('Intents', 'mxchat'), // Menu title 'manage_options', // Capability 'mxchat-intents', // Menu slug array($this, 'mxchat_intents_page_html') // Callback function ); // Submenu page for Activation Key add_submenu_page( 'mxchat-max', esc_html__('Pro Upgrade', 'mxchat'), esc_html__('Pro Upgrade', 'mxchat'), 'manage_options', 'mxchat-activation', array($this, 'mxchat_create_activation_page') ); } public function mxchat_save_setting_callback() { check_ajax_referer('mxchat_save_setting_nonce'); if (!current_user_can('manage_options')) { wp_send_json_error(['message' => esc_html__('Unauthorized', 'mxchat')]); } $name = isset($_POST['name']) ? $_POST['name'] : ''; // Strip slashes from the value before saving $value = isset($_POST['value']) ? stripslashes($_POST['value']) : ''; if (empty($name)) { wp_send_json_error(['message' => esc_html__('Invalid field name', 'mxchat')]); } // Load the full options array $options = get_option('mxchat_options', []); // Handle special cases switch ($name) { case 'additional_popular_questions': $questions = json_decode($value, true); // No need for stripslashes here if (is_array($questions)) { $options[$name] = $questions; // Also update old option for backwards compatibility update_option('additional_popular_questions', $questions); } break; case 'close_button_color': case 'user_message_bg_color': case 'user_message_font_color': case 'bot_message_bg_color': case 'bot_message_font_color': case 'top_bar_bg_color': case 'send_button_font_color': case 'chatbot_background_color': case 'icon_color': case 'chat_input_font_color': case 'live_agent_message_bg_color': case 'live_agent_message_font_color': case 'mode_indicator_bg_color': case 'mode_indicator_font_color': case 'toolbar_icon_color': // Store color values directly $options[$name] = $value; break; case 'live_agent_status': // Set the new value $options[$name] = ($value === 'on') ? 'on' : 'off'; break; case 'enable_woocommerce_integration': // Handle values that used to be 1/0 $options[$name] = ($value === 'on' || $value === '1') ? 'on' : 'off'; break; default: // Handle role rate limits if (strpos($name, 'mxchat_options[role_rate_limits]') !== false) { // Extract role ID from the name preg_match('/\[role_rate_limits\]\[(.*?)\]/', $name, $matches); if (isset($matches[1])) { $role_id = $matches[1]; // Initialize role_rate_limits if it doesn't exist if (!isset($options['role_rate_limits'])) { $options['role_rate_limits'] = []; } // Update the specific role's rate limit $options['role_rate_limits'][$role_id] = sanitize_text_field($value); break; } } // Handle toggles if (strpos($name, 'toggle') !== false || in_array($name, [ 'chat_persistence_toggle', 'privacy_toggle', 'complianz_toggle', 'chat_toolbar_toggle' // Removed live_agent_status from here ])) { $options[$name] = ($value === 'on') ? 'on' : 'off'; } else { // Store all other values directly $options[$name] = $value; } break; } // Save all updates $updated = update_option('mxchat_options', $options); // Handle backwards compatibility for certain fields $legacy_fields = ['brave_api_key', 'brave_image_count', 'brave_safe_search', 'brave_news_count', 'brave_country', 'brave_language', 'similarity_threshold']; if (in_array($name, $legacy_fields)) { // Also update the individual option for backwards compatibility update_option($name, $value); } if ($updated) { wp_send_json_success(['message' => esc_html__('Setting saved', 'mxchat')]); } else { wp_send_json_error(['message' => esc_html__('Update failed or no changes', 'mxchat')]); } } public function mxchat_display_admin_notice() { // Success notice if ($message = get_transient('mxchat_admin_notice_success')) { ?>

is_activated): ?>

.

.

.

.

.

[mxchat_chatbot floating="yes"] [mxchat_chatbot floating="no"].

.

prefix . 'mxchat_chat_transcripts'; // Get basic stats $total_chats = $wpdb->get_var("SELECT COUNT(DISTINCT session_id) FROM $table_name"); $total_messages = $wpdb->get_var("SELECT COUNT(*) FROM $table_name"); $total_users = $wpdb->get_var("SELECT COUNT(DISTINCT user_email) FROM $table_name WHERE user_email != ''"); ?>
💬
📝
👥
prefix . 'mxchat_system_prompt_content'; // Display success message if all prompts were deleted if (isset($_GET['all_deleted']) && $_GET['all_deleted'] === 'true') { echo '

' . esc_html__('All knowledge has been deleted successfully.', 'mxchat') . '

'; } // Set up pagination and search query $nonce = isset($_GET['_wpnonce']) ? sanitize_text_field($_GET['_wpnonce']) : ''; $search_query = (!empty($nonce) && wp_verify_nonce($nonce, 'mxchat_prompts_search_nonce') && isset($_GET['search'])) ? sanitize_text_field($_GET['search']) : ''; $current_page = isset($_GET['paged']) ? absint($_GET['paged']) : 1; $per_page = 10; $offset = ($current_page - 1) * $per_page; // Modify query to handle search input $sql_search = ""; if ($search_query) { $sql_search = $wpdb->prepare("WHERE article_content LIKE %s", '%' . $wpdb->esc_like($search_query) . '%'); } // Retrieve total number of prompts, considering search filter $total_prompts = $wpdb->get_var("SELECT COUNT(*) FROM {$table_name} {$sql_search}"); $total_pages = ceil($total_prompts / $per_page); // Retrieve prompts from the database $prompts = $wpdb->get_results( $wpdb->prepare( "SELECT * FROM {$table_name} {$sql_search} ORDER BY timestamp DESC LIMIT %d OFFSET %d", $per_page, $offset ) ); ?>

get_pdf_processing_status($pdf_url) : false; $sitemap_status = $sitemap_url ? $this->get_sitemap_processing_status($sitemap_url) : false; // Clear old completed statuses if ($pdf_status && $pdf_status['status'] === 'complete') { delete_transient('mxchat_last_pdf_url'); $pdf_status = false; } if ($sitemap_status && $sitemap_status['status'] === 'complete') { delete_transient('mxchat_last_sitemap_url'); $sitemap_status = false; } $is_processing = ($pdf_status && $pdf_status['status'] === 'processing') || ($sitemap_status && $sitemap_status['status'] === 'processing'); ?>

add_query_arg(array( 'paged' => '%#%', 'search' => urlencode($search_query), '_wpnonce' => wp_create_nonce('mxchat_prompts_search_nonce') ), admin_url('admin.php?page=mxchat-prompts')), 'format' => '', 'prev_text' => __('« Previous', 'mxchat'), 'next_text' => __('Next »', 'mxchat'), 'total' => $total_pages, 'current' => $current_page, )); if ($page_links) : ?>
id); ?> article_content))); ?> source_url)) : ?> source_url); ?>
prefix . 'mxchat_system_prompt_content'; // Delete all prompts from the table $wpdb->query("DELETE FROM {$table_name}"); // Clear relevant cache wp_cache_delete('all_prompts', 'mxchat_prompts'); // Redirect back with a success message $redirect_url = add_query_arg(array( 'page' => 'mxchat-prompts', 'all_deleted' => 'true' ), admin_url('admin.php')); wp_safe_redirect($redirect_url); exit; } public function mxchat_handle_delete_prompt() { // Sanitize and validate nonce $nonce = isset($_GET['_wpnonce']) ? sanitize_text_field(wp_unslash($_GET['_wpnonce'])) : ''; if (empty($nonce) || !wp_verify_nonce($nonce, 'mxchat_delete_prompt_nonce')) { wp_die(esc_html__('Nonce verification failed.', 'mxchat')); } // Check permissions if (!current_user_can('manage_options')) { wp_die(esc_html__('You do not have sufficient permissions to delete prompts.', 'mxchat')); } // Validate and sanitize ID parameter $id = isset($_GET['id']) ? intval($_GET['id']) : 0; if ($id <= 0) { wp_die(esc_html__('Invalid prompt ID.', 'mxchat')); } global $wpdb; $table_name = $wpdb->prefix . 'mxchat_system_prompt_content'; // Clear cache and delete prompt wp_cache_delete('prompt_' . $id, 'mxchat_prompts'); $wpdb->delete($table_name, array('id' => $id), array('%d')); wp_safe_redirect(add_query_arg(array('page' => 'mxchat-prompts', 'deleted' => 'true'), admin_url('admin.php'))); exit; } public function mxchat_generate_embedding($text) { $options = get_option('mxchat_options'); $api_key = $options['api_key'] ?? esc_html__('default_api_key', 'mxchat'); $response = wp_remote_post('https://api.openai.com/v1/embeddings', array( 'body' => wp_json_encode(array( 'model' => esc_html__('text-embedding-ada-002', 'mxchat'), 'input' => $text )), 'headers' => array( 'Authorization' => 'Bearer ' . $api_key, 'Content-Type' => esc_html__('application/json', 'mxchat') ), )); if (is_wp_error($response)) { return null; } $response_data = json_decode(wp_remote_retrieve_body($response), true); return $response_data['data'][0]['embedding'] ?? null; } public function mxchat_delete_chat_history() { if (!current_user_can('manage_options')) { echo wp_json_encode(['error' => esc_html__('You do not have sufficient permissions.', 'mxchat')]); wp_die(); } check_ajax_referer('mxchat_delete_chat_history', 'security'); global $wpdb; $table_name = $wpdb->prefix . 'mxchat_chat_transcripts'; if (isset($_POST['delete_session_ids']) && is_array($_POST['delete_session_ids'])) { foreach ($_POST['delete_session_ids'] as $session_id) { $session_id_sanitized = sanitize_text_field($session_id); // Clear relevant cache before deletion $cache_key = 'chat_session_' . $session_id_sanitized; wp_cache_delete($cache_key, 'mxchat_chat_sessions'); // Perform the deletion $wpdb->delete($table_name, ['session_id' => $session_id_sanitized]); } // Optionally, clear a general cache if you have one wp_cache_delete('all_chat_sessions', 'mxchat_chat_sessions'); echo wp_json_encode(['success' => esc_html__('Selected chat sessions have been deleted.', 'mxchat')]); } else { echo wp_json_encode(['error' => esc_html__('No chat sessions selected for deletion.', 'mxchat')]); } wp_die(); } public function mxchat_save_inline_prompt() { // Check for nonce security check_ajax_referer('mxchat_save_inline_nonce'); // Verify permissions if (!current_user_can('manage_options')) { wp_send_json_error(esc_html__('Permission denied.', 'mxchat')); return; } global $wpdb; $table_name = $wpdb->prefix . 'mxchat_system_prompt_content'; // Validate and sanitize input data $prompt_id = isset($_POST['id']) ? absint($_POST['id']) : 0; $article_content = isset($_POST['article_content']) ? sanitize_textarea_field($_POST['article_content']) : ''; $article_url = isset($_POST['article_url']) ? esc_url_raw($_POST['article_url']) : ''; if ($prompt_id > 0 && !empty($article_content)) { // Re-generate the embedding vector for the updated content $embedding_vector = $this->mxchat_generate_embedding($article_content); if (is_array($embedding_vector)) { // Serialize the embedding vector before storing it $embedding_vector_serialized = serialize($embedding_vector); // Update the prompt in the database $updated = $wpdb->update( $table_name, array( 'article_content' => $article_content, 'embedding_vector' => $embedding_vector_serialized, 'source_url' => $article_url, ), array('id' => $prompt_id), array('%s', '%s', '%s'), array('%d') ); if ($updated !== false) { wp_send_json_success(); } else { wp_send_json_error(esc_html__('Database update failed.', 'mxchat')); } } else { wp_send_json_error(esc_html__('Embedding generation failed.', 'mxchat')); } } else { wp_send_json_error(esc_html__('Invalid data.', 'mxchat')); } } // Add this method to handle post updates public function handle_post_update($post_id, $post, $update) { // Don't process auto-saves or revisions if (defined('DOING_AUTOSAVE') && DOING_AUTOSAVE) { //error_log(esc_html__('MXChat: Skipping - autosave', 'mxchat')); return; } if (wp_is_post_revision($post_id)) { //error_log(esc_html__('MXChat: Skipping - revision', 'mxchat')); return; } // Only process published content if (!in_array($post->post_status, array('publish'))) { //error_log(esc_html__('MXChat: Skipping - not published', 'mxchat')); return; } // Check if sync is enabled for this post type $post_type = $post->post_type; $sync_option = ($post_type === 'post') ? 'mxchat_auto_sync_posts' : 'mxchat_auto_sync_pages'; if (get_option($sync_option) !== '1') { //error_log(esc_html__('MXChat: Skipping - sync not enabled for this type', 'mxchat')); return; } // Only process posts and pages if (!in_array($post_type, array('post', 'page'))) return; global $wpdb; $table_name = $wpdb->prefix . 'mxchat_system_prompt_content'; // Get the post content and URL $content = wp_strip_all_tags($post->post_content); $url = get_permalink($post_id); // Check if this URL already exists in the database $existing_entry = $wpdb->get_row( $wpdb->prepare( "SELECT id FROM $table_name WHERE source_url = %s", $url ) ); // Generate embedding for the content $embedding_vector = $this->mxchat_generate_embedding($content); if (!$embedding_vector) return; if ($existing_entry) { // Update existing entry $wpdb->update( $table_name, array( 'article_content' => $content, 'embedding_vector' => serialize($embedding_vector), 'timestamp' => current_time('mysql') ), array('id' => $existing_entry->id), array('%s', '%s', '%s'), array('%d') ); } else { // Insert new entry $wpdb->insert( $table_name, array( 'article_content' => $content, 'source_url' => $url, 'embedding_vector' => serialize($embedding_vector), 'timestamp' => current_time('mysql') ), array('%s', '%s', '%s', '%s') ); } } public function mxchat_handle_content_submission() { // Check if the form was submitted and the user has sufficient permissions if (!isset($_POST['submit_content']) || !current_user_can('manage_options')) { return; } // Verify the nonce field for security $nonce = isset($_POST['mxchat_submit_content_nonce']) ? sanitize_text_field(wp_unslash($_POST['mxchat_submit_content_nonce'])) : ''; if (!wp_verify_nonce($nonce, 'mxchat_submit_content_action')) { wp_die(esc_html__('Nonce verification failed.', 'mxchat')); } // Sanitize the content input $article_content = sanitize_textarea_field($_POST['article_content']); // Sanitize the URL input (optional URL) $article_url = isset($_POST['article_url']) ? esc_url_raw($_POST['article_url']) : ''; // Default to empty if not provided // Generate the embedding vector for the content $embedding_vector = $this->mxchat_generate_embedding($article_content); global $wpdb; $table_name = $wpdb->prefix . 'mxchat_system_prompt_content'; // Check if the 'source_url' column exists in the table and add it if it doesn't if ($wpdb->get_var($wpdb->prepare("SHOW COLUMNS FROM {$table_name} LIKE %s", 'source_url')) != 'source_url') { // Use wpdb::query and a prepared statement to avoid SQL injection $wpdb->query($wpdb->prepare("ALTER TABLE {$table_name} ADD source_url VARCHAR(255) DEFAULT ''")); } if (is_array($embedding_vector)) { // Serialize the embedding vector before storing it $embedding_vector_serialized = serialize($embedding_vector); // Insert the content, embedding vector, and source URL into the database, using a prepared statement $inserted = $wpdb->insert( $table_name, array( 'article_content' => $article_content, 'embedding_vector' => $embedding_vector_serialized, 'source_url' => $article_url, // Insert the URL, empty string if not provided ), array( '%s', // Format for article_content (string) '%s', // Format for embedding_vector (serialized string) '%s', // Format for source_url (string) ) ); if ($inserted === false) { //error_log('Error inserting content: ' . $wpdb->last_error); set_transient('mxchat_admin_notice_error', esc_html__('Error inserting content into the database. Please try again.', 'mxchat'), 30); } else { set_transient('mxchat_admin_notice_success', esc_html__('Content successfully submitted!', 'mxchat'), 30); } } else { //error_log('Embedding generation failed for article content: ' . $article_content); set_transient('mxchat_admin_notice_error', esc_html__('Embedding generation failed. Please ensure your API key is correct and try again.', 'mxchat'), 30); } // Redirect after setting the transient wp_safe_redirect(esc_url(admin_url('admin.php?page=mxchat-prompts'))); exit; } private function is_pdf_url($url, $response) { $content_type = wp_remote_retrieve_header($response, 'content-type'); $file_extension = strtolower(pathinfo($url, PATHINFO_EXTENSION)); return strpos($content_type, 'pdf') !== false || $file_extension === 'pdf'; } private function handle_pdf_for_knowledge_base($pdf_url, $response) { if (!current_user_can('manage_options')) { //error_log(esc_html__('Unauthorized PDF processing attempt', 'mxchat')); return false; } $pdf_url = esc_url_raw($pdf_url); $upload_dir = wp_upload_dir(); if (isset($upload_dir['error']) && $upload_dir['error'] !== false) { //error_log(sprintf(esc_html__('Upload directory error: %s', 'mxchat'), esc_html($upload_dir['error']))); return false; } $pdf_filename = sanitize_file_name('mxchat_kb_' . time() . '.pdf'); $pdf_path = trailingslashit($upload_dir['path']) . $pdf_filename; $response_body = wp_remote_retrieve_body($response); if (empty($response_body)) { //error_log(esc_html__('Empty PDF response body', 'mxchat')); return false; } if (!wp_mkdir_p(dirname($pdf_path))) { //error_log(sprintf(esc_html__('Failed to create directory for PDF: %s', 'mxchat'), esc_html($pdf_path))); return false; } try { file_put_contents($pdf_path, $response_body); if (!file_exists($pdf_path)) { throw new Exception(__('Failed to save PDF file', 'mxchat')); } $parser = new \Smalot\PdfParser\Parser(); $pdf = $parser->parseFile($pdf_path); $total_pages = absint(count($pdf->getPages())); if ($total_pages < 1) { throw new Exception(__('Invalid PDF: no pages found', 'mxchat')); } wp_schedule_single_event(time(), 'mxchat_process_pdf_pages', array( 'pdf_path' => $pdf_path, 'pdf_url' => $pdf_url, 'total_pages' => $total_pages, 'batch_size' => absint(15), 'batch_pause' => absint(10) )); $status_data = array( 'total_pages' => $total_pages, 'processed_pages' => 0, 'status' => 'processing', 'last_update' => time() ); set_transient( sanitize_key('mxchat_pdf_status_' . md5($pdf_url)), array_map('sanitize_text_field', $status_data), DAY_IN_SECONDS ); return __('scheduled', 'mxchat'); } catch (Exception $e) { //error_log(sprintf(esc_html__('Error preparing PDF for processing: %s', 'mxchat'), esc_html($e->getMessage()))); if (file_exists($pdf_path)) { wp_delete_file($pdf_path); } return false; } } public static function process_pdf_pages_cron($pdf_path, $pdf_url, $total_pages, $batch_size, $batch_pause) { // Validate inputs $pdf_path = sanitize_text_field($pdf_path); $pdf_url = esc_url_raw($pdf_url); $total_pages = absint($total_pages); $batch_size = absint($batch_size); $batch_pause = absint($batch_pause); try { if (!file_exists($pdf_path)) { throw new Exception(sprintf('PDF file not found at path: %s', esc_html($pdf_path))); } $parser = new \Smalot\PdfParser\Parser(); $pdf = $parser->parseFile($pdf_path); $pages = $pdf->getPages(); // Get current progress $status_key = sanitize_key('mxchat_pdf_status_' . md5($pdf_url)); $status = get_transient($status_key); if (!$status || !is_array($status)) { throw new Exception('Invalid status data retrieved from transient'); } $start_page = absint($status['processed_pages']); $end_page = min($start_page + $batch_size, $total_pages); $instance = new self(); // Create an instance of the class for ($i = $start_page; $i < $end_page; $i++) { $text = $pages[$i]->getText(); $sanitized_content = $instance->mxchat_sanitize_content_for_api($text); // Call via instance if (!empty($sanitized_content)) { $embedding_vector = $instance->mxchat_generate_embedding($sanitized_content); // Call via instance if (is_array($embedding_vector)) { $metadata = array( 'document_type' => 'pdf', 'total_pages' => $total_pages, 'current_page' => $i + 1, 'prev_page' => $i > 0 ? $i : null, 'next_page' => $i < ($total_pages - 1) ? $i + 2 : null, 'source_url' => $pdf_url ); $content_with_metadata = wp_json_encode($metadata) . "\n---\n" . $sanitized_content; $page_url = esc_url($pdf_url . "#page=" . ($i + 1)); $options = get_option('mxchat_options'); MxChat_Utils::submit_content_to_db($content_with_metadata, $page_url, $options['api_key']); } } // Update progress with sanitized data $status['processed_pages'] = absint($i + 1); $status['last_update'] = time(); set_transient($status_key, array_map('sanitize_text_field', $status), DAY_IN_SECONDS); } // Schedule next batch if needed if ($end_page < $total_pages) { wp_schedule_single_event(time() + $batch_pause, 'mxchat_process_pdf_pages', array( 'pdf_path' => $pdf_path, 'pdf_url' => $pdf_url, 'total_pages' => $total_pages, 'batch_size' => $batch_size, 'batch_pause' => $batch_pause )); } else { // Processing complete $status['status'] = 'complete'; set_transient($status_key, array_map('sanitize_text_field', $status), DAY_IN_SECONDS); if (file_exists($pdf_path)) { wp_delete_file($pdf_path); } } } catch (\Exception $e) { $status['status'] = 'error'; $status['error'] = sanitize_text_field($e->getMessage()); set_transient($status_key, array_map('sanitize_text_field', $status), DAY_IN_SECONDS); if (file_exists($pdf_path)) { wp_delete_file($pdf_path); } } } public function get_pdf_processing_status($pdf_url) { $pdf_url = esc_url_raw($pdf_url); $status = get_transient(sanitize_key('mxchat_pdf_status_' . md5($pdf_url))); if (!$status || !is_array($status)) { return false; } return array( 'total_pages' => absint($status['total_pages']), 'processed_pages' => absint($status['processed_pages']), 'percentage' => round((absint($status['processed_pages']) / absint($status['total_pages'])) * 100), 'status' => sanitize_text_field($status['status']), 'last_update' => human_time_diff(absint($status['last_update']), time()) . ' ' . esc_html__('ago', 'mxchat') ); } public function mxchat_handle_sitemap_submission() { // Check if the form was submitted and verify permissions if (!isset($_POST['submit_sitemap']) || !current_user_can('manage_options')) { wp_die(esc_html__('Unauthorized access', 'mxchat')); } // Verify nonce check_admin_referer('mxchat_submit_sitemap_action', 'mxchat_submit_sitemap_nonce'); // Validate URL if (!isset($_POST['sitemap_url']) || empty($_POST['sitemap_url'])) { set_transient('mxchat_admin_notice_error', esc_html__('Please provide a valid URL.', 'mxchat'), 30 ); wp_safe_redirect(esc_url(admin_url('admin.php?page=mxchat-prompts'))); exit; } $submitted_url = esc_url_raw($_POST['sitemap_url']); $response = wp_remote_get($submitted_url, array('timeout' => 30)); if (is_wp_error($response) || wp_remote_retrieve_response_code($response) !== 200) { $error_message = is_wp_error($response) ? $response->get_error_message() : __('Failed to fetch URL', 'mxchat'); set_transient('mxchat_admin_notice_error', sprintf( esc_html__('Failed to fetch the URL: %s', 'mxchat'), esc_html($error_message) ), 30 ); wp_safe_redirect(esc_url(admin_url('admin.php?page=mxchat-prompts'))); exit; } $content_type = wp_remote_retrieve_header($response, 'content-type'); $body_content = wp_remote_retrieve_body($response); if (empty($body_content)) { set_transient('mxchat_admin_notice_error', esc_html__('Empty response received from URL.', 'mxchat'), 30 ); wp_safe_redirect(esc_url(admin_url('admin.php?page=mxchat-prompts'))); exit; } // Handle PDF URL if ($this->is_pdf_url($submitted_url, $response)) { $result = $this->handle_pdf_for_knowledge_base($submitted_url, $response); if ($result === 'scheduled') { set_transient( 'mxchat_last_pdf_url', sanitize_text_field($submitted_url), DAY_IN_SECONDS ); set_transient('mxchat_admin_notice_info', esc_html__('PDF processing has started in the background. You can check the progress in the Knowledge Base section.', 'mxchat'), 30 ); } else { set_transient('mxchat_admin_notice_error', esc_html__('Failed to start PDF processing. Please try again.', 'mxchat'), 30 ); } wp_safe_redirect(esc_url(admin_url('admin.php?page=mxchat-prompts'))); exit; } // Handle Sitemap XML if (strpos($content_type, 'xml') !== false || strpos($body_content, 'handle_sitemap_for_knowledge_base($xml, $submitted_url); if ($result === 'scheduled') { set_transient( 'mxchat_last_sitemap_url', sanitize_text_field($submitted_url), DAY_IN_SECONDS ); set_transient('mxchat_admin_notice_info', esc_html__('Sitemap processing has started in the background. You can check the progress in the Knowledge Base section.', 'mxchat'), 30 ); } else { set_transient('mxchat_admin_notice_error', esc_html__('Failed to start sitemap processing. Please try again.', 'mxchat'), 30 ); } wp_safe_redirect(esc_url(admin_url('admin.php?page=mxchat-prompts'))); exit; } // Handle Regular URL $page_content = $this->mxchat_extract_main_content($body_content); $sanitized_content = $this->mxchat_sanitize_content_for_api($page_content); if (empty($sanitized_content)) { set_transient('mxchat_admin_notice_error', esc_html__('No valid content found on the provided URL.', 'mxchat'), 30 ); wp_safe_redirect(esc_url(admin_url('admin.php?page=mxchat-prompts'))); exit; } $embedding_vector = $this->mxchat_generate_embedding($sanitized_content); if (is_array($embedding_vector)) { MxChat_Utils::submit_content_to_db( $sanitized_content, $submitted_url, $this->options['api_key'] ); set_transient('mxchat_admin_notice_success', esc_html__('URL content successfully submitted!', 'mxchat'), 30 ); } else { set_transient('mxchat_admin_notice_error', esc_html__('Failed to generate embedding for the URL content. Please check your API key and try again.', 'mxchat'), 30 ); } wp_safe_redirect(esc_url(admin_url('admin.php?page=mxchat-prompts'))); exit; } private function handle_sitemap_for_knowledge_base($xml, $sitemap_url) { if (!current_user_can('manage_options')) { //error_log(esc_html__('Unauthorized sitemap processing attempt', 'mxchat')); return false; } try { $sitemap_url = esc_url_raw($sitemap_url); if (!$xml || !is_object($xml)) { throw new Exception(__('Invalid XML object provided', 'mxchat')); } $urls = []; foreach ($xml->url as $url_element) { $url = esc_url_raw((string)$url_element->loc); if ($url) { $urls[] = $url; } } $total_urls = absint(count($urls)); if ($total_urls < 1) { throw new Exception(__('No valid URLs found in sitemap', 'mxchat')); } wp_schedule_single_event(time(), 'mxchat_process_sitemap_urls', array( 'urls' => $urls, 'sitemap_url' => $sitemap_url, 'total_urls' => $total_urls, 'batch_size' => absint(10), 'batch_pause' => absint(5) )); $status_data = array( 'total_urls' => $total_urls, 'processed_urls' => 0, 'status' => 'processing', 'last_update' => time() ); set_transient( sanitize_key('mxchat_sitemap_status_' . md5($sitemap_url)), array_map('sanitize_text_field', $status_data), DAY_IN_SECONDS ); return __('scheduled', 'mxchat'); } catch (\Exception $e) { //error_log(sprintf(esc_html__('Error preparing sitemap for processing: %s', 'mxchat'), esc_html($e->getMessage()))); return false; } } public static function process_sitemap_urls_cron($urls, $sitemap_url, $total_urls, $batch_size, $batch_pause) { // Validate inputs $sitemap_url = esc_url_raw($sitemap_url); $total_urls = absint($total_urls); $batch_size = absint($batch_size); $batch_pause = absint($batch_pause); if (!is_array($urls) || empty($urls)) { return; } try { $status_key = sanitize_key('mxchat_sitemap_status_' . md5($sitemap_url)); $status = get_transient($status_key); if (!$status || !is_array($status)) { throw new Exception('Invalid status data retrieved from transient'); } $start_url = absint($status['processed_urls']); $end_url = min($start_url + $batch_size, $total_urls); $instance = new self(); // Create an instance of the class $embedding_success = true; for ($i = $start_url; $i < $end_url; $i++) { $page_url = esc_url_raw($urls[$i]); $page_response = wp_remote_get($page_url); if (is_wp_error($page_response) || wp_remote_retrieve_response_code($page_response) !== 200) { continue; } $page_html = wp_remote_retrieve_body($page_response); $page_content = $instance->mxchat_extract_main_content($page_html); // Call via instance $sanitized_content = $instance->mxchat_sanitize_content_for_api($page_content); // Call via instance if (!empty($sanitized_content)) { $embedding_vector = $instance->mxchat_generate_embedding($sanitized_content); // Call via instance if (is_array($embedding_vector)) { $options = get_option('mxchat_options'); MxChat_Utils::submit_content_to_db($sanitized_content, $page_url, $options['api_key']); } else { $embedding_success = false; } } $status['processed_urls'] = absint($i + 1); $status['last_update'] = time(); set_transient($status_key, array_map('sanitize_text_field', $status), DAY_IN_SECONDS); } if ($end_url < $total_urls) { wp_schedule_single_event(time() + $batch_pause, 'mxchat_process_sitemap_urls', array( 'urls' => array_map('esc_url_raw', $urls), 'sitemap_url' => $sitemap_url, 'total_urls' => $total_urls, 'batch_size' => $batch_size, 'batch_pause' => $batch_pause, )); } else { $status['status'] = 'complete'; set_transient($status_key, array_map('sanitize_text_field', $status), DAY_IN_SECONDS); } } catch (\Exception $e) { $status['status'] = 'error'; $status['error'] = sanitize_text_field($e->getMessage()); set_transient($status_key, array_map('sanitize_text_field', $status), DAY_IN_SECONDS); } } public function get_sitemap_processing_status($sitemap_url) { $sitemap_url = esc_url_raw($sitemap_url); $status = get_transient(sanitize_key('mxchat_sitemap_status_' . md5($sitemap_url))); if (!$status || !is_array($status)) { return false; } return array( 'total_urls' => absint($status['total_urls']), 'processed_urls' => absint($status['processed_urls']), 'percentage' => round((absint($status['processed_urls']) / absint($status['total_urls'])) * 100), 'status' => sanitize_text_field($status['status']), 'last_update' => human_time_diff(absint($status['last_update']), time()) . ' ' . esc_html__('ago', 'mxchat') ); } public function mxchat_stop_processing() { // Verify permissions if (!current_user_can('manage_options')) { wp_die(esc_html__('Unauthorized access', 'mxchat')); } // Verify nonce check_admin_referer('mxchat_stop_processing_action', 'mxchat_stop_processing_nonce'); // Get the last sitemap URL and clear its transient $sitemap_url = get_transient('mxchat_last_sitemap_url'); if ($sitemap_url) { delete_transient('mxchat_sitemap_status_' . md5($sitemap_url)); delete_transient('mxchat_last_sitemap_url'); } // Get the last PDF URL and clear its transient $pdf_url = get_transient('mxchat_last_pdf_url'); if ($pdf_url) { delete_transient('mxchat_pdf_status_' . md5($pdf_url)); delete_transient('mxchat_last_pdf_url'); } // Unschedule any pending sitemap events $timestamp = wp_next_scheduled('mxchat_process_sitemap_urls'); if ($timestamp) { wp_unschedule_event($timestamp, 'mxchat_process_sitemap_urls'); } // Redirect back with a success message set_transient('mxchat_admin_notice_success', esc_html__('Processing has been stopped successfully.', 'mxchat'), 30 ); wp_safe_redirect(admin_url('admin.php?page=mxchat-prompts')); exit; } private function mxchat_sanitize_content_for_api($content) { // Remove script, style tags, and HTML comments $content = preg_replace('/]*>(.*?)<\/script>/is', '', $content); $content = preg_replace('/]*>(.*?)<\/style>/is', '', $content); $content = preg_replace('//', '', $content); // Remove all HTML tags and decode HTML entities $content = wp_strip_all_tags($content); $content = html_entity_decode($content, ENT_QUOTES | ENT_HTML5); // Trim and normalize whitespace $content = trim(preg_replace('/\s+/', ' ', $content)); return $content; } public function mxchat_fetch_chat_history() { global $wpdb; $table_name = $wpdb->prefix . 'mxchat_chat_transcripts'; if (!current_user_can('manage_options')) { wp_die(esc_html__('You do not have sufficient permissions to view this page.', 'mxchat')); } // First get unique session IDs ordered by most recent message in each session $session_ids = $wpdb->get_col( $wpdb->prepare( "SELECT DISTINCT session_id FROM {$table_name} GROUP BY session_id ORDER BY MAX(timestamp) DESC" ) ); if (empty($session_ids)) { wp_die(esc_html__('No chat history available.', 'mxchat')); } ob_start(); echo '
'; // Iterate through sessions from newest to oldest foreach ($session_ids as $session_id) { // Get the email associated with this session (if available) $email = $wpdb->get_var( $wpdb->prepare( "SELECT user_email FROM {$table_name} WHERE session_id = %s AND user_email != '' ORDER BY timestamp ASC LIMIT 1", $session_id ) ); // Debug: Check email retrieval if (empty($email)) { //error_log("No email found for session {$session_id}"); } else { //error_log("Email for session {$session_id}: " . $email); } // Get messages for this session ordered by timestamp $messages = $wpdb->get_results( $wpdb->prepare( "SELECT * FROM {$table_name} WHERE session_id = %s ORDER BY timestamp ASC", $session_id ) ); // Start session block echo '
'; echo '
'; // Wrap checkbox and session ID in one block echo '
'; echo ' '; echo '' . esc_html__('Session ID:', 'mxchat') . ' ' . esc_html($session_id); echo '
'; // Place email directly below the session ID block if (!empty($email)) { echo '
'; echo '' . esc_html__('Email:', 'mxchat') . ' ' . esc_html($email); echo '
'; } echo '
'; echo '
'; // Display messages for this session foreach ($messages as $transcript) { $formatted_timestamp = date_i18n('F j, Y g:i a', strtotime($transcript->timestamp)); // Determine message styling switch ($transcript->role) { case 'assistant': case 'bot': $message_class = 'bot-message'; $display_role = esc_html__('Chatbot', 'mxchat'); break; case 'user': $message_class = 'user-message'; $display_role = !empty($transcript->user_identifier) ? sanitize_text_field($transcript->user_identifier) : esc_html__('User', 'mxchat'); break; case 'agent': $message_class = 'agent-message'; $display_role = esc_html__('Agent', 'mxchat'); break; default: $message_class = 'unknown-message'; $display_role = esc_html__('Unknown', 'mxchat'); } // Process message content $message_content = wp_kses( stripslashes($transcript->message), [ 'b' => [], 'strong' => [], 'i' => [], 'em' => [], 'u' => [], 'br' => [], 'p' => [], 'ul' => [], 'ol' => [], 'li' => [], 'a' => ['href' => [], 'title' => []] ] ); $message_content = nl2br($message_content); // Render message echo '
'; echo '
' . esc_html($display_role) . '
'; echo '
' . $message_content . '
'; echo '
' . esc_html($formatted_timestamp) . '
'; echo '
'; } // Close session block echo '
'; } echo '
'; $output = ob_get_clean(); echo $output; wp_die(); } public function mxchat_create_activation_page() { $license_status = get_option('mxchat_license_status', 'inactive'); $license_error = get_option('mxchat_license_error', ''); ?>

prefix . 'mxchat_intents'; $page = isset( $_GET['paged'] ) ? max( 1, intval( $_GET['paged'] ) ) : 1; $per_page = 20; $offset = ( $page - 1 ) * $per_page; // Add at the start of mxchat_intents_page_html() if (isset($_GET['updated']) && $_GET['updated'] === 'true') { echo '

' . esc_html__('Intent updated successfully.', 'mxchat') . '

'; } // Build the WHERE clause based on filters $where = '1=1'; $search_term = isset( $_GET['s'] ) ? trim( $_GET['s'] ) : ''; $callback_filter = isset( $_GET['callback_filter'] ) ? sanitize_text_field( $_GET['callback_filter'] ) : ''; if ( $search_term ) { $search_term_like = '%' . $wpdb->esc_like( $search_term ) . '%'; $where .= $wpdb->prepare( ' AND (intent_label LIKE %s OR phrases LIKE %s)', $search_term_like, $search_term_like ); } if ( $callback_filter ) { $where .= $wpdb->prepare( ' AND callback_function = %s', $callback_filter ); } // Get total count for pagination $total_intents = $wpdb->get_var( "SELECT COUNT(*) FROM $table_name WHERE $where" ); $total_pages = ceil( $total_intents / $per_page ); // Fetch intents with pagination and filters $intents = $wpdb->get_results( $wpdb->prepare( "SELECT * FROM $table_name WHERE $where LIMIT %d OFFSET %d", $per_page, $offset ) ); // Get available callback functions with 'pro_only' flag $available_callbacks = $this->mxchat_get_available_callbacks(); ?>

callback_function; $callback_label = isset( $available_callbacks[ $callback_function ]['label'] ) ? $available_callbacks[ $callback_function ]['label'] : $callback_function; $threshold_value = isset( $intent->similarity_threshold ) ? round( $intent->similarity_threshold * 100 ) : 85; ?>
intent_label ); ?> phrases ); ?>
%
mxchat_generate_embedding($phrase, $this->options['api_key']); if (is_array($embedding_vector)) { $vectors[] = $embedding_vector; } else { wp_die(esc_html__('Error generating embedding for phrase: ', 'mxchat') . esc_html($phrase)); } } if (empty($vectors)) { wp_die(esc_html__('No valid embeddings generated. Please check your phrases.', 'mxchat')); } // Create combined vector just like in intent creation $combined_vector = $this->mxchat_average_vectors($vectors); $serialized_vector = maybe_serialize($combined_vector); global $wpdb; $table_name = $wpdb->prefix . 'mxchat_intents'; // Update the intent with both new phrases and the combined vector $result = $wpdb->update( $table_name, array( 'phrases' => implode(', ', $phrases_array), 'embedding_vector' => $serialized_vector ), array('id' => $intent_id), array('%s', '%s'), array('%d') ); if (false === $result) { wp_die(esc_html__('Failed to update intent.', 'mxchat')); } // Redirect back to the intents page with a success message $redirect_url = add_query_arg( array( 'page' => 'mxchat-intents', 'updated' => 'true' ), admin_url('admin.php') ); wp_safe_redirect($redirect_url); exit; } public function mxchat_handle_update_intent_threshold() { if ( ! current_user_can( 'manage_options' ) ) { wp_die( esc_html__('Unauthorized user', 'mxchat') ); } check_admin_referer('mxchat_update_intent_threshold_nonce'); if (isset($_POST['intent_id'], $_POST['intent_threshold'])) { global $wpdb; $table_name = $wpdb->prefix . 'mxchat_intents'; $intent_id = intval($_POST['intent_id']); $threshold_percentage = max(70, min(95, intval($_POST['intent_threshold']))); $similarity_threshold = $threshold_percentage / 100; $wpdb->update( $table_name, ['similarity_threshold' => $similarity_threshold], ['id' => $intent_id], ['%f'], ['%d'] ); } wp_safe_redirect(admin_url('admin.php?page=mxchat-intents')); exit; } public function mxchat_handle_add_intent() { if ( ! current_user_can( 'manage_options' ) ) { wp_die( esc_html__('Unauthorized user', 'mxchat') ); } check_admin_referer('mxchat_add_intent_nonce'); global $wpdb; $table_name = $wpdb->prefix . 'mxchat_intents'; $intent_label = isset($_POST['intent_label']) ? sanitize_text_field($_POST['intent_label']) : ''; $phrases_input = isset($_POST['phrases']) ? sanitize_textarea_field($_POST['phrases']) : ''; $callback_function = isset($_POST['callback_function']) ? sanitize_text_field($_POST['callback_function']) : ''; $default_threshold = 0.85; if (empty($intent_label) || empty($callback_function) || empty($phrases_input)) { wp_die( esc_html__('Invalid input. Please ensure all fields are filled out.', 'mxchat') ); } $available_callbacks = $this->mxchat_get_available_callbacks(); if (!array_key_exists($callback_function, $available_callbacks)) { wp_die( esc_html__('Invalid callback function selected.', 'mxchat') ); } $is_pro_only = $available_callbacks[$callback_function]['pro_only']; if ($is_pro_only && !$this->is_activated) { wp_die( esc_html__('This callback function is available in the Pro version only.', 'mxchat') ); } $phrases_array = array_map('sanitize_text_field', array_filter(array_map('trim', explode(',', $phrases_input)))); if (empty($phrases_array)) { wp_die( esc_html__('Please enter at least one valid phrase.', 'mxchat') ); } $vectors = []; foreach ($phrases_array as $phrase) { $embedding_vector = $this->mxchat_generate_embedding($phrase, $this->options['api_key']); if (is_array($embedding_vector)) { $vectors[] = $embedding_vector; } else { wp_die( esc_html__('Error generating embedding for phrase: ', 'mxchat') . esc_html($phrase) ); } } if (!empty($vectors)) { $combined_vector = $this->mxchat_average_vectors($vectors); $serialized_vector = maybe_serialize($combined_vector); $result = $wpdb->insert($table_name, [ 'intent_label' => $intent_label, 'phrases' => implode(', ', $phrases_array), 'embedding_vector' => $serialized_vector, 'callback_function' => $callback_function, 'similarity_threshold' => $default_threshold, ]); if ($result === false) { wp_die( esc_html__('Database error: ', 'mxchat') . esc_html($wpdb->last_error) ); } } else { wp_die( esc_html__('No valid embeddings generated. Please check your phrases.', 'mxchat') ); } wp_safe_redirect(admin_url('admin.php?page=mxchat-intents')); exit; } private function mxchat_get_available_callbacks($grouped = false) { $callbacks = [ 'mxchat_handle_email_capture' => [ 'label' => __('Email Capture', 'mxchat'), 'pro_only' => false, 'group' => __('Customer Engagement', 'mxchat'), ], 'mxchat_handle_product_inquiry' => [ 'label' => __('Show Product Card', 'mxchat'), 'pro_only' => true, 'group' => __('WooCommerce Features', 'mxchat'), ], 'mxchat_handle_order_history' => [ 'label' => __('Order History', 'mxchat'), 'pro_only' => true, 'group' => __('WooCommerce Features', 'mxchat'), ], 'mxchat_generate_image' => [ 'label' => __('Generate Image', 'mxchat'), 'pro_only' => true, 'group' => __('Other Features', 'mxchat'), ], 'mxchat_handle_search_request' => [ 'label' => __('Brave Web Search', 'mxchat'), 'pro_only' => false, 'group' => __('Search Features', 'mxchat'), ], 'mxchat_handle_image_search_request' => [ 'label' => __('Brave Image Search', 'mxchat'), 'pro_only' => false, 'group' => __('Search Features', 'mxchat'), ], 'mxchat_handle_add_to_cart_intent' => [ 'label' => __('Add to Cart', 'mxchat'), 'pro_only' => true, 'group' => __('WooCommerce Features', 'mxchat'), ], 'mxchat_handle_checkout_intent' => [ 'label' => __('Proceed to Checkout', 'mxchat'), 'pro_only' => true, 'group' => __('WooCommerce Features', 'mxchat'), ], 'mxchat_handle_pdf_discussion' => [ 'label' => __('Chat with PDF', 'mxchat'), 'pro_only' => true, 'group' => __('Other Features', 'mxchat'), ], 'mxchat_handle_product_recommendations' => [ 'label' => __('Product Recommendations', 'mxchat'), 'pro_only' => true, 'group' => __('WooCommerce Features', 'mxchat'), ], 'mxchat_live_agent_handover' => [ 'label' => __('Live Agent', 'mxchat'), 'pro_only' => true, 'group' => __('Customer Engagement', 'mxchat'), ], 'mxchat_handle_switch_to_chatbot_intent' => [ 'label' => __('Back to Chatbot', 'mxchat'), 'pro_only' => true, 'group' => __('Customer Engagement', 'mxchat'), ], ]; // Return grouped structure if requested if ($grouped) { $grouped_callbacks = []; foreach ($callbacks as $key => $data) { $group_label = $data['group'] ?? __('Other Features', 'mxchat'); $grouped_callbacks[$group_label][$key] = [ 'label' => $data['label'], 'pro_only' => $data['pro_only'], ]; } return $grouped_callbacks; } return $callbacks; } private function mxchat_average_vectors($vectors) { $vector_length = count($vectors[0]); $sum_vector = array_fill(0, $vector_length, 0); foreach ($vectors as $vector) { for ($i = 0; $i < $vector_length; $i++) { $sum_vector[$i] += $vector[$i]; } } // Divide each component by the number of vectors to get the average $num_vectors = count($vectors); for ($i = 0; $i < $vector_length; $i++) { $sum_vector[$i] /= $num_vectors; } return $sum_vector; } public function mxchat_handle_delete_intent() { if ( ! current_user_can( 'manage_options' ) ) { wp_die( esc_html__('Unauthorized user', 'mxchat') ); } check_admin_referer('mxchat_delete_intent_nonce'); if (isset($_POST['intent_id'])) { global $wpdb; $table_name = $wpdb->prefix . 'mxchat_intents'; $intent_id = intval($_POST['intent_id']); $wpdb->delete($table_name, ['id' => $intent_id], ['%d']); } wp_safe_redirect(admin_url('admin.php?page=mxchat-intents')); exit; } public function mxchat_page_init() { // Register settings register_setting( 'mxchat_option_group', 'mxchat_options', array($this, 'mxchat_sanitize') ); register_setting( 'mxchat_option_group', 'mxchat_similarity_threshold', array( 'type' => 'number', 'sanitize_callback' => function($value) { $value = absint($value); // Ensure it's an integer return min(max($value, 70), 85); // Enforce range }, 'default' => 80, ) ); // Chatbot Settings Section add_settings_section( 'mxchat_chatbot_section', esc_html__('Chatbot Settings', 'mxchat'), null, 'mxchat-chatbot' ); // Similarity Threshold Slider add_settings_field( 'similarity_threshold', // Field ID esc_html__('Similarity Threshold', 'mxchat'), // Field title array($this, 'mxchat_similarity_threshold_callback'), // Callback function 'mxchat-chatbot', // Page 'mxchat_chatbot_section' // Section ); add_settings_field( 'append_to_body', esc_html__('Auto-Display Chatbot', 'mxchat'), array($this, 'mxchat_append_to_body_callback'), 'mxchat-chatbot', 'mxchat_chatbot_section' ); // Existing fields... add_settings_field( 'api_key', esc_html__('OpenAI API Key', 'mxchat'), array($this, 'api_key_callback'), 'mxchat-chatbot', 'mxchat_chatbot_section' ); add_settings_field( 'xai_api_key', esc_html__('X.AI API Key', 'mxchat'), array($this, 'xai_api_key_callback'), 'mxchat-chatbot', 'mxchat_chatbot_section' ); add_settings_field( 'claude_api_key', esc_html__('Claude API Key', 'mxchat'), array($this, 'claude_api_key_callback'), 'mxchat-chatbot', 'mxchat_chatbot_section' ); add_settings_field( 'deepseek_api_key', esc_html__('DeepSeek API Key', 'mxchat'), array($this, 'deepseek_api_key_callback'), 'mxchat-chatbot', 'mxchat_chatbot_section' ); add_settings_field( 'system_prompt_instructions', esc_html__('AI Instructions (Behavior)', 'mxchat'), array($this, 'system_prompt_instructions_callback'), 'mxchat-chatbot', 'mxchat_chatbot_section' ); add_settings_field( 'model', esc_html__('Model', 'mxchat'), array($this, 'mxchat_model_callback'), 'mxchat-chatbot', 'mxchat_chatbot_section' ); add_settings_field( 'top_bar_title', esc_html__('Top Bar Title', 'mxchat'), array($this, 'mxchat_top_bar_title_callback'), 'mxchat-chatbot', 'mxchat_chatbot_section' ); add_settings_field( 'enable_email_block', esc_html__('Require Email Before Chat', 'mxchat'), array($this, 'enable_email_block_callback'), 'mxchat-chatbot', 'mxchat_chatbot_section' ); add_settings_field( 'email_blocker_header_content', esc_html__('Require Email Chat Content', 'mxchat'), array($this, 'email_blocker_header_content_callback'), 'mxchat-chatbot', 'mxchat_chatbot_section' ); add_settings_field( 'email_blocker_button_text', esc_html__('Require Email Chat Button Text', 'mxchat'), [$this, 'email_blocker_button_text_callback'], 'mxchat-chatbot', 'mxchat_chatbot_section' ); add_settings_field( 'intro_message', esc_html__('Introductory Message', 'mxchat'), array($this, 'mxchat_intro_message_callback'), 'mxchat-chatbot', 'mxchat_chatbot_section' ); add_settings_field( 'input_copy', esc_html__('Input Copy', 'mxchat'), array($this, 'mxchat_input_copy_callback'), 'mxchat-chatbot', 'mxchat_chatbot_section' ); add_settings_field( 'rate_limit_logged_out', __('Rate Limit for Logged-out Users', 'mxchat'), array($this, 'mxchat_rate_limit_logged_out_callback'), 'mxchat-chatbot', 'mxchat_chatbot_section' ); add_settings_field( 'rate_limit_roles', __('Rate Limits by User Role', 'mxchat'), array($this, 'mxchat_rate_limit_roles_callback'), 'mxchat-chatbot', 'mxchat_chatbot_section' ); add_settings_field( 'rate_limit_message', esc_html__('Rate Limit Message', 'mxchat'), array($this, 'mxchat_rate_limit_message_callback'), 'mxchat-chatbot', 'mxchat_chatbot_section' ); add_settings_field( 'pre_chat_message', esc_html__('Chat Teaser Pop-up', 'mxchat'), array($this, 'mxchat_pre_chat_message_callback'), 'mxchat-chatbot', 'mxchat_chatbot_section' ); add_settings_field( 'privacy_toggle', esc_html__('Toggle Privacy Notice', 'mxchat'), array($this, 'mxchat_privacy_toggle_callback'), 'mxchat-chatbot', 'mxchat_chatbot_section' ); add_settings_field( 'complianz_toggle', esc_html__('Enable Complianz', 'mxchat'), array($this, 'mxchat_complianz_toggle_callback'), 'mxchat-chatbot', 'mxchat_chatbot_section' ); add_settings_field( 'link_target_toggle', esc_html__('Open Links in a New Tab', 'mxchat'), array($this, 'mxchat_link_target_toggle_callback'), 'mxchat-chatbot', 'mxchat_chatbot_section' ); add_settings_field( 'chat_persistence_toggle', esc_html__('Enable Chat Persistence', 'mxchat'), array($this, 'mxchat_chat_persistence_toggle_callback'), 'mxchat-chatbot', 'mxchat_chatbot_section' ); add_settings_field( 'popular_question_1', esc_html__('Popular Question 1', 'mxchat'), array($this, 'mxchat_popular_question_1_callback'), 'mxchat-chatbot', 'mxchat_chatbot_section' ); add_settings_field( 'popular_question_2', esc_html__('Popular Question 2', 'mxchat'), array($this, 'mxchat_popular_question_2_callback'), 'mxchat-chatbot', 'mxchat_chatbot_section' ); add_settings_field( 'popular_question_3', esc_html__('Popular Question 3', 'mxchat'), array($this, 'mxchat_popular_question_3_callback'), 'mxchat-chatbot', 'mxchat_chatbot_section' ); add_settings_field( 'additional_popular_questions', esc_html__('Additional Popular Questions', 'mxchat'), array($this, 'mxchat_additional_popular_questions_callback'), 'mxchat-chatbot', 'mxchat_chatbot_section' ); // WooCommerce Settings Section add_settings_section( 'mxchat_woocommerce_section', esc_html__('WooCommerce Settings', 'mxchat'), null, 'mxchat-embed' ); // Loops Settings Section add_settings_section( 'mxchat_loops_section', esc_html__('Loops Settings', 'mxchat'), null, 'mxchat-embed' ); // WooCommerce Settings Fields add_settings_field( 'enable_woocommerce_integration', esc_html__('Automatically Embed Products', 'mxchat'), array($this, 'mxchat_enable_woocommerce_integration_callback'), 'mxchat-embed', 'mxchat_woocommerce_section' ); add_settings_field( 'woocommerce_consumer_key', esc_html__('WooCommerce Consumer Key', 'mxchat'), array($this, 'mxchat_woocommerce_consumer_key_callback'), 'mxchat-embed', 'mxchat_woocommerce_section' ); add_settings_field( 'woocommerce_consumer_secret', esc_html__('WooCommerce Consumer Secret', 'mxchat'), array($this, 'mxchat_woocommerce_consumer_secret_callback'), 'mxchat-embed', 'mxchat_woocommerce_section' ); // Loops Settings Fields add_settings_field( 'loops_api_key', esc_html__('Loops API Key', 'mxchat'), array($this, 'mxchat_loops_api_key_callback'), 'mxchat-embed', 'mxchat_loops_section' ); add_settings_field( 'loops_mailing_list', esc_html__('Loops Mailing List', 'mxchat'), array($this, 'mxchat_loops_mailing_list_callback'), 'mxchat-embed', 'mxchat_loops_section' ); add_settings_field( 'triggered_phrase_response', esc_html__('Triggered Phrase Response', 'mxchat'), array($this, 'mxchat_triggered_phrase_response_callback'), 'mxchat-embed', 'mxchat_loops_section' ); add_settings_field( 'email_capture_response', esc_html__('Email Capture Response', 'mxchat'), array($this, 'mxchat_email_capture_response_callback'), 'mxchat-embed', 'mxchat_loops_section' ); // Brave Search Settings Fields add_settings_section( 'mxchat_brave_section', __('Brave Search Settings', 'mxchat'), array($this, 'mxchat_brave_section_callback'), 'mxchat-embed' ); add_settings_field( 'brave_api_key', __('Brave API Key', 'mxchat'), array($this, 'mxchat_brave_api_key_callback'), 'mxchat-embed', 'mxchat_brave_section' ); add_settings_field( 'brave_image_count', __('Number of Images to Return', 'mxchat'), array($this, 'mxchat_brave_image_count_callback'), 'mxchat-embed', 'mxchat_brave_section' ); add_settings_field( 'brave_safe_search', __('Safe Search', 'mxchat'), array($this, 'mxchat_brave_safe_search_callback'), 'mxchat-embed', 'mxchat_brave_section' ); add_settings_field( 'brave_news_count', __('Number of News Articles', 'mxchat'), array($this, 'mxchat_brave_news_count_callback'), 'mxchat-embed', 'mxchat_brave_section' ); add_settings_field( 'brave_country', __('Country', 'mxchat'), array($this, 'mxchat_brave_country_callback'), 'mxchat-embed', 'mxchat_brave_section' ); add_settings_field( 'brave_language', __('Language', 'mxchat'), array($this, 'mxchat_brave_language_callback'), 'mxchat-embed', 'mxchat_brave_section' ); // Chat with PDF Intent Settings Fields add_settings_section( 'mxchat_pdf_intent_section', __('Toolbar Settings & Intents', 'mxchat'), array($this, 'mxchat_pdf_intent_section_callback'), 'mxchat-embed' ); add_settings_field( 'chat_toolbar_toggle', __('Show Chat Toolbar', 'mxchat'), array($this, 'mxchat_chat_toolbar_toggle_callback'), 'mxchat-embed', 'mxchat_pdf_intent_section' ); add_settings_field( 'pdf_intent_trigger_text', __('Intent Trigger Text', 'mxchat'), array($this, 'mxchat_pdf_intent_trigger_text_callback'), 'mxchat-embed', 'mxchat_pdf_intent_section' ); add_settings_field( 'pdf_intent_success_text', __('Success Text', 'mxchat'), array($this, 'mxchat_pdf_intent_success_text_callback'), 'mxchat-embed', 'mxchat_pdf_intent_section' ); add_settings_field( 'pdf_intent_error_text', __('Error Text', 'mxchat'), array($this, 'mxchat_pdf_intent_error_text_callback'), 'mxchat-embed', 'mxchat_pdf_intent_section' ); // Add PDF Maximum Pages Field add_settings_field( 'pdf_max_pages', __('Maximum Document Pages', 'mxchat'), array($this, 'mxchat_pdf_max_pages_callback'), 'mxchat-embed', 'mxchat_pdf_intent_section' ); // Live Agent Settings Fields add_settings_section( 'mxchat_live_agent_section', __('Live Agent Settings', 'mxchat'), array($this, 'mxchat_live_agent_section_callback'), 'mxchat-embed' ); // Live Agent Status Fields (add at top of live agent settings) add_settings_field( 'live_agent_status', __('Live Agent Status', 'mxchat'), array($this, 'mxchat_live_agent_status_callback'), 'mxchat-embed', 'mxchat_live_agent_section' ); add_settings_field( 'live_agent_notification_message', __('Notification Message', 'mxchat'), array($this, 'mxchat_live_agent_notification_message_callback'), 'mxchat-embed', 'mxchat_live_agent_section' ); add_settings_field( 'live_agent_away_message', __('Away Message', 'mxchat'), array($this, 'mxchat_live_agent_away_message_callback'), 'mxchat-embed', 'mxchat_live_agent_section' ); add_settings_field( 'live_agent_webhook_url', __('Slack Webhook URL', 'mxchat'), array($this, 'mxchat_live_agent_webhook_url_callback'), 'mxchat-embed', 'mxchat_live_agent_section' ); add_settings_field( 'live_agent_secret_key', __('Slack Secret Key', 'mxchat'), array($this, 'mxchat_live_agent_secret_key_callback'), 'mxchat-embed', 'mxchat_live_agent_section' ); // Live Agent Integration Fields add_settings_field( 'live_agent_bot_token', __('Slack Bot OAuth Token', 'mxchat'), array($this, 'mxchat_live_agent_bot_token_callback'), 'mxchat-embed', 'mxchat_live_agent_section' ); // Theme Settings Section add_settings_section( 'mxchat_theme_section', esc_html__('Theme Settings', 'mxchat'), null, 'mxchat-theme' ); add_settings_field( 'close_button_color', esc_html__('Close Button & Title Color', 'mxchat'), array($this, 'mxchat_close_button_color_callback'), 'mxchat-theme', 'mxchat_theme_section' ); add_settings_field( 'chatbot_bg_color', esc_html__('Chatbot Background Color', 'mxchat'), array($this, 'mxchat_chatbot_bg_color_callback'), 'mxchat-theme', 'mxchat_theme_section' ); add_settings_field( 'user_message_bg_color', esc_html__('User Message Background Color', 'mxchat'), array($this, 'mxchat_user_message_bg_color_callback'), 'mxchat-theme', 'mxchat_theme_section' ); add_settings_field( 'user_message_font_color', esc_html__('User Message Font Color', 'mxchat'), array($this, 'mxchat_user_message_font_color_callback'), 'mxchat-theme', 'mxchat_theme_section' ); add_settings_field( 'bot_message_bg_color', esc_html__('Bot Message Background Color', 'mxchat'), array($this, 'mxchat_bot_message_bg_color_callback'), 'mxchat-theme', 'mxchat_theme_section' ); add_settings_field( 'bot_message_font_color', esc_html__('Bot Message Font Color', 'mxchat'), array($this, 'mxchat_bot_message_font_color_callback'), 'mxchat-theme', 'mxchat_theme_section' ); add_settings_field( 'top_bar_bg_color', esc_html__('Top Bar Background Color', 'mxchat'), array($this, 'mxchat_top_bar_bg_color_callback'), 'mxchat-theme', 'mxchat_theme_section' ); add_settings_field( 'send_button_font_color', esc_html__('Send Button Color', 'mxchat'), array($this, 'mxchat_send_button_font_color_callback'), 'mxchat-theme', 'mxchat_theme_section' ); add_settings_field( 'chat_input_font_color', esc_html__('Chat Input Font Color', 'mxchat'), array($this, 'mxchat_chat_input_font_color_callback'), 'mxchat-theme', 'mxchat_theme_section' ); add_settings_field( 'chatbot_background_color', esc_html__('Floating Widget Background Color', 'mxchat'), array($this, 'mxchat_chatbot_background_color_callback'), 'mxchat-theme', 'mxchat_theme_section' ); add_settings_field( 'icon_color', esc_html__('Chatbot Icon Color', 'mxchat'), array($this, 'mxchat_icon_color_callback'), 'mxchat-theme', 'mxchat_theme_section' ); add_settings_field( 'custom_icon', esc_html__('Custom Chatbot Icon (PNG)', 'mxchat'), array($this, 'mxchat_custom_icon_callback'), 'mxchat-theme', 'mxchat_theme_section' ); add_settings_field( 'title_icon', esc_html__('Title Bar Icon (PNG)', 'mxchat'), array($this, 'mxchat_title_icon_callback'), 'mxchat-theme', 'mxchat_theme_section' ); add_settings_field( 'live_agent_message_bg_color', esc_html__('Live Agent Background Color', 'mxchat'), array($this, 'mxchat_live_agent_message_bg_color_callback'), 'mxchat-theme', 'mxchat_theme_section' ); add_settings_field( 'live_agent_message_font_color', esc_html__('Live Agent Font Color', 'mxchat'), array($this, 'mxchat_live_agent_message_font_color_callback'), 'mxchat-theme', 'mxchat_theme_section' ); // Mode Indicator Background Color add_settings_field( 'mode_indicator_bg_color', esc_html__('Mode Indicator Background Color', 'mxchat'), array($this, 'mxchat_mode_indicator_bg_color_callback'), 'mxchat-theme', 'mxchat_theme_section' ); // Mode Indicator Font Color add_settings_field( 'mode_indicator_font_color', esc_html__('Mode Indicator Font Color', 'mxchat'), array($this, 'mxchat_mode_indicator_font_color_callback'), 'mxchat-theme', 'mxchat_theme_section' ); add_settings_field( 'toolbar_icon_color', esc_html__('Toolbar Icon Color', 'mxchat'), array($this, 'mxchat_toolbar_icon_color_callback'), 'mxchat-theme', 'mxchat_theme_section' ); // General Settings Section add_settings_section( 'mxchat_general_section', esc_html__('Frequently Asked Questions (FAQ)', 'mxchat'), null, 'mxchat-general' ); } public function mxchat_prompts_page_init() { // Register settings for the prompts/knowledge base page register_setting( 'mxchat_prompts_options', 'mxchat_auto_sync_posts', array( 'type' => 'boolean', 'description' => __('Automatically sync posts to knowledge base', 'mxchat'), 'sanitize_callback' => array($this, 'sanitize_sync_setting'), 'default' => 0, 'show_in_rest' => false, ) ); register_setting( 'mxchat_prompts_options', 'mxchat_auto_sync_pages', array( 'type' => 'boolean', 'description' => __('Automatically sync pages to knowledge base', 'mxchat'), 'sanitize_callback' => array($this, 'sanitize_sync_setting'), 'default' => 0, 'show_in_rest' => false, ) ); // Add settings saved message add_action('admin_notices', array($this, 'sync_settings_notice')); } public function sync_settings_notice() { // Only show notice on our plugin page if (!isset($_GET['page']) || $_GET['page'] !== 'mxchat-prompts') { return; } // Check if settings were updated if (isset($_GET['settings-updated'])) { ?>

'software-api', 'request' => 'activation', 'email' => $customer_email, 'license_key' => $license_key, 'product_id' => $product_id ), 'http://mxchat.ai/' ) ); if (is_wp_error($response)) { wp_send_json_error(esc_html__('Activation failed due to a server error: ', 'mxchat') . $response->get_error_message()); return; } $body = wp_remote_retrieve_body($response); $data = json_decode($body); if ($data && isset($data->activated) && $data->activated) { update_option('mxchat_license_status', 'active'); update_option('mxchat_pro_email', $customer_email); update_option('mxchat_activation_key', $license_key); wp_send_json_success(array('message' => esc_html__('License activated successfully', 'mxchat'))); } else { $error_message = isset($data->error) ? $data->error : esc_html__('Activation failed', 'mxchat'); update_option('mxchat_license_status', 'inactive'); update_option('mxchat_license_error', $error_message); wp_send_json_error($error_message); } } public function mxchat_rate_limit_logged_out_callback() { // Load the entire 'mxchat_options' array $all_options = get_option('mxchat_options', []); // Retrieve the saved rate limit or use the default value $default_rate_limit = '10'; $selected_rate_limit = isset($all_options['rate_limit_logged_out']) ? $all_options['rate_limit_logged_out'] : $default_rate_limit; // Define available rate limits $rate_limits = array('1', '3', '5', '10', '15', '20', '100', 'unlimited'); // Output the dropdown echo '
'; echo ''; echo '

' . esc_html__('Set the maximum number of messages a logged-out user can send within a 24-hour period.', 'mxchat') . '

'; echo '
'; } // Add this new callback function public function mxchat_rate_limit_roles_callback() { $all_options = get_option('mxchat_options', []); $roles = wp_roles()->get_names(); $rate_limits = array('1', '3', '5', '10', '15', '20', '100', 'unlimited'); echo '
'; foreach ($roles as $role_id => $role_name) { $default_rate_limit = '100'; $selected_rate_limit = isset($all_options['role_rate_limits'][$role_id]) ? $all_options['role_rate_limits'][$role_id] : $default_rate_limit; echo '
'; echo ''; echo ''; echo '
'; } echo '

' . esc_html__('Set the maximum number of messages users in each role can send within a 24-hour period.', 'mxchat') . '

'; echo '
'; } public function mxchat_rate_limit_message_callback() { // Load the entire 'mxchat_options' array $all_options = get_option('mxchat_options', []); // Retrieve the saved message or use the default value $default_message = esc_html__('Rate limit exceeded. Please try again later.', 'mxchat'); $rate_limit_message = isset($all_options['rate_limit_message']) ? $all_options['rate_limit_message'] : $default_message; // Output the textarea echo '
'; printf( '', esc_textarea($rate_limit_message) ); echo '

' . esc_html__('This message will be displayed when a user exceeds the rate limit.', 'mxchat') . '

'; echo '
'; } public function mxchat_enable_woocommerce_integration_callback() { // Load from mxchat_options array $options = get_option('mxchat_options', []); // Get WooCommerce integration status with backwards compatibility $woo_integration = isset($options['enable_woocommerce_integration']) ? $options['enable_woocommerce_integration'] : ''; // Support both old ('1') and new ('on') values $checked = ($woo_integration === 'on' || $woo_integration === '1') ? 'checked' : ''; // Check if the feature is activated (paid feature) $disabled = $this->is_activated ? '' : 'disabled'; $class = $this->is_activated ? 'pro-feature-wrapper active' : 'pro-feature-wrapper inactive'; echo '
'; echo ''; echo '

' . esc_html__('Automatically syncs new product additions, updates, and removals to the knowledge base. For existing products, submit your product sitemap in the Knowledge Base section to add them initially.', 'mxchat') . '

'; // Pro feature overlay for non-activated users if (!$this->is_activated) { echo '
'; echo ''; echo '' . esc_attr__('Pro Only', 'mxchat') . ''; echo ''; echo '
'; } echo '
'; } private function mxchat_add_option_field($id, $title, $callback = '') { add_settings_field( $id, __($title, 'mxchat'), $callback ? array($this, $callback) : array($this, $id . '_callback'), 'mxchat-max', 'mxchat_setting_section_id', $id === 'model' ? ['label_for' => 'model'] : [] ); } public function api_key_callback() { // Retrieve from your stored 'api_key' in the mxchat_options array $apiKey = isset($this->options['api_key']) ? esc_attr($this->options['api_key']) : ''; // Notice we changed the name to "api_key" (no array notation). echo ''; echo ''; echo '

' . esc_html__('The OpenAI API key is required even when using other models as it is used for vector embedding functionality.', 'mxchat') . '

'; } public function xai_api_key_callback() { // Check if the feature is activated (paid feature) $disabled = $this->is_activated ? '' : 'disabled'; // Disable input if not activated $class = $this->is_activated ? 'pro-feature-wrapper active' : 'pro-feature-wrapper inactive'; // CSS class to style the wrapper based on activation status // Retrieve the X.AI API key value $xaiApiKey = isset($this->options['xai_api_key']) ? esc_attr($this->options['xai_api_key']) : ''; // Render the input field for the X.AI API key echo '
'; printf( '', $xaiApiKey, $disabled ); echo ''; // If the feature is not activated, show the overlay with a "Pro Only" message if (!$this->is_activated) { echo '
'; echo '' . esc_attr__('Pro Only', 'mxchat') . ''; echo '
'; } echo '
'; } public function claude_api_key_callback() { // Check if the feature is activated (paid feature) $disabled = $this->is_activated ? '' : 'disabled'; // Disable input if not activated $class = $this->is_activated ? 'pro-feature-wrapper active' : 'pro-feature-wrapper inactive'; // CSS class to style the wrapper based on activation status // Retrieve the Claude API key value $claudeApiKey = isset($this->options['claude_api_key']) ? esc_attr($this->options['claude_api_key']) : ''; // Render the input field for the Claude API key echo '
'; printf( '', $claudeApiKey, $disabled ); echo ''; // If the feature is not activated, show the overlay with a "Pro Only" message if (!$this->is_activated) { echo '
'; echo '' . esc_attr__('Pro Only', 'mxchat') . ''; echo '
'; } echo '
'; } public function deepseek_api_key_callback() { // Retrieve from your stored 'deepseek_api_key' in the mxchat_options array $apiKey = isset($this->options['deepseek_api_key']) ? esc_attr($this->options['deepseek_api_key']) : ''; // Notice we changed the name to "deepseek_api_key" (no array notation). echo ''; echo ''; } public function mxchat_woocommerce_consumer_key_callback() { // Load the entire 'mxchat_options' array $all_options = get_option('mxchat_options', []); // Retrieve the WooCommerce consumer key or set a default $consumer_key = isset($all_options['woocommerce_consumer_key']) ? $all_options['woocommerce_consumer_key'] : ''; // Check if the feature is activated (paid feature) $disabled = $this->is_activated ? '' : 'disabled'; $class = $this->is_activated ? 'pro-feature-wrapper active' : 'pro-feature-wrapper inactive'; echo '
'; // Render the input field printf( '', esc_attr($consumer_key), esc_attr($disabled) ); // Description for the input field echo '

' . esc_html__('Enter your WooCommerce consumer key for integration.', 'mxchat') . '

'; // Pro feature overlay for non-activated users if (!$this->is_activated) { echo '
'; echo '' . esc_attr__('Pro Only', 'mxchat') . ''; echo '
'; } echo '
'; } public function mxchat_woocommerce_consumer_secret_callback() { // Get value with fallback $consumer_secret = isset($this->options['woocommerce_consumer_secret']) ? esc_attr($this->options['woocommerce_consumer_secret']) : ''; // Check if the feature is activated (paid feature) $disabled = $this->is_activated ? '' : 'disabled'; $class = $this->is_activated ? 'pro-feature-wrapper active' : 'pro-feature-wrapper inactive'; echo '
'; // Output the password input echo sprintf( '', $consumer_secret, esc_attr($disabled) ); // Add show/hide button echo ''; // Pro feature overlay if (!$this->is_activated) { echo '
'; echo ''; echo '' . esc_attr__('Pro Only', 'mxchat') . ''; echo ''; echo '
'; } echo '
'; } public function mxchat_loops_api_key_callback() { // Support both old and new format $loops_api_key = isset($this->options['loops_api_key']) ? esc_attr($this->options['loops_api_key']) : ''; echo '
'; echo sprintf( '', $loops_api_key ); echo ''; echo '
'; echo '

' . esc_html__('Enter your Loops API Key here. (See FAQ for details)', 'mxchat') . '

'; } public function mxchat_loops_mailing_list_callback() { // Add error handling and type checking $loops_api_key = ''; $selected_list = ''; // Safely get the API key if (isset($this->options['loops_api_key']) && is_string($this->options['loops_api_key'])) { $loops_api_key = $this->options['loops_api_key']; } // Safely get the selected list if (isset($this->options['loops_mailing_list']) && is_string($this->options['loops_mailing_list'])) { $selected_list = $this->options['loops_mailing_list']; } if (!empty($loops_api_key)) { $lists = $this->mxchat_fetch_loops_mailing_lists($loops_api_key); if (is_array($lists) && !empty($lists)) { echo ''; } else { echo '

' . esc_html__('No lists found. Please verify your API Key.', 'mxchat') . '

'; } } else { echo '

' . esc_html__('Enter a valid Loops API Key to load mailing lists.', 'mxchat') . '

'; } } public function mxchat_triggered_phrase_response_callback() { $default_response = __('Would you like to join our mailing list? Please provide your email below.', 'mxchat'); $triggered_response = isset($this->options['triggered_phrase_response']) ? $this->options['triggered_phrase_response'] : $default_response; echo sprintf( '', esc_textarea($triggered_response) ); echo '

' . esc_html__('Enter the chatbot response when a trigger keyword is detected, prompting the user to share their email.', 'mxchat') . '

'; } public function mxchat_email_capture_response_callback() { $default_response = __('Thank you for providing your email! You\'ve been added to our list.', 'mxchat'); $email_capture_response = isset($this->options['email_capture_response']) ? $this->options['email_capture_response'] : $default_response; echo sprintf( '', esc_textarea($email_capture_response) ); echo '

' . esc_html__('Enter the message to send when a user provides their email.', 'mxchat') . '

'; } public function mxchat_pre_chat_message_callback() { // Load the entire 'mxchat_options' array $all_options = get_option('mxchat_options', []); // Retrieve the saved message or use the default value $default_message = __('Hey there! Ask me anything!', 'mxchat'); $pre_chat_message = isset($all_options['pre_chat_message']) ? $all_options['pre_chat_message'] : $default_message; // Output the textarea printf( '', esc_textarea($pre_chat_message) ); echo '

' . esc_html__('Set the message displayed to users before they start a chat. Use this to provide a friendly greeting or instructions.', 'mxchat') . '

'; } // Callback for AI Instructions textarea public function system_prompt_instructions_callback() { // Retrieve the current value of the system prompt instructions $instructions = isset($this->options['system_prompt_instructions']) ? esc_textarea($this->options['system_prompt_instructions']) : ''; // Render the textarea field printf( '', $instructions ); // Provide a helpful description echo '

' . esc_html__('Provide system-level instructions for the AI to guide its behavior. Be clear and concise for better results.', 'mxchat') . '

'; } public function mxchat_model_callback() { // Define available models grouped by provider $models = array( esc_html__('X.AI Models', 'mxchat') => array( 'grok-beta' => esc_html__('grok-beta (Early Beta)', 'mxchat'), 'grok-2' => esc_html__('Grok 2', 'mxchat') ), esc_html__('DeepSeek Models', 'mxchat') => array( 'deepseek-chat' => esc_html__('DeepSeek-V3', 'mxchat'), ), esc_html__('Claude Models', 'mxchat') => array( 'claude-3-5-sonnet-20241022' => esc_html__('Claude 3.5 Sonnet (Most Intelligent)', 'mxchat'), 'claude-3-opus-20240229' => esc_html__('Claude 3 Opus (Highly Complex Tasks)', 'mxchat'), 'claude-3-sonnet-20240229' => esc_html__('Claude 3 Sonnet (Balanced)', 'mxchat'), 'claude-3-haiku-20240307' => esc_html__('Claude 3 Haiku (Fastest)', 'mxchat') ), esc_html__('OpenAI Models', 'mxchat') => array( 'gpt-4o' => esc_html__('GPT-4o (Recommended)', 'mxchat'), 'gpt-4o-mini' => esc_html__('GPT-4o Mini (Fast and Lightweight)', 'mxchat'), 'gpt-4-turbo' => esc_html__('GPT-4 Turbo (High-Performance)', 'mxchat'), 'gpt-4' => esc_html__('GPT-4 (High Intelligence)', 'mxchat'), 'gpt-3.5-turbo' => esc_html__('GPT-3.5 Turbo (Affordable and Fast)', 'mxchat') ) ); // Retrieve the currently selected model from saved options $selected_model = isset($this->options['model']) ? esc_attr($this->options['model']) : 'gpt-4o'; // Begin the select dropdown echo ''; // Add a description below the dropdown echo '

' . esc_html__('Select the AI model to use for your chatbot. Pro-only models are marked accordingly.', 'mxchat') . '

'; } public function mxchat_top_bar_title_callback() { // Retrieve the current value of the top bar title from saved options $top_bar_title = isset($this->options['top_bar_title']) ? esc_attr($this->options['top_bar_title']) : ''; // Render the input field echo ''; // Add a description echo '

' . esc_html__('Enter the title text that will appear on the top bar of the chatbot.', 'mxchat') . '

'; } public function enable_email_block_callback() { // Load full plugin options array $all_options = get_option('mxchat_options', []); // Get the value, default to 'off' $enable_email_block = isset($all_options['enable_email_block']) ? $all_options['enable_email_block'] : 'off'; // Check if it's 'on' $checked = ($enable_email_block === 'on') ? 'checked' : ''; echo ''; echo '

' . esc_html__('Enable to require email before a user chats. Their email will appear at the top of the transcript.', 'mxchat') . '

'; } public function email_blocker_header_content_callback() { // Load the entire 'mxchat_options' array $all_options = get_option('mxchat_options', []); // Retrieve the saved content or default to empty $content = isset($all_options['email_blocker_header_content']) ? $all_options['email_blocker_header_content'] : ''; // Render the textarea echo ''; echo '

'; echo esc_html__('You may enter HTML here, such as <h2>Welcome</h2> or <p>Let\'s get started</p>.', 'mxchat'); echo ' ' . esc_html__('Email form will show for users who are not logged in or have not provided an email within 24h.', 'mxchat'); echo '

'; } public function email_blocker_button_text_callback() { // Load the entire 'mxchat_options' array $all_options = get_option('mxchat_options', []); // Retrieve the saved button text or default to empty $button_text = isset($all_options['email_blocker_button_text']) ? $all_options['email_blocker_button_text'] : ''; // Use esc_attr to safely render the existing text echo ''; echo '

'; echo esc_html__('Enter the text you want on the submit button, e.g. "Start Chat".', 'mxchat'); echo '

'; } public function mxchat_intro_message_callback() { // Load the entire 'mxchat_options' array $all_options = get_option('mxchat_options', []); // Retrieve the saved intro message or use the default $default_message = __('Hello! How can I assist you today?', 'mxchat'); $saved_message = isset($all_options['intro_message']) ? $all_options['intro_message'] : $default_message; // Output the textarea with the saved value ?>

', esc_attr($input_copy), esc_attr__('How can I assist?', 'mxchat') ); // Output the description echo '

' . esc_html__('This is the placeholder text for the chat input field.', 'mxchat') . '

'; } public function mxchat_close_button_color_callback() { $disabled = $this->is_activated ? '' : 'disabled'; $class = $this->is_activated ? 'pro-feature-wrapper active' : 'pro-feature-wrapper inactive'; echo '
'; echo sprintf( '', isset($this->options['close_button_color']) ? esc_attr($this->options['close_button_color']) : '#4a4a4a', esc_attr($disabled) ); if (!$this->is_activated) { echo '
'; echo ''; echo '' . esc_attr__('Pro Only', 'mxchat') . ''; echo ''; echo '
'; } echo '
'; } public function mxchat_chatbot_bg_color_callback() { $disabled = $this->is_activated ? '' : 'disabled'; $class = $this->is_activated ? 'pro-feature-wrapper active' : 'pro-feature-wrapper inactive'; echo '
'; echo sprintf( '', isset($this->options['chatbot_bg_color']) ? esc_attr($this->options['chatbot_bg_color']) : '#f9f9f9', esc_attr($disabled) ); if (!$this->is_activated) { echo '
'; echo ''; echo '' . esc_attr__('Pro Only', 'mxchat') . ''; echo ''; echo '
'; } echo '
'; } public function mxchat_user_message_bg_color_callback() { $disabled = $this->is_activated ? '' : 'disabled'; $class = $this->is_activated ? 'pro-feature-wrapper active' : 'pro-feature-wrapper inactive'; echo '
'; echo sprintf( '', isset($this->options['user_message_bg_color']) ? esc_attr($this->options['user_message_bg_color']) : '#0078d7', esc_attr($disabled) ); if (!$this->is_activated) { echo '
'; echo ''; echo '' . esc_attr__('Pro Only', 'mxchat') . ''; echo ''; echo '
'; } echo '
'; } public function mxchat_user_message_font_color_callback() { $disabled = $this->is_activated ? '' : 'disabled'; $class = $this->is_activated ? 'pro-feature-wrapper active' : 'pro-feature-wrapper inactive'; echo '
'; echo sprintf( '', isset($this->options['user_message_font_color']) ? esc_attr($this->options['user_message_font_color']) : '#ffffff', esc_attr($disabled) ); if (!$this->is_activated) { echo '
'; echo ''; echo '' . esc_attr__('Pro Only', 'mxchat') . ''; echo ''; echo '
'; } echo '
'; } public function mxchat_bot_message_bg_color_callback() { $disabled = $this->is_activated ? '' : 'disabled'; $class = $this->is_activated ? 'pro-feature-wrapper active' : 'pro-feature-wrapper inactive'; echo '
'; echo sprintf( '', isset($this->options['bot_message_bg_color']) ? esc_attr($this->options['bot_message_bg_color']) : '#e1e1e1', esc_attr($disabled) ); if (!$this->is_activated) { echo '
'; echo ''; echo '' . esc_attr__('Pro Only', 'mxchat') . ''; echo ''; echo '
'; } echo '
'; } public function mxchat_bot_message_font_color_callback() { $disabled = $this->is_activated ? '' : 'disabled'; $class = $this->is_activated ? 'pro-feature-wrapper active' : 'pro-feature-wrapper inactive'; echo '
'; echo sprintf( '', isset($this->options['bot_message_font_color']) ? esc_attr($this->options['bot_message_font_color']) : '#333333', esc_attr($disabled) ); if (!$this->is_activated) { echo '
'; echo ''; echo '' . esc_attr__('Pro Only', 'mxchat') . ''; echo ''; echo '
'; } echo '
'; } public function mxchat_live_agent_message_bg_color_callback() { $disabled = $this->is_activated ? '' : 'disabled'; $class = $this->is_activated ? 'pro-feature-wrapper active' : 'pro-feature-wrapper inactive'; echo '
'; echo sprintf( '', isset($this->options['live_agent_message_bg_color']) ? esc_attr($this->options['live_agent_message_bg_color']) : '#ffffff', esc_attr($disabled) ); if (!$this->is_activated) { echo '
'; echo ''; echo '' . esc_attr__('Pro Only', 'mxchat') . ''; echo ''; echo '
'; } echo '
'; } public function mxchat_live_agent_message_font_color_callback() { $disabled = $this->is_activated ? '' : 'disabled'; $class = $this->is_activated ? 'pro-feature-wrapper active' : 'pro-feature-wrapper inactive'; echo '
'; echo sprintf( '', isset($this->options['live_agent_message_font_color']) ? esc_attr($this->options['live_agent_message_font_color']) : '#333333', esc_attr($disabled) ); if (!$this->is_activated) { echo '
'; echo ''; echo '' . esc_attr__('Pro Only', 'mxchat') . ''; echo ''; echo '
'; } echo '
'; } public function mxchat_mode_indicator_bg_color_callback() { $disabled = $this->is_activated ? '' : 'disabled'; $class = $this->is_activated ? 'pro-feature-wrapper active' : 'pro-feature-wrapper inactive'; echo '
'; echo sprintf( '', isset($this->options['mode_indicator_bg_color']) ? esc_attr($this->options['mode_indicator_bg_color']) : '#767676', esc_attr($disabled) ); if (!$this->is_activated) { echo '
'; echo ''; echo '' . esc_attr__('Pro Only', 'mxchat') . ''; echo ''; echo '
'; } echo '
'; } public function mxchat_mode_indicator_font_color_callback() { $disabled = $this->is_activated ? '' : 'disabled'; $class = $this->is_activated ? 'pro-feature-wrapper active' : 'pro-feature-wrapper inactive'; echo '
'; echo sprintf( '', isset($this->options['mode_indicator_font_color']) ? esc_attr($this->options['mode_indicator_font_color']) : '#ffffff', esc_attr($disabled) ); if (!$this->is_activated) { echo '
'; echo ''; echo '' . esc_attr__('Pro Only', 'mxchat') . ''; echo ''; echo '
'; } echo '
'; } public function mxchat_toolbar_icon_color_callback() { $disabled = $this->is_activated ? '' : 'disabled'; $class = $this->is_activated ? 'pro-feature-wrapper active' : 'pro-feature-wrapper inactive'; echo '
'; echo sprintf( '', isset($this->options['toolbar_icon_color']) ? esc_attr($this->options['toolbar_icon_color']) : '#212121', esc_attr($disabled) ); if (!$this->is_activated) { echo '
'; echo ''; echo '' . esc_attr__('Pro Only', 'mxchat') . ''; echo ''; echo '
'; } echo '
'; } public function mxchat_top_bar_bg_color_callback() { $disabled = $this->is_activated ? '' : 'disabled'; $class = $this->is_activated ? 'pro-feature-wrapper active' : 'pro-feature-wrapper inactive'; echo '
'; echo sprintf( '', isset($this->options['top_bar_bg_color']) ? esc_attr($this->options['top_bar_bg_color']) : '#00b294', esc_attr($disabled) ); if (!$this->is_activated) { echo '
'; echo ''; echo '' . esc_attr__('Pro Only', 'mxchat') . ''; echo ''; echo '
'; } echo '
'; } public function mxchat_send_button_font_color_callback() { $disabled = $this->is_activated ? '' : 'disabled'; $class = $this->is_activated ? 'pro-feature-wrapper active' : 'pro-feature-wrapper inactive'; echo '
'; echo sprintf( '', isset($this->options['send_button_font_color']) ? esc_attr($this->options['send_button_font_color']) : '#ffffff', esc_attr($disabled) ); if (!$this->is_activated) { echo '
'; echo ''; echo '' . esc_attr__('Pro Only', 'mxchat') . ''; echo ''; echo '
'; } echo '
'; } public function mxchat_chatbot_background_color_callback() { $disabled = $this->is_activated ? '' : 'disabled'; $class = $this->is_activated ? 'pro-feature-wrapper active' : 'pro-feature-wrapper inactive'; echo '
'; echo sprintf( '', isset($this->options['chatbot_background_color']) ? esc_attr($this->options['chatbot_background_color']) : '#000000', esc_attr($disabled) ); if (!$this->is_activated) { echo '
'; echo ''; echo '' . esc_attr__('Pro Only', 'mxchat') . ''; echo ''; echo '
'; } echo '
'; } public function mxchat_icon_color_callback() { $disabled = $this->is_activated ? '' : 'disabled'; $class = $this->is_activated ? 'pro-feature-wrapper active' : 'pro-feature-wrapper inactive'; echo '
'; echo sprintf( '', isset($this->options['icon_color']) ? esc_attr($this->options['icon_color']) : '#ffffff', esc_attr($disabled) ); if (!$this->is_activated) { echo '
'; echo ''; echo '' . esc_attr__('Pro Only', 'mxchat') . ''; echo ''; echo '
'; } echo '
'; } public function mxchat_custom_icon_callback() { $disabled = $this->is_activated ? '' : 'disabled'; $class = $this->is_activated ? 'pro-feature-wrapper active' : 'pro-feature-wrapper inactive'; $custom_icon_url = isset($this->options['custom_icon']) ? esc_url($this->options['custom_icon']) : ''; echo '
'; echo sprintf( '', $custom_icon_url, esc_attr__('Enter PNG URL', 'mxchat'), esc_attr($disabled) ); // Preview container for the icon if (!empty($custom_icon_url)) { echo '
'; echo '' . esc_attr__('Custom Icon Preview', 'mxchat') . ''; echo '
'; } echo '

' . esc_html__('Upload your PNG icon and paste the URL here. Recommended size: 48x48 pixels.', 'mxchat') . '

'; if (!$this->is_activated) { echo '
'; echo ''; echo '' . esc_attr__('Pro Only', 'mxchat') . ''; echo ''; echo '
'; } echo '
'; } public function mxchat_title_icon_callback() { $disabled = $this->is_activated ? '' : 'disabled'; $class = $this->is_activated ? 'pro-feature-wrapper active' : 'pro-feature-wrapper inactive'; // Fixed the variable reference - it was using custom_icon instead of title_icon $title_icon_url = isset($this->options['title_icon']) ? esc_url($this->options['title_icon']) : ''; echo '
'; echo sprintf( '', $title_icon_url, esc_attr__('Enter PNG URL', 'mxchat'), esc_attr($disabled) ); // Preview container for the icon if (!empty($title_icon_url)) { echo '
'; echo '' . esc_attr__('Title Icon Preview', 'mxchat') . ''; echo '
'; } echo '

' . esc_html__('Upload your PNG icon and paste the URL here. Recommended size: 48x48 pixels.', 'mxchat') . '

'; if (!$this->is_activated) { echo '
'; echo ''; echo '' . esc_attr__('Pro Only', 'mxchat') . ''; echo ''; echo '
'; } echo '
'; } public function mxchat_chat_input_font_color_callback() { $disabled = $this->is_activated ? '' : 'disabled'; $class = $this->is_activated ? 'pro-feature-wrapper active' : 'pro-feature-wrapper inactive'; echo '
'; echo sprintf( '', isset($this->options['chat_input_font_color']) ? esc_attr($this->options['chat_input_font_color']) : '#555555', esc_attr($disabled) ); if (!$this->is_activated) { echo '
'; echo ''; echo '' . esc_attr__('Pro Only', 'mxchat') . ''; echo ''; echo '
'; } echo '
'; } public function mxchat_append_to_body_callback() { // Get value from options array, default to 'off' $append_to_body = isset($this->options['append_to_body']) ? $this->options['append_to_body'] : 'off'; $checked = ($append_to_body === 'on') ? 'checked' : ''; echo ''; echo '

' . esc_html__('Show chatbot automatically on all pages. When disabled, you can place the chatbot manually using shortcode [mxchat_chatbot floating="yes"].', 'mxchat') . '

'; } public function mxchat_privacy_toggle_callback() { // Load from mxchat_options array $options = get_option('mxchat_options', []); // Get privacy toggle value with fallback $privacy_toggle = isset($options['privacy_toggle']) ? $options['privacy_toggle'] : 'off'; $checked = ($privacy_toggle === 'on') ? 'checked' : ''; // Get privacy text with fallback $privacy_text = isset($options['privacy_text']) ? $options['privacy_text'] : __('By chatting, you agree to our privacy policy.', 'mxchat'); // Output the toggle switch echo ''; echo '

' . esc_html__('Enable this option to display a privacy notice below the chat widget.', 'mxchat') . '

'; // Output the custom text input field echo sprintf( '', esc_textarea($privacy_text) ); echo '

' . esc_html__('Enter the privacy policy text. You can include HTML links.', 'mxchat') . '

'; } public function mxchat_complianz_toggle_callback() { // Load from mxchat_options array $options = get_option('mxchat_options', []); // Get complianz toggle value with fallback $complianz_toggle = isset($options['complianz_toggle']) ? $options['complianz_toggle'] : 'off'; $checked = ($complianz_toggle === 'on') ? 'checked' : ''; // Check if the plugin is activated (paid feature) $disabled = $this->is_activated ? '' : 'disabled'; $class = $this->is_activated ? 'pro-feature-wrapper active' : 'pro-feature-wrapper inactive'; echo '
'; // Output the toggle switch echo ''; echo '

' . esc_html__('Enable this option to apply Complianz consent logic to the chatbot (must have Complianz Plugin).', 'mxchat') . '

'; // If the feature is not activated, show the Pro feature overlay if (!$this->is_activated) { echo '
'; echo ''; echo '' . esc_attr__('Pro Only', 'mxchat') . ''; echo ''; echo '
'; } echo '
'; } public function mxchat_link_target_toggle_callback() { // Load from mxchat_options array $options = get_option('mxchat_options', []); // Get link target toggle value with fallback $link_target_toggle = isset($options['link_target_toggle']) ? $options['link_target_toggle'] : 'off'; $checked = ($link_target_toggle === 'on') ? 'checked' : ''; // Output the toggle switch echo ''; echo '

' . esc_html__('Enable to open links in a new tab (default is to open in the same tab).', 'mxchat') . '

'; } public function mxchat_chat_persistence_toggle_callback() { // Load from mxchat_options array $options = get_option('mxchat_options', []); // Get chat persistence toggle value with fallback $chat_persistence_toggle = isset($options['chat_persistence_toggle']) ? $options['chat_persistence_toggle'] : 'off'; $checked = ($chat_persistence_toggle === 'on') ? 'checked' : ''; // Check if the plugin is activated (paid feature) $disabled = $this->is_activated ? '' : 'disabled'; $class = $this->is_activated ? 'pro-feature-wrapper active' : 'pro-feature-wrapper inactive'; echo '
'; // Output the toggle switch echo ''; echo '

' . esc_html__('Enable to keep chat history when users navigate tabs or return to the site within 24 hours.', 'mxchat') . '

'; // If not activated, show Pro feature overlay if (!$this->is_activated) { echo '
'; echo ''; echo '' . esc_attr__('Pro Only', 'mxchat') . ''; echo ''; echo '
'; } echo '
'; } public function mxchat_popular_question_1_callback() { // Load the full plugin options array $all_options = get_option('mxchat_options', []); // Retrieve the specific option for popular_question_1 $popular_question_1 = isset($all_options['popular_question_1']) ? $all_options['popular_question_1'] : ''; // Render the input field printf( '', esc_attr($popular_question_1), esc_attr__('Enter Popular Question 1', 'mxchat') ); // Add a description for the field echo '

' . esc_html__('This will be the first popular question in the chatbot.', 'mxchat') . '

'; } public function mxchat_popular_question_2_callback() { // Load the full plugin options array $all_options = get_option('mxchat_options', []); // Retrieve the specific option for popular_question_2 $popular_question_2 = isset($all_options['popular_question_2']) ? $all_options['popular_question_2'] : ''; // Check if the plugin is activated (paid feature) $disabled = $this->is_activated ? '' : 'disabled'; $class = $this->is_activated ? 'pro-feature-wrapper active' : 'pro-feature-wrapper inactive'; echo '
'; // Render the input field printf( '', esc_attr($popular_question_2), esc_attr__('Enter Popular Question 2', 'mxchat'), esc_attr($disabled) ); // Add a description for the field echo '

' . esc_html__('This will be the second popular question in the chatbot.', 'mxchat') . '

'; // If not activated, show Pro feature overlay if (!$this->is_activated) { echo '
'; echo '' . esc_attr__('Pro Only', 'mxchat') . ''; echo '
'; } echo '
'; } public function mxchat_popular_question_3_callback() { // Load the full plugin options array $all_options = get_option('mxchat_options', []); // Retrieve the specific option for popular_question_3 $popular_question_3 = isset($all_options['popular_question_3']) ? $all_options['popular_question_3'] : ''; // Check if the plugin is activated (paid feature) $disabled = $this->is_activated ? '' : 'disabled'; $class = $this->is_activated ? 'pro-feature-wrapper active' : 'pro-feature-wrapper inactive'; echo '
'; // Render the input field printf( '', esc_attr($popular_question_3), esc_attr(__('Enter Popular Question 3', 'mxchat')), esc_attr($disabled) ); // Add a description for the field echo '

' . esc_html__('This will be the third popular question in the chatbot.', 'mxchat') . '

'; // If not activated, show Pro feature overlay if (!$this->is_activated) { echo '
'; echo '' . esc_attr__('Pro Only', 'mxchat') . ''; echo '
'; } echo '
'; } public function mxchat_additional_popular_questions_callback() { // Load from both possible sources for backwards compatibility $options = get_option('mxchat_options', []); $additional_questions = isset($options['additional_popular_questions']) ? $options['additional_popular_questions'] : get_option('additional_popular_questions', array()); // Check if the feature is activated (paid feature) $disabled = $this->is_activated ? '' : 'disabled'; $class = $this->is_activated ? 'pro-feature-wrapper active' : 'pro-feature-wrapper inactive'; echo '
'; echo '
'; if (!empty($additional_questions)) { foreach ($additional_questions as $index => $question) { printf( '
', esc_attr($question), esc_attr(sprintf(__('Enter Additional Popular Question %d', 'mxchat'), $index + 4)), $index, esc_attr($disabled), esc_attr(__('Remove question', 'mxchat')), esc_attr($disabled), esc_html__('Remove', 'mxchat') ); } } else { printf( '
', esc_attr(__('Enter Additional Popular Question 4', 'mxchat')), esc_attr($disabled), esc_attr(__('Remove question', 'mxchat')), esc_attr($disabled), esc_html__('Remove', 'mxchat') ); } echo '
'; printf( '', esc_attr(__('Add question', 'mxchat')), esc_attr($disabled), esc_html__('Add Question', 'mxchat') ); echo '

' . esc_html__('You can add more popular questions beyond the default three here.', 'mxchat') . '

'; if (!$this->is_activated) { echo '
'; echo ''; echo '' . esc_attr__('Pro Only', 'mxchat') . ''; echo ''; echo '
'; } echo '
'; } public function mxchat_brave_api_key_callback() { $brave_api_key = isset($this->options['brave_api_key']) ? esc_attr($this->options['brave_api_key']) : ''; echo '
'; echo sprintf( '', $brave_api_key ); echo ''; echo '
'; echo '

' . __('Enter your Brave Search API Key here. (See FAQ for details)', 'mxchat') . '

'; } public function mxchat_brave_image_count_callback() { $brave_image_count = isset($this->options['brave_image_count']) ? intval($this->options['brave_image_count']) : 4; echo sprintf( '', $brave_image_count ); echo '

' . __('Select the number of images to return (1-6).', 'mxchat') . '

'; } public function mxchat_brave_safe_search_callback() { $brave_safe_search = isset($this->options['brave_safe_search']) ? esc_attr($this->options['brave_safe_search']) : 'strict'; echo ''; echo '

' . esc_html__('Set the Safe Search level for image searches. Brave Search only supports "Strict" and "Off" options.', 'mxchat') . '

'; } public function mxchat_brave_news_count_callback() { $brave_news_count = isset($this->options['brave_news_count']) ? intval($this->options['brave_news_count']) : 3; echo sprintf( '', $brave_news_count ); echo '

' . esc_html__('Select the number of news articles to retrieve (1-10).', 'mxchat') . '

'; } public function mxchat_brave_country_callback() { $brave_country = isset($this->options['brave_country']) ? esc_attr($this->options['brave_country']) : 'us'; echo sprintf( '', $brave_country ); echo '

' . esc_html__('Enter the country code (e.g., "us" for United States).', 'mxchat') . '

'; } public function mxchat_brave_language_callback() { $brave_language = isset($this->options['brave_language']) ? esc_attr($this->options['brave_language']) : 'en'; echo sprintf( '', $brave_language ); echo '

' . esc_html__('Enter the language code (e.g., "en" for English).', 'mxchat') . '

'; } // Section Callback public function mxchat_pdf_intent_section_callback() { echo '

' . esc_html__('Configure the intent settings for the Chat with PDF feature.', 'mxchat') . '

'; } public function mxchat_chat_toolbar_toggle_callback() { // Get chat toolbar toggle value with fallback $chat_toolbar_toggle = isset($this->options['chat_toolbar_toggle']) ? $this->options['chat_toolbar_toggle'] : 'off'; $checked = ($chat_toolbar_toggle === 'on') ? 'checked' : ''; // Check if the plugin is activated (paid feature) $disabled = $this->is_activated ? '' : 'disabled'; $class = $this->is_activated ? 'pro-feature-wrapper active' : 'pro-feature-wrapper inactive'; echo '
'; // Output the toggle switch echo ''; // Pro feature overlay if (!$this->is_activated) { echo '
'; echo ''; echo '' . esc_attr__('Pro Only', 'mxchat') . ''; echo ''; echo '
'; } echo '
'; echo '

' . esc_html__('Enable to display the chat toolbar, adding two icons below the chatbot input field for uploading PDF and Word documents (default is hidden).', 'mxchat') . '

'; } public function mxchat_pdf_intent_trigger_text_callback() { $disabled = $this->is_activated ? '' : 'disabled'; $class = $this->is_activated ? 'pro-feature-wrapper active' : 'pro-feature-wrapper inactive'; $default_text = __("Please provide the URL to the PDF you'd like to discuss.", 'mxchat'); echo '
'; echo sprintf( '', esc_attr__('Enter trigger text', 'mxchat'), esc_attr($disabled), isset($this->options['pdf_intent_trigger_text']) ? esc_textarea($this->options['pdf_intent_trigger_text']) : esc_textarea($default_text) ); echo '

' . esc_html__('Text displayed when the intent is triggered.', 'mxchat') . '

'; if (!$this->is_activated) { echo '
'; echo ''; echo '' . esc_attr__('Pro Only', 'mxchat') . ''; echo ''; echo '
'; } echo '
'; } public function mxchat_pdf_intent_success_text_callback() { $disabled = $this->is_activated ? '' : 'disabled'; $class = $this->is_activated ? 'pro-feature-wrapper active' : 'pro-feature-wrapper inactive'; $default_text = __("I've processed the PDF. What questions do you have about it?", 'mxchat'); echo '
'; echo sprintf( '', esc_attr__('Enter success text', 'mxchat'), esc_attr($disabled), isset($this->options['pdf_intent_success_text']) ? esc_textarea($this->options['pdf_intent_success_text']) : esc_textarea($default_text) ); echo '

' . esc_html__('Text displayed when the intent is successful.', 'mxchat') . '

'; if (!$this->is_activated) { echo '
'; echo ''; echo '' . esc_attr__('Pro Only', 'mxchat') . ''; echo ''; echo '
'; } echo '
'; } public function mxchat_pdf_intent_error_text_callback() { $disabled = $this->is_activated ? '' : 'disabled'; $class = $this->is_activated ? 'pro-feature-wrapper active' : 'pro-feature-wrapper inactive'; $default_text = __("Sorry, I couldn't process the PDF. Please ensure it's a valid file.", 'mxchat'); echo '
'; echo sprintf( '', esc_attr__('Enter error text', 'mxchat'), esc_attr($disabled), isset($this->options['pdf_intent_error_text']) ? esc_textarea($this->options['pdf_intent_error_text']) : esc_textarea($default_text) ); echo '

' . esc_html__('Text displayed when an error occurs during the intent.', 'mxchat') . '

'; if (!$this->is_activated) { echo '
'; echo ''; echo '' . esc_attr__('Pro Only', 'mxchat') . ''; echo ''; echo '
'; } echo '
'; } public function mxchat_pdf_max_pages_callback() { $disabled = $this->is_activated ? '' : 'disabled'; $class = $this->is_activated ? 'pro-feature-wrapper active' : 'pro-feature-wrapper inactive'; $max_pages = isset($this->options['pdf_max_pages']) ? intval($this->options['pdf_max_pages']) : 69; echo '
'; echo sprintf( '', esc_attr($max_pages), esc_attr($disabled) ); echo '' . esc_html($max_pages) . ''; echo '

' . esc_html__('Set the maximum number of document pages users can upload for processing. (1-69 pages)', 'mxchat') . '

'; if (!$this->is_activated) { echo '
'; echo ''; echo '' . esc_attr__('Pro Only', 'mxchat') . ''; echo ''; echo '
'; } echo '
'; } public function mxchat_live_agent_status_callback() { $disabled = $this->is_activated ? '' : 'disabled'; $class = $this->is_activated ? 'pro-feature-wrapper active' : 'pro-feature-wrapper inactive'; $status = isset($this->options['live_agent_status']) ? $this->options['live_agent_status'] : 'off'; echo '
'; echo ''; echo ''; if (!$this->is_activated) { echo '
'; echo '' . esc_attr__('Pro Only', 'mxchat') . ''; echo '
'; } echo '
'; } // Away Message Callback public function mxchat_live_agent_away_message_callback() { $disabled = $this->is_activated ? '' : 'disabled'; $class = $this->is_activated ? 'pro-feature-wrapper active' : 'pro-feature-wrapper inactive'; $message = isset($this->options['live_agent_away_message']) ? $this->options['live_agent_away_message'] : __('Sorry, live agents are currently unavailable. I can continue helping you as an AI assistant.', 'mxchat'); echo '
'; printf( '', esc_attr($disabled), esc_textarea($message) ); echo '

' . esc_html__('Message shown when live agents are offline.', 'mxchat') . '

'; if (!$this->is_activated) { echo '
'; echo '' . esc_attr__('Pro Only', 'mxchat') . ''; echo '
'; } echo '
'; } public function mxchat_live_agent_notification_message_callback() { $disabled = $this->is_activated ? '' : 'disabled'; $class = $this->is_activated ? 'pro-feature-wrapper active' : 'pro-feature-wrapper inactive'; $message = isset($this->options['live_agent_notification_message']) ? $this->options['live_agent_notification_message'] : __('Live agent has been notified.', 'mxchat'); echo '
'; printf( '', esc_attr($disabled), esc_textarea($message) ); echo '

' . esc_html__('Message shown when live transfer activated.', 'mxchat') . '

'; if (!$this->is_activated) { echo '
'; echo '' . esc_attr__('Pro Only', 'mxchat') . ''; echo '
'; } echo '
'; } public function mxchat_live_agent_webhook_url_callback() { $disabled = $this->is_activated ? '' : 'disabled'; $class = $this->is_activated ? 'pro-feature-wrapper active' : 'pro-feature-wrapper inactive'; $webhook_url = isset($this->options['live_agent_webhook_url']) ? esc_url($this->options['live_agent_webhook_url']) : esc_url(get_option('live_agent_webhook_url', '')); echo '
'; printf( '', $webhook_url, esc_attr($disabled) ); echo ''; echo '

' . esc_html__('Enter your Slack webhook URL for live agent notifications.', 'mxchat') . '

'; if (!$this->is_activated) { echo '
'; echo '' . esc_attr__('Pro Only', 'mxchat') . ''; echo '
'; } echo '
'; } public function mxchat_similarity_threshold_callback() { // Load from mxchat_options array $options = get_option('mxchat_options', []); // Get value with backwards compatibility $threshold = isset($options['similarity_threshold']) ? $options['similarity_threshold'] : get_option('mxchat_similarity_threshold', 80); echo '
'; echo sprintf( '', esc_attr($threshold) ); echo sprintf( '%s', esc_html($threshold) ); echo '
'; echo '

'; echo esc_html__('Set the similarity threshold (recommended: 75) to balance accuracy; too high might limit your bot\'s ability to find relevant knowledge.', 'mxchat'); echo '

'; } public function mxchat_live_agent_secret_key_callback() { $disabled = $this->is_activated ? '' : 'disabled'; $class = $this->is_activated ? 'pro-feature-wrapper active' : 'pro-feature-wrapper inactive'; echo '
'; printf( '', isset($this->options['live_agent_secret_key']) ? esc_attr($this->options['live_agent_secret_key']) : '', esc_attr($disabled) ); echo ''; echo '

' . esc_html__('Secret key for validating Slack requests. Keep this secure.', 'mxchat') . '

'; if (!$this->is_activated) { echo '
'; echo '' . esc_attr__('Pro Only', 'mxchat') . ''; echo '
'; } echo '
'; } public function mxchat_live_agent_bot_token_callback() { $disabled = $this->is_activated ? '' : 'disabled'; $class = $this->is_activated ? 'pro-feature-wrapper active' : 'pro-feature-wrapper inactive'; echo '
'; printf( '', isset($this->options['live_agent_bot_token']) ? esc_attr($this->options['live_agent_bot_token']) : '', esc_attr($disabled) ); echo ''; echo '

' . esc_html__('Your Slack Bot OAuth Token (starts with xoxb-). Keep this secure.', 'mxchat') . '

'; if (!$this->is_activated) { echo '
'; echo '' . esc_attr__('Pro Only', 'mxchat') . ''; echo '
'; } echo '
'; } public function mxchat_enqueue_admin_assets() { wp_enqueue_style('wp-color-picker'); // Get the plugin version or file modification time for cache busting $plugin_version = '1.6.4'; // Replace this with your plugin's version // File paths $color_picker_js_path = plugin_dir_path(__FILE__) . '../js/my-color-picker.js'; $embedding_check_js_path = plugin_dir_path(__FILE__) . '../js/embedding-check.js'; $admin_css_path = plugin_dir_path(__FILE__) . '../css/admin-style.css'; $transcripts_js_path = plugin_dir_path(__FILE__) . '../js/mxchat_transcripts.js'; // Check if files exist and get modification times $color_picker_version = file_exists($color_picker_js_path) ? filemtime($color_picker_js_path) : $plugin_version; $embedding_check_version = file_exists($embedding_check_js_path) ? filemtime($embedding_check_js_path) : $plugin_version; $admin_css_version = file_exists($admin_css_path) ? filemtime($admin_css_path) : $plugin_version; $transcripts_js_version = file_exists($transcripts_js_path) ? filemtime($transcripts_js_path) : $plugin_version; // Enqueue scripts and styles with corrected paths wp_enqueue_script( 'mxchat-color-picker', plugin_dir_url(__FILE__) . '../js/my-color-picker.js', array('wp-color-picker'), $color_picker_version, true ); wp_enqueue_script( 'mxchat-embedding-check', plugin_dir_url(__FILE__) . '../js/embedding-check.js', array(), $embedding_check_version, true ); wp_enqueue_script( 'mxchat-transcripts-js', plugin_dir_url(__FILE__) . '../js/mxchat_transcripts.js', array('jquery'), $transcripts_js_version, true ); wp_enqueue_script( 'mxchat-admin-js', plugin_dir_url(__FILE__) . '../js/mxchat-admin.js', array('jquery'), $plugin_version, true ); wp_localize_script('mxchat-admin-js', 'mxchatAdmin', array( 'ajax_url' => admin_url('admin-ajax.php'), 'license_nonce' => wp_create_nonce('mxchat_activate_license_nonce'), 'inline_edit_nonce' => wp_create_nonce('mxchat_save_inline_nonce'), 'setting_nonce' => wp_create_nonce('mxchat_save_setting_nonce'), )); // Enqueue the admin CSS wp_enqueue_style( 'mxchat-admin-css', plugin_dir_url(__FILE__) . '../css/admin-style.css', array(), $admin_css_version ); // Localize the script for color picker and settings wp_localize_script('mxchat-color-picker', 'mxchatStyleSettings', array( 'ajax_url' => admin_url('admin-ajax.php'), 'link_target_toggle' => $this->options['link_target_toggle'] ?? 'off', 'user_message_bg_color' => $this->options['user_message_bg_color'] ?? '#fff', 'user_message_font_color' => $this->options['user_message_font_color'] ?? '#212121', 'bot_message_bg_color' => $this->options['bot_message_bg_color'] ?? '#212121', 'bot_message_font_color' => $this->options['bot_message_font_color'] ?? '#fff', 'top_bar_bg_color' => $this->options['top_bar_bg_color'] ?? '#212121', 'send_button_font_color' => $this->options['send_button_font_color'] ?? '#212121', 'close_button_color' => $this->options['close_button_color'] ?? '#fff', 'chatbot_background_color' => $this->options['chatbot_background_color'] ?? '#212121', 'icon_color' => $this->options['icon_color'] ?? '#fff', 'chat_input_font_color' => $this->options['chat_input_font_color'] ?? '#212121', 'pre_chat_message' => $this->options['pre_chat_message'] ?? esc_html__('Hey there! Ask me anything!', 'mxchat'), 'rate_limit_message' => $this->options['rate_limit_message'] ?? esc_html__('Rate limit exceeded. Please try again later.', 'mxchat'), 'loops_api_key' => $this->options['loops_api_key'] ?? '', 'loops_mailing_list' => $this->options['loops_mailing_list'] ?? '', 'triggered_phrase_response' => $this->options['triggered_phrase_response'] ?? esc_html__('Would you like to join our mailing list? Please provide your email below.', 'mxchat'), 'email_capture_response' => $this->options['email_capture_response'] ?? esc_html__('Thank you for providing your email! You\'ve been added to our list.', 'mxchat'), 'pdf_intent_trigger_text' => $this->options['pdf_intent_trigger_text'] ?? esc_html__("Please provide the URL to the PDF you'd like to discuss.", 'mxchat'), 'pdf_intent_success_text' => $this->options['pdf_intent_success_text'] ?? esc_html__("I've processed the PDF. What questions do you have about it?", 'mxchat'), 'pdf_intent_error_text' => $this->options['pdf_intent_error_text'] ?? esc_html__("Sorry, I couldn't process the PDF. Please ensure it's a valid file.", 'mxchat'), 'pdf_max_pages' => $this->options['pdf_max_pages'] ?? 69, 'live_agent_webhook_url' => $this->options['live_agent_webhook_url'] ?? '', 'live_agent_secret_key' => $this->options['live_agent_secret_key'] ?? '', 'live_agent_bot_token' => $this->options['live_agent_bot_token'] ?? '', 'live_agent_message_bg_color' => $this->options['live_agent_message_bg_color'] ?? '#ffffff', 'live_agent_message_font_color' => $this->options['live_agent_message_font_color'] ?? '#333333', 'chat_toolbar_toggle' => $this->options['chat_toolbar_toggle'] ?? 'off', 'mode_indicator_bg_color' => $this->options['mode_indicator_bg_color'] ?? '#767676', 'mode_indicator_font_color' => $this->options['mode_indicator_font_color'] ?? '#ffffff', 'toolbar_icon_color' => $this->options['toolbar_icon_color'] ?? '#212121', )); } public function mxchat_sanitize($input) { $new_input = array(); if (isset($input['api_key'])) { $new_input['api_key'] = sanitize_text_field($input['api_key']); } if (isset($input['similarity_threshold'])) { $new_input['similarity_threshold'] = absint($input['similarity_threshold']); // Ensure it's an integer $new_input['similarity_threshold'] = min(max($new_input['similarity_threshold'], 70), 85); // Enforce range } if (isset($input['xai_api_key'])) { $new_input['xai_api_key'] = sanitize_text_field($input['xai_api_key']); } if (isset($input['claude_api_key'])) { $new_input['claude_api_key'] = sanitize_text_field($input['claude_api_key']); } if (isset($input['deepseek_api_key'])) { $new_input['deepseek_api_key'] = sanitize_text_field($input['deepseek_api_key']); } if (isset($input['enable_woocommerce_integration'])) { $new_input['enable_woocommerce_integration'] = $input['enable_woocommerce_integration'] === 'on' ? 'on' : 'off'; } if (isset($input['privacy_toggle'])) { $new_input['privacy_toggle'] = $input['privacy_toggle']; } if (isset($input['complianz_toggle'])) { $new_input['complianz_toggle'] = $input['complianz_toggle']; } // Handle custom privacy text input if (isset($input['privacy_text'])) { // Allow basic HTML for links $new_input['privacy_text'] = wp_kses_post($input['privacy_text']); } if (isset($input['system_prompt_instructions'])) { $new_input['system_prompt_instructions'] = sanitize_textarea_field($input['system_prompt_instructions']); } if (isset($input['mxchat_pro_email'])) { $new_input['mxchat_pro_email'] = sanitize_email($input['mxchat_pro_email']); } if (isset($input['mxchat_activation_key'])) { $new_input['mxchat_activation_key'] = sanitize_text_field($input['mxchat_activation_key']); } if (isset($input['append_to_body'])) { $new_input['append_to_body'] = $input['append_to_body'] === 'on' ? 'on' : 'off'; } if (isset($input['top_bar_title'])) { $new_input['top_bar_title'] = sanitize_text_field($input['top_bar_title']); } if (isset($input['enable_email_block'])) { $new_input['enable_email_block'] = sanitize_text_field($input['enable_email_block']); } if (isset($input['email_blocker_header_content'])) { // wp_kses_post() allows standard HTML tags permitted by WordPress $new_input['email_blocker_header_content'] = wp_kses_post($input['email_blocker_header_content']); } if (isset($input['email_blocker_button_text'])) { $new_input['email_blocker_button_text'] = sanitize_text_field($input['email_blocker_button_text']); } if (isset($input['intro_message'])) { $new_input['intro_message'] = sanitize_textarea_field($input['intro_message']); // Changed from sanitize_text_field } if (isset($input['input_copy'])) { $new_input['input_copy'] = sanitize_text_field($input['input_copy']); } if (isset($input['rate_limit_message'])) { $new_input['rate_limit_message'] = sanitize_text_field($input['rate_limit_message']); } if (isset($input['rate_limit_logged_out'])) { $allowed_limits = array('1', '3', '5', '10', '15', '20', '100', 'unlimited'); // Add 'unlimited' to allowed values $rate_limit = sanitize_text_field($input['rate_limit_logged_out']); if (in_array($rate_limit, $allowed_limits, true)) { $new_input['rate_limit_logged_out'] = $rate_limit; } else { $new_input['rate_limit_logged_out'] = '10'; // Default for logged-out users } } // Handle role rate limits if (isset($input['role_rate_limits']) && is_array($input['role_rate_limits'])) { $allowed_limits = array('1', '3', '5', '10', '15', '20', '100', 'unlimited'); $new_input['role_rate_limits'] = array(); foreach ($input['role_rate_limits'] as $role_id => $rate_limit) { $rate_limit = sanitize_text_field($rate_limit); if (in_array($rate_limit, $allowed_limits, true)) { $new_input['role_rate_limits'][$role_id] = $rate_limit; } else { $new_input['role_rate_limits'][$role_id] = '100'; // Default } } } if (isset($input['pre_chat_message'])) { $new_input['pre_chat_message'] = sanitize_textarea_field($input['pre_chat_message']); } if (isset($input['model'])) { $allowed_models = array( 'grok-beta', 'grok-2', 'deepseek-chat', 'claude-3-5-sonnet-20241022', 'claude-3-opus-20240229', 'claude-3-sonnet-20240229', 'claude-3-haiku-20240307', 'gpt-4o', 'gpt-4o-mini', 'gpt-4-turbo', 'gpt-4', 'gpt-3.5-turbo', ); if (in_array($input['model'], $allowed_models)) { $new_input['model'] = sanitize_text_field($input['model']); } } // Sanitize new pro features if (isset($input['close_button_color'])) { $new_input['close_button_color'] = sanitize_hex_color($input['close_button_color']); } if (isset($input['chatbot_bg_color'])) { $new_input['chatbot_bg_color'] = sanitize_hex_color($input['chatbot_bg_color']); } if (isset($input['woocommerce_consumer_key'])) { $new_input['woocommerce_consumer_key'] = sanitize_text_field($input['woocommerce_consumer_key']); } if (isset($input['woocommerce_consumer_secret'])) { $new_input['woocommerce_consumer_secret'] = sanitize_text_field($input['woocommerce_consumer_secret']); } if (isset($input['user_message_bg_color'])) { $new_input['user_message_bg_color'] = sanitize_hex_color($input['user_message_bg_color']); } if (isset($input['user_message_font_color'])) { $new_input['user_message_font_color'] = sanitize_hex_color($input['user_message_font_color']); } if (isset($input['bot_message_bg_color'])) { $new_input['bot_message_bg_color'] = sanitize_hex_color($input['bot_message_bg_color']); } if (isset($input['bot_message_font_color'])) { $new_input['bot_message_font_color'] = sanitize_hex_color($input['bot_message_font_color']); } if (isset($input['live_agent_message_bg_color'])) { $new_input['live_agent_message_bg_color'] = sanitize_hex_color($input['live_agent_message_bg_color']); } if (isset($input['live_agent_message_font_color'])) { $new_input['live_agent_message_font_color'] = sanitize_hex_color($input['live_agent_message_font_color']); } if (isset($input['mode_indicator_bg_color'])) { $new_input['mode_indicator_bg_color'] = sanitize_hex_color($input['mode_indicator_bg_color']); } if (isset($input['mode_indicator_font_color'])) { $new_input['mode_indicator_font_color'] = sanitize_hex_color($input['mode_indicator_font_color']); } if (isset($input['toolbar_icon_color'])) { $new_input['toolbar_icon_color'] = sanitize_hex_color($input['toolbar_icon_color']); } if (isset($input['top_bar_bg_color'])) { $new_input['top_bar_bg_color'] = sanitize_hex_color($input['top_bar_bg_color']); } if (isset($input['send_button_font_color'])) { $new_input['send_button_font_color'] = sanitize_hex_color($input['send_button_font_color']); } if (isset($input['chatbot_background_color'])) { $new_input['chatbot_background_color'] = sanitize_hex_color($input['chatbot_background_color']); } if (isset($input['icon_color'])) { $new_input['icon_color'] = sanitize_hex_color($input['icon_color']); } if (isset($input['custom_icon'])) { $new_input['custom_icon'] = esc_url_raw($input['custom_icon']); } if (isset($input['title_icon'])) { $new_input['title_icon'] = esc_url_raw($input['title_icon']); } if (isset($input['chat_input_font_color'])) { $new_input['chat_input_font_color'] = sanitize_hex_color($input['chat_input_font_color']); } // Sanitize link_target_toggle if (isset($input['link_target_toggle'])) { $new_input['link_target_toggle'] = $input['link_target_toggle'] === 'on' ? 'on' : 'off'; } // Sanitize Loops API Key if (isset($input['loops_api_key'])) { $new_input['loops_api_key'] = sanitize_text_field($input['loops_api_key']); } if (isset($input['chat_persistence_toggle'])) { $new_input['chat_persistence_toggle'] = $input['chat_persistence_toggle'] === 'on' ? 'on' : 'off'; } if (isset($input['popular_question_1'])) { $new_input['popular_question_1'] = sanitize_text_field($input['popular_question_1']); } if (isset($input['popular_question_2'])) { $new_input['popular_question_2'] = sanitize_text_field($input['popular_question_2']); } if (isset($input['popular_question_3'])) { $new_input['popular_question_3'] = sanitize_text_field($input['popular_question_3']); } if (isset($input['additional_popular_questions']) && is_array($input['additional_popular_questions'])) { $new_input['additional_popular_questions'] = array_map('sanitize_text_field', $input['additional_popular_questions']); } // Sanitize Loops Mailing List if (isset($input['loops_mailing_list'])) { $new_input['loops_mailing_list'] = sanitize_text_field($input['loops_mailing_list']); } // Sanitize Triggered Phrase Response if (isset($input['triggered_phrase_response'])) { $new_input['triggered_phrase_response'] = wp_kses_post($input['triggered_phrase_response']); } if (isset($input['email_capture_response'])) { $new_input['email_capture_response'] = sanitize_textarea_field($input['email_capture_response']); } // Sanitize Brave Search Settings if (isset($input['brave_api_key'])) { $new_input['brave_api_key'] = sanitize_text_field($input['brave_api_key']); } if (isset($input['brave_image_count'])) { $image_count = intval($input['brave_image_count']); $new_input['brave_image_count'] = ($image_count >=1 && $image_count <=6) ? $image_count : 4; } if (isset($input['brave_safe_search'])) { $allowed = array('strict', 'off'); $new_input['brave_safe_search'] = in_array($input['brave_safe_search'], $allowed, true) ? $input['brave_safe_search'] : 'strict'; } if (isset($input['brave_news_count'])) { $news_count = intval($input['brave_news_count']); $new_input['brave_news_count'] = ($news_count >=1 && $news_count <=10) ? $news_count : 3; } if (isset($input['brave_country'])) { $new_input['brave_country'] = sanitize_text_field($input['brave_country']); } if (isset($input['brave_language'])) { $new_input['brave_language'] = sanitize_text_field($input['brave_language']); } if (isset($input['chat_toolbar_toggle'])) { $new_input['chat_toolbar_toggle'] = $input['chat_toolbar_toggle'] === 'on' ? 'on' : 'off'; } if (isset($input['pdf_intent_trigger_text'])) { $new_input['pdf_intent_trigger_text'] = sanitize_text_field($input['pdf_intent_trigger_text']); } if (isset($input['pdf_intent_success_text'])) { $new_input['pdf_intent_success_text'] = sanitize_text_field($input['pdf_intent_success_text']); } if (isset($input['pdf_intent_error_text'])) { $new_input['pdf_intent_error_text'] = sanitize_text_field($input['pdf_intent_error_text']); } if (isset($input['pdf_max_pages'])) { $new_input['pdf_max_pages'] = intval($input['pdf_max_pages']); if ($new_input['pdf_max_pages'] < 1 || $new_input['pdf_max_pages'] > 69) { $new_input['pdf_max_pages'] = 69; // Default to 69 if out of range } } if (isset($input['live_agent_webhook_url'])) { $new_input['live_agent_webhook_url'] = esc_url_raw($input['live_agent_webhook_url']); } if (isset($input['live_agent_secret_key'])) { $new_input['live_agent_secret_key'] = sanitize_text_field($input['live_agent_secret_key']); } // Live Agent Integration if (isset($input['live_agent_bot_token'])) { $new_input['live_agent_bot_token'] = sanitize_text_field($input['live_agent_bot_token']); } if (isset($input['live_agent_status'])) { $new_input['live_agent_status'] = ($input['live_agent_status'] === 'on') ? 'on' : 'off'; } if (isset($input['live_agent_away_message'])) { $new_input['live_agent_away_message'] = sanitize_textarea_field($input['live_agent_away_message']); } if (isset($input['live_agent_notification_message'])) { $new_input['live_agent_notification_message'] = sanitize_textarea_field($input['live_agent_notification_message']); } return $new_input; } // Method to append the chatbot to the body public function mxchat_append_chatbot_to_body() { $options = get_option('mxchat_options'); if (isset($options['append_to_body']) && $options['append_to_body'] === 'on') { echo do_shortcode('[mxchat_chatbot floating="yes"]'); } } private static function mxchat_extract_main_content($html) { $dom = new DOMDocument; libxml_use_internal_errors(true); // Suppress HTML parsing errors @$dom->loadHTML($html); libxml_clear_errors(); $xpath = new DOMXPath($dom); // Simplified selectors focusing on common content areas $selectors = [ '//article', '//*[@id="content"]', '//*[@class="entry-content"]', '//main', ]; foreach ($selectors as $selector) { $nodes = $xpath->query($selector); if ($nodes->length > 0) { $content = ''; foreach ($nodes as $node) { $content .= $dom->saveHTML($node); } return $content; } } // Fallback: Return the entire body content if no specific selector matches $body = $dom->getElementsByTagName('body'); return $body->length > 0 ? $dom->saveHTML($body->item(0)) : $html; } private function mxchat_fetch_loops_mailing_lists($api_key) { $url = 'https://app.loops.so/api/v1/lists'; $response = wp_remote_get($url, array( 'headers' => array( 'Authorization' => 'Bearer ' . $api_key, 'Content-Type' => 'application/json' ) )); if (is_wp_error($response)) { return array(); } $body = wp_remote_retrieve_body($response); $lists = json_decode($body, true); return isset($lists) && is_array($lists) ? $lists : array(); } function mxchat_calculate_cosine_similarity($vec1, $vec2) { if (empty($vec1) || empty($vec2)) { return 0.0; } $dot_product = 0.0; $norm_a = 0.0; $norm_b = 0.0; for ($i = 0; $i < count($vec1); $i++) { $dot_product += $vec1[$i] * $vec2[$i]; $norm_a += pow($vec1[$i], 2); $norm_b += pow($vec2[$i], 2); } if ($norm_a == 0.0 || $norm_b == 0.0) { return 0.0; } else { return $dot_product / (sqrt($norm_a) * sqrt($norm_b)); } } } ?>