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_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'));
}
// Method to check if the license is active
private function is_license_active() {
$license_status = get_option('mxchat_license_status', 'inactive');
return $license_status === 'active';
}
// Initialize default options
private function initialize_default_options() {
$default_options = array(
'api_key' => '',
'xai_api_key' => '',
'system_prompt_instructions' => '[EXAMPLE INSTRUCTIONS] You are an AI Chatbot assistant for this website. The primary subject you should focus on is [insert proper subject here]. Your main goal is to assist visitors with questions related to this specific topic. Here are some key things to keep in mind:
- Your name is [Chatbot Name]. Always introduce yourself as this name when appropriate.
- Stay focused on topics related to [insert proper subject here]. If a visitor asks about an unrelated topic, politely redirect the conversation to how you can assist them with this subject. If there is an exception topic (e.g., "parking") that you should assist with, you may do so if instructed.
- When appropriate, highlight the benefits of [insert proper subject here]. Offer to guide visitors to relevant pages or provide them with more information.
- If a visitor asks for a purchase link or further information, provide them with this link: [Insert Purchase Link Here]. Always ensure that the link is relevant and directly related to the website\'s offerings.
- Keep your responses short, concise, and to the point. Provide clear and direct answers suitable for a chatbot interaction.
- If you reference specific content, provide a hyperlink to the relevant page using hypertext. Avoid including links that do not directly relate to the content or answer the visitor\'s query.
- Provide answers based on the knowledge available to you. If you do not have an answer to a specific question, let the visitor know that you don’t have the information and suggest where they might find it or offer to help with something else.',
'model' => 'gpt-3.5-turbo',
'rate_limit' => '100',
'rate_limit_message' => 'Rate limit exceeded. Please try again later.',
'top_bar_title' => 'MxChat',
'intro_message' => 'Hello! How can I assist you today?',
'input_copy' => 'How can I assist?',
'append_to_body' => 'off',
'close_button_color' => '#fff',
'chatbot_bg_color' => '#fff',
'user_message_bg_color' => '#fff',
'user_message_font_color' => '#212121',
'bot_message_bg_color' => '#212121',
'bot_message_font_color' => '#fff',
'top_bar_bg_color' => '#212121',
'send_button_font_color' => '#212121',
'chat_input_font_color' => '#212121',
'chatbot_background_color' => '#212121',
'icon_color' => '#fff',
'enable_woocommerce_integration' => '0',
'enable_woocommerce_order_access' => '0',
'link_target_toggle' => 'off',
'pre_chat_message' => 'Hey there! Ask me anything!',
// New fields for Loops Integration
'loops_api_key' => '',
'loops_mailing_list' => '',
'trigger_keywords' => '',
'triggered_phrase_response' => 'Would you like to join our mailing list? Please provide your email below.',
'email_capture_response' => 'Thank you for providing your email! You\'ve been added to our list.',
);
// 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);
}
// Update the $this->options property
$this->options = $merged_options;
}
public function mxchat_add_plugin_page() {
// Main menu page
add_menu_page(
'MxChat Settings',
'MxChat',
'manage_options',
'mxchat-max',
array($this, 'mxchat_create_admin_page'),
'dashicons-testimonial',
6
);
// Submenu page for Knowledge
add_submenu_page(
'mxchat-max',
'Prompts',
'Knowledge',
'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
'Chat Transcripts',
'Transcripts',
'manage_options',
'mxchat-transcripts',
array($this, 'mxchat_create_transcripts_page') // Prefixed function name with mxchat_
);
// Submenu page for Activation Key
add_submenu_page(
'mxchat-max',
'Pro Upgrade',
'Pro Upgrade',
'manage_options',
'mxchat-activation',
array($this, 'mxchat_create_activation_page')
);
}
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('Nonce verification failed.');
}
// 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', 'Error inserting content into the database. Please try again.', 30);
} else {
set_transient('mxchat_admin_notice_success', 'Content successfully submitted!', 30);
}
} else {
//error_log('Embedding generation failed for article content: ' . $article_content);
set_transient('mxchat_admin_notice_error', 'Embedding generation failed. Please ensure your API key is correct and try again.', 30);
}
// Redirect after setting the transient
wp_safe_redirect(esc_url(admin_url('admin.php?page=mxchat-prompts')));
exit;
}
public function mxchat_display_admin_notice() {
// Success notice
if ($message = get_transient('mxchat_admin_notice_success')) {
?>
prefix . 'mxchat_system_prompt_content';
// Clear relevant cache before deletion
$cache_key = 'prompt_' . $id;
wp_cache_delete($cache_key, 'mxchat_prompts');
// Delete the record using a prepared statement
$deleted = $wpdb->delete($table_name, array('id' => $id), array('%d'));
if ($deleted !== false) {
// Optionally, clear a general cache if you have one
wp_cache_delete('all_prompts', 'mxchat_prompts');
}
// Redirect to the prompts page with a success message
$redirect_url = add_query_arg(array(
'page' => 'mxchat-prompts',
'deleted' => 'true'
), admin_url('admin.php'));
wp_safe_redirect($redirect_url);
exit;
}
public function mxchat_create_admin_page() {
?>
is_activated): ?>
Limited-time offer: Get a lifetime MxChat Pro license for just $49.97 until 01.01.25! After that, it switches to an annual license at $99.97/year. Purchase now and be grandfathered into the lifetime deal!
Upgrade to MxChat Pro today!
wp_json_encode(array(
'model' => 'text-embedding-ada-002',
'input' => $text
)),
'headers' => array(
'Authorization' => 'Bearer ' . $api_key,
'Content-Type' => 'application/json'
),
));
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' => 'You do not have sufficient permissions.']);
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' => 'Selected chat sessions have been deleted.']);
} else {
echo wp_json_encode(['error' => 'No chat sessions selected for deletion.']);
}
wp_die();
}
public function mxchat_fetch_chat_history() {
global $wpdb;
$table_name = $wpdb->prefix . 'mxchat_chat_transcripts';
// Check if the current user has sufficient permissions
if (!current_user_can('manage_options')) {
echo esc_html__('You do not have sufficient permissions to view this page.', 'mxchat');
wp_die();
}
// Fetch chat transcripts from the database, ordered by timestamp
$chat_transcripts = $wpdb->get_results(
$wpdb->prepare("SELECT * FROM {$table_name} ORDER BY timestamp ASC")
);
// If no transcripts are available, display a message
if (empty($chat_transcripts)) {
echo esc_html__('No chat history available.', 'mxchat');
wp_die();
}
ob_start();
$current_session_id = '';
foreach ($chat_transcripts as $transcript) {
// Start a new session block if session ID changes
if ($current_session_id !== $transcript->session_id) {
if ($current_session_id !== '') {
echo ''; // Close the previous session block
}
$current_session_id = sanitize_text_field($transcript->session_id);
echo '
';
}
// Format the timestamp for display
$formatted_timestamp = date_i18n('F j, Y g:i a', strtotime($transcript->timestamp));
// Determine the role to display (user identifier or email for users, bot for the AI)
$role = $transcript->role;
if ($role === 'user') {
// Sanitize email if available
if (!empty($transcript->user_email)) {
$role = sanitize_email($transcript->user_email);
} else {
// Sanitize user identifier, anonymize if it's an IP address
$user_identifier = sanitize_text_field($transcript->user_identifier);
// Check if the user identifier is an IP address and anonymize it
if (filter_var($user_identifier, FILTER_VALIDATE_IP)) {
$role = preg_replace('/\.\d+$/', '.xxx', $user_identifier); // Mask the last octet
} else {
$role = $user_identifier; // If it's not an IP, just display the identifier
}
}
}
// Output the chat message
echo '
';
}
private function mxchat_add_option_field($id, $title, $callback = '') {
add_settings_field(
$id,
$title,
$callback ? array($this, $callback) : array($this, $id . '_callback'),
'mxchat-max',
'mxchat_setting_section_id',
$id === 'model' ? ['label_for' => 'model'] : []
);
}
public function api_key_callback() {
$apiKey = isset($this->options['api_key']) ? esc_attr($this->options['api_key']) : '';
echo '';
echo '';
}
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
// Render the input field for the X.AI API key
echo '
';
printf(
'',
isset($this->options['xai_api_key']) ? esc_attr($this->options['xai_api_key']) : '',
$disabled
);
echo '';
// If the feature is not activated, show the overlay with a "Pro Only" message
if (!$this->is_activated) {
echo '
';
}
public function mxchat_loops_api_key_callback() {
$loops_api_key = isset($this->options['loops_api_key']) ? esc_attr($this->options['loops_api_key']) : '';
echo '
';
printf(
'',
$loops_api_key
);
echo '';
echo '
';
echo '
Enter your Loops API Key here. (See FAQ for details)
';
}
public function mxchat_loops_mailing_list_callback() {
// Retrieve Loops API key and lists
$loops_api_key = isset($this->options['loops_api_key']) ? $this->options['loops_api_key'] : '';
$selected_list = isset($this->options['loops_mailing_list']) ? $this->options['loops_mailing_list'] : '';
if ($loops_api_key) {
// Fetch lists from Loops API
$lists = $this->mxchat_fetch_loops_mailing_lists($loops_api_key);
if ($lists) {
echo '';
} else {
echo '
No lists found. Please verify your API Key.
';
}
} else {
echo '
Enter a valid Loops API Key to load mailing lists.
';
}
}
public function mxchat_trigger_keywords_callback() {
$trigger_keywords = isset($this->options['trigger_keywords']) ? $this->options['trigger_keywords'] : '';
echo '';
echo '
Enter comma-separated trigger keywords (e.g., subscribe, discount, newsletter).
';
}
public function mxchat_triggered_phrase_response_callback() {
$triggered_response = isset($this->options['triggered_phrase_response']) ? $this->options['triggered_phrase_response'] : '';
echo '';
echo '
Enter the chatbot response when a trigger keyword is detected, prompting the user to share their email.
';
}
public function mxchat_email_capture_response_callback() {
$email_capture_response = isset($this->options['email_capture_response']) ? $this->options['email_capture_response'] : 'Thank you for providing your email! You\'ve been added to our list.';
echo '';
echo '
Enter the message to send when a user provides their email.
';
}
public function mxchat_pre_chat_message_callback() {
printf(
'',
isset($this->options['pre_chat_message']) ? esc_textarea($this->options['pre_chat_message']) : ''
);
}
// Callback for AI Instructions textarea
public function system_prompt_instructions_callback() {
printf(
'',
isset($this->options['system_prompt_instructions']) ? esc_textarea($this->options['system_prompt_instructions']) : ''
);
}
public function mxchat_model_callback() {
$models = array(
'X.AI Models' => array(
'grok-beta' => 'grok-beta'
),
'OpenAI Models' => array(
'gpt-4o' => 'gpt-4o',
'gpt-4o-mini' => 'gpt-4o-mini',
'gpt-4-turbo' => 'gpt-4-turbo',
'gpt-4' => 'gpt-4',
'gpt-3.5-turbo' => 'gpt-3.5-turbo'
)
);
$selected_model = isset($this->options['model']) ? $this->options['model'] : 'gpt-3.5-turbo';
echo '';
}
public function mxchat_top_bar_title_callback() {
printf(
'',
isset($this->options['top_bar_title']) ? esc_attr($this->options['top_bar_title']) : ''
);
}
public function mxchat_intro_message_callback() {
printf(
'',
isset($this->options['intro_message']) ? esc_textarea($this->options['intro_message']) : 'Hello! How can I assist you today?'
);
}
public function mxchat_input_copy_callback() {
printf(
'',
isset($this->options['input_copy']) ? esc_attr($this->options['input_copy']) : 'How can I assist?'
);
echo '
This is the placeholder text for the chat input field.
';
}
public function mxchat_close_button_color_callback() {
$disabled = $this->is_activated ? '' : 'disabled';
echo '
Enable this option to automatically append the chat widget to the body of every page (recommended). No need to manually use the shortcode [mxchat_chatbot floating="yes"].
';
}
public function mxchat_privacy_toggle_callback() {
// Check if the privacy toggle is enabled
$privacy_toggle_checked = isset($this->options['privacy_toggle']) && $this->options['privacy_toggle'] === 'on' ? 'checked' : '';
// Retrieve the stored privacy text if it exists
$privacy_text = isset($this->options['privacy_text']) ? wp_kses_post($this->options['privacy_text']) : 'By chatting, you agree to our privacy policy.';
// Output the toggle switch
echo '';
echo '
Enable this option to display a privacy notice below the chat widget.
';
// Output the custom text input field
printf(
'',
esc_textarea($privacy_text)
);
echo '
Enter the privacy policy text. You can include HTML links.
';
}
public function mxchat_complianz_toggle_callback() {
// Check if the Complianz toggle is enabled
$complianz_toggle_checked = isset($this->options['complianz_toggle']) && $this->options['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 '
Enable this option to apply Complianz consent logic to the chatbot.
';
// If the feature is not activated, show the Pro feature overlay
if (!$this->is_activated) {
echo '
';
echo '';
echo '
';
}
echo '
';
}
public function mxchat_link_target_toggle_callback() {
// Check if the toggle is enabled in the options
$link_target_toggle = isset($this->options['link_target_toggle']) && $this->options['link_target_toggle'] === 'on' ? 'checked' : '';
// Output the toggle switch
echo '';
echo '
Enable to open links in a new tab (default is to open in the same tab).
';
}
public function mxchat_chat_persistence_toggle_callback() {
// Check if chat persistence toggle is enabled
$chat_persistence_toggle_checked = isset($this->options['chat_persistence_toggle']) && $this->options['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 '
Enable to keep chat history when users navigate tabs or return to the site within 24 hours.
';
// If not activated, show Pro feature overlay
if (!$this->is_activated) {
echo '
';
echo '';
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.1.8'; // 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'),
'nonce' => wp_create_nonce('mxchat_activate_license_nonce'),
));
wp_enqueue_style(
'mxchat-admin-css',
plugin_dir_url(__FILE__) . '../css/admin-style.css',
array(),
$admin_css_version
);
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'] ?? 'Hey there! Ask me anything!',
'rate_limit_message' => $this->options['rate_limit_message'] ?? 'Rate limit exceeded. Please try again later.',
// New fields for Loops Integration
'loops_api_key' => $this->options['loops_api_key'] ?? '',
'loops_mailing_list' => $this->options['loops_mailing_list'] ?? '',
'trigger_keywords' => $this->options['trigger_keywords'] ?? '',
'triggered_phrase_response' => $this->options['triggered_phrase_response'] ?? 'Would you like to join our mailing list? Please provide your email below.',
'email_capture_response' => $this->options['email_capture_response'] ?? 'Thank you for providing your email! You\'ve been added to our list.'
));
}
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['xai_api_key'])) {
$new_input['xai_api_key'] = sanitize_text_field($input['xai_api_key']);
}
if (isset($input['enable_woocommerce_integration'])) {
$new_input['enable_woocommerce_integration'] = isset($input['enable_woocommerce_integration']) && $input['enable_woocommerce_integration'] === '1' ? '1' : '0';
}
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['enable_woocommerce_order_access'])) {
$new_input['enable_woocommerce_order_access'] = isset($input['enable_woocommerce_order_access']) && $input['enable_woocommerce_order_access'] === '1' ? '1' : '0';
}
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['intro_message'])) {
$new_input['intro_message'] = sanitize_text_field($input['intro_message']);
}
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'])) {
$allowed_limits = array('5', '10', '15', '20', '100');
$rate_limit = sanitize_text_field($input['rate_limit']);
if (in_array($rate_limit, $allowed_limits, true)) {
$new_input['rate_limit'] = $rate_limit;
} else {
// Set a default or a fallback value in case of an invalid entry
$new_input['rate_limit'] = '100';
}
}
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',
'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['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['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';
}
// Sanitize Loops Mailing List
if (isset($input['loops_mailing_list'])) {
$new_input['loops_mailing_list'] = sanitize_text_field($input['loops_mailing_list']);
}
// Sanitize Trigger Keywords
if (isset($input['trigger_keywords'])) {
$new_input['trigger_keywords'] = sanitize_text_field($input['trigger_keywords']);
}
// 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']);
}
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 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;
}
public function mxchat_handle_sitemap_submission() {
// Check if the form was submitted and the user has sufficient permissions
if (!isset($_POST['submit_sitemap']) || !current_user_can('manage_options')) {
return;
}
// Verify the nonce field for security
check_admin_referer('mxchat_submit_sitemap_action', 'mxchat_submit_sitemap_nonce');
// Sanitize and retrieve the submitted URL
$submitted_url = esc_url_raw($_POST['sitemap_url']); // Accept either a sitemap URL or a regular URL
// Fetch the content of the submitted URL
$response = wp_remote_get($submitted_url);
if (is_wp_error($response) || wp_remote_retrieve_response_code($response) !== 200) {
set_transient('mxchat_admin_notice_error', 'Failed to fetch the URL. Please check the URL and try again.', 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);
// Check if the URL points to a sitemap (XML) or a regular HTML page
if (strpos($content_type, 'xml') !== false || strpos($body_content, 'url as $url_element) {
$page_url = (string)$url_element->loc;
$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 = $this->mxchat_extract_main_content($page_html);
$sanitized_content = $this->mxchat_sanitize_content_for_api($page_content);
if (!empty($sanitized_content)) {
$embedding_vector = $this->mxchat_generate_embedding($sanitized_content);
if (is_array($embedding_vector)) {
MxChat_Utils::submit_content_to_db($sanitized_content, $page_url, $this->options['api_key']);
} else {
$embedding_success = false; // Set flag to false if any embedding fails
}
}
}
if ($embedding_success) {
set_transient('mxchat_admin_notice_success', 'Sitemap content successfully submitted!', 30);
} else {
set_transient('mxchat_admin_notice_error', 'Some content failed to embed. Please check your API key and try again.', 30);
}
} else {
// Handle Regular URL (HTML Page)
$page_content = $this->mxchat_extract_main_content($body_content);
$sanitized_content = $this->mxchat_sanitize_content_for_api($page_content);
if (!empty($sanitized_content)) {
$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', 'URL content successfully submitted!', 30);
} else {
set_transient('mxchat_admin_notice_error', 'Failed to generate embedding for the URL content. Please check your API key and try again.', 30);
}
} else {
set_transient('mxchat_admin_notice_error', 'No valid content found on the provided URL.', 30);
}
}
// Redirect after setting the transient
wp_safe_redirect(esc_url(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('/