options = get_option('mxchat_options', array()); add_shortcode('mxchat_chatbot', array($this, 'render_chatbot_shortcode')); add_action('wp_footer', array($this, 'append_chatbot_to_body')); } /** * UPDATED: Enhanced should_hide_chatbot method - only blocks auto-append, not shortcodes */ private function should_hide_chatbot($context = 'auto') { global $post; if (!$post) { return false; } // Only hide if it's the auto-append context (floating="yes" from global setting) // Allow shortcodes to work regardless of this setting if ($context === 'auto') { // Check new visibility field first $visibility = get_post_meta($post->ID, '_mxchat_page_visibility', true); if ($visibility === 'hide') { return true; } // Backward compat: check legacy field if new field not set if (empty($visibility)) { $hide_chatbot = get_post_meta($post->ID, '_mxchat_hide_chatbot', true); if ($hide_chatbot === '1') { return true; } } } return false; } /** * UPDATED: Enhanced append_chatbot_to_body method with context */ public function append_chatbot_to_body() { // Only run on public pages if (is_admin() || wp_doing_ajax()) { return; } // Check if auto-append chatbot should be hidden on this page if ($this->should_hide_chatbot('auto')) { return; // Don't show auto-appended chatbot } // Get the bot that should be displayed using new logic $bot_to_show = $this->get_display_bot(); // Don't show chatbot if determination is false if ($bot_to_show === false) { return; } // Handle consent for display $consent_category = 'marketing'; $has_consent = true; if ( isset($this->options['complianz_toggle']) && $this->options['complianz_toggle'] === 'on' && function_exists('cmplz_has_consent') ) { $has_consent = cmplz_has_consent($consent_category); } // Display the appropriate chatbot (always floating for auto-append) if ($bot_to_show && $bot_to_show !== 'default') { // Show specific bot echo do_shortcode('[mxchat_chatbot floating="yes" bot_id="' . esc_attr($bot_to_show) . '" has_consent="' . ($has_consent ? 'yes' : 'no') . '"]'); } else { // Show default bot echo do_shortcode('[mxchat_chatbot floating="yes" has_consent="' . ($has_consent ? 'yes' : 'no') . '"]'); } } private function mxchat_get_user_identifier() { return sanitize_text_field($_SERVER['REMOTE_ADDR']); } /** * UPDATED: Enhanced shortcode with context-aware hiding */ public function render_chatbot_shortcode($atts) { // UPDATED: Add bot_id parameter support and improve logic $attributes = shortcode_atts(array( 'floating' => 'yes', 'has_consent' => 'yes', 'bot_id' => '' // Support for multi-bot functionality - empty means auto-detect ), $atts); // Determine which bot to use $bot_id = $this->determine_bot_for_shortcode($attributes['bot_id']); // UPDATED: Only check hiding for floating shortcodes that could conflict with auto-append // Non-floating shortcodes should always work if ($attributes['floating'] === 'yes') { // For floating shortcodes, check if auto-append is hidden // This prevents duplicate floating chatbots if ($this->should_hide_chatbot('auto') && $this->is_auto_append_enabled()) { // If auto-append is enabled but hidden on this page, // allow the floating shortcode to work (user is overriding) // But if auto-append is disabled globally, also allow shortcode } } // Non-floating shortcodes (floating="no") should NEVER be blocked by the hide setting // This allows embedded chatbots even when floating is hidden $is_floating = $attributes['floating'] === 'yes'; $bot_id = sanitize_key($bot_id); // Sanitize bot ID // Rest of your existing shortcode rendering logic continues unchanged... // [All the existing HTML generation code remains the same] // Get bot-specific options if multi-bot add-on is active $bot_options = $this->get_bot_options($bot_id); // Use bot-specific options or fall back to default options $current_options = !empty($bot_options) ? $bot_options : $this->options; // [Rest of your existing rendering code stays exactly the same] // Just remove the old should_hide_chatbot() check from the beginning // Check for Complianz consent if the toggle is enabled $initial_visibility = 'hidden'; $additional_class = ''; if (isset($current_options['complianz_toggle']) && $current_options['complianz_toggle'] === 'on') { $additional_class = ' no-consent'; } $visibility_class = $initial_visibility . $additional_class; $theme_options = get_option('mxchat_theme_options', array()); $custom_send_image = isset($theme_options['custom_send_button_image']) ? esc_url($theme_options['custom_send_button_image']) : ''; $send_width = isset($theme_options['send_button_width']) ? intval($theme_options['send_button_width']) : 24; $send_height = isset($theme_options['send_button_height']) ? intval($theme_options['send_button_height']) : 24; $send_rotation = isset($theme_options['send_button_rotation']) ? intval($theme_options['send_button_rotation']) : 0; // Check if an AI theme is active (global or bot-specific) - if so, skip inline color styles $ai_theme_active = !empty($theme_options['active_ai_theme_css']); $bot_has_theme = isset($theme_options['bot_theme_assignments'][$bot_id]); $skip_inline_colors = $ai_theme_active || $bot_has_theme; // UPDATED: Use current_options instead of $this->options throughout $bg_color = $current_options['chatbot_background_color'] ?? '#fff'; $user_message_bg_color = $current_options['user_message_bg_color'] ?? '#fff'; $user_message_font_color = $current_options['user_message_font_color'] ?? '#212121'; $bot_message_bg_color = $current_options['bot_message_bg_color'] ?? '#212121'; $bot_message_font_color = $current_options['bot_message_font_color'] ?? '#fff'; $top_bar_bg_color = $current_options['top_bar_bg_color'] ?? '#212121'; $send_button_font_color = $current_options['send_button_font_color'] ?? '#212121'; $intro_message = $current_options['intro_message'] ?? esc_html__('Hello! How can I assist you today?', 'mxchat'); $top_bar_title = $current_options['top_bar_title'] ?? esc_html__('MxChat: Basic', 'mxchat'); $chatbot_background_color = $current_options['chatbot_background_color'] ?? '#212121'; $icon_color = $current_options['icon_color'] ?? '#fff'; $chat_input_font_color = $current_options['chat_input_font_color'] ?? '#212121'; $close_button_color = $current_options['close_button_color'] ?? '#fff'; $chatbot_bg_color = $current_options['chatbot_bg_color'] ?? '#fff'; $pre_chat_message = isset($current_options['pre_chat_message']) ? sanitize_textarea_field(trim($current_options['pre_chat_message'])) : ''; $user_id = sanitize_key($this->mxchat_get_user_identifier()); $email_state = $this->determine_email_collection_state(); $show_email_form = $email_state['show_email_form']; $user_email = $email_state['user_email'] ?? ''; $user_name = $email_state['user_name'] ?? ''; // Pre-chat dismissal now handled client-side via localStorage (zero server load) $input_copy = isset($current_options['input_copy']) ? esc_attr($current_options['input_copy']) : esc_attr__('How can I assist?', 'mxchat'); $rate_limit_message = isset($current_options['rate_limit_message']) ? esc_attr($current_options['rate_limit_message']) : esc_attr__('Rate limit exceeded. Please try again later.', 'mxchat'); $mode_indicator_bg_color = $current_options['mode_indicator_bg_color'] ?? '#212121'; $mode_indicator_font_color = $current_options['mode_indicator_font_color'] ?? '#fff'; $quick_questions_toggle_color = $current_options['quick_questions_toggle_color'] ?? '#212121'; $privacy_toggle = isset($current_options['privacy_toggle']) && $current_options['privacy_toggle'] === 'on'; $privacy_text = isset($current_options['privacy_text']) ? wp_kses_post($current_options['privacy_text']) : wp_kses_post(__('By chatting, you agree to our privacy policy.', 'mxchat')); $popular_question_1 = isset($current_options['popular_question_1']) ? esc_html($current_options['popular_question_1']) : ''; $popular_question_2 = isset($current_options['popular_question_2']) ? esc_html($current_options['popular_question_2']) : ''; $popular_question_3 = isset($current_options['popular_question_3']) ? esc_html($current_options['popular_question_3']) : ''; $additional_questions = isset($current_options['additional_popular_questions']) ? $current_options['additional_popular_questions'] : []; $custom_icon = isset($current_options['custom_icon']) ? esc_url($current_options['custom_icon']) : ''; $title_icon = isset($current_options['title_icon']) ? esc_url($current_options['title_icon']) : ''; // AI agent text - if explicitly set to empty string, hide the indicator entirely $ai_agent_text = isset($current_options['ai_agent_text']) ? $current_options['ai_agent_text'] : __('AI Agent', 'mxchat'); $live_agent_message_bg_color = $current_options['live_agent_message_bg_color'] ?? '#212121'; $live_agent_message_font_color = $current_options['live_agent_message_font_color'] ?? '#fff'; $enable_email_block = isset($current_options['enable_email_block']) && ($current_options['enable_email_block'] === '1' || $current_options['enable_email_block'] === 'on'); // Add name field variables $enable_name_field = isset($current_options['enable_name_field']) && ($current_options['enable_name_field'] === '1' || $current_options['enable_name_field'] === 'on'); $name_field_placeholder = isset($current_options['name_field_placeholder']) ? esc_attr($current_options['name_field_placeholder']) : esc_attr__('Enter your name', 'mxchat'); ob_start(); // Check if floating attribute is set to 'yes' and wrap accordingly if ($is_floating) { echo '
'; } // Add bot_id to the chatbot wrapper as a data attribute echo '
'; echo '
'; echo '
'; echo '
'; if (!empty($title_icon)) { echo ' '; } echo '

' . esc_html($top_bar_title) . '

'; echo '
'; // Only show mode indicator if ai_agent_text is not empty if (!empty(trim($ai_agent_text))) { echo '' . esc_html($ai_agent_text) . ''; } echo '
'; echo ' '; echo '
'; // 3b) Main chatbot container echo '
'; if ($enable_email_block) { echo ''; } echo ' '; echo '
'; echo '
'; echo '
'; echo '
'; echo wp_kses_post($intro_message); echo '
'; echo '
'; echo '
'; // end #chat-box // Replace the existing popular questions section with this: echo ' '; echo '
'; echo ' '; echo ' '; echo '
'; echo '
'; // PDF Upload Button - wrapped in conditional using current_options $show_pdf_button = isset($current_options['show_pdf_upload_button']) ? $current_options['show_pdf_upload_button'] : 'on'; if ($show_pdf_button === 'on') { echo ' '; echo ' '; } // Word Upload Button - wrapped in conditional using current_options $show_word_button = isset($current_options['show_word_upload_button']) ? $current_options['show_word_upload_button'] : 'on'; if ($show_word_button === 'on') { echo ' '; echo ' '; } // File containers echo ' '; echo ' '; // Perplexity Button if (apply_filters('mxchat_perplexity_should_show_logo', true)) { echo ' '; } // Image Analysis Button - hidden by default, controlled by MxChat Vision add-on echo ' '; echo ' '; echo '
'; echo ' '; echo '
'; echo '
'; echo '
'; if ($is_floating) { echo '
'; if (!empty($pre_chat_message)) { // Rendered hidden by default — JS checkPreChatDismissal() handles show/hide via localStorage echo ''; } echo '
'; echo ''; if (!empty($custom_icon)) { echo '' . esc_attr__('Chatbot Icon', 'mxchat') . ''; } else { $widget_icon_style = 'height: 48px; width: 48px;'; if (!$skip_inline_colors) { $widget_icon_style .= ' fill: ' . esc_attr($icon_color) . ';'; } echo ''; echo ' '; echo ' '; echo ''; } echo '
'; } return ob_get_clean(); } /** * Get bot-specific options for multi-bot functionality * Falls back to default options if bot_id is 'default' or multi-bot add-on is not active */ private function get_bot_options($bot_id = 'default') { // If default bot or multi-bot add-on not active, return empty (use default options) if ($bot_id === 'default' || !class_exists('MxChat_Multi_Bot_Manager')) { return array(); } //Hook for multi-bot add-on to provide bot-specific options $bot_options = apply_filters('mxchat_get_bot_options', array(), $bot_id); return is_array($bot_options) ? $bot_options : array(); } /** * Get bot-specific Pinecone configuration * Used in the knowledge retrieval functions */ private function get_bot_pinecone_config($bot_id = 'default') { // If default bot or multi-bot add-on not active, use default Pinecone config if ($bot_id === 'default' || !class_exists('MxChat_Multi_Bot_Manager')) { $addon_options = get_option('mxchat_pinecone_addon_options', array()); return array( 'use_pinecone' => (isset($addon_options['mxchat_use_pinecone']) && $addon_options['mxchat_use_pinecone'] === '1'), 'api_key' => $addon_options['mxchat_pinecone_api_key'] ?? '', 'host' => $addon_options['mxchat_pinecone_host'] ?? '', 'namespace' => $addon_options['mxchat_pinecone_namespace'] ?? '' ); } // Hook for multi-bot add-on to provide bot-specific Pinecone config $bot_pinecone_config = apply_filters('mxchat_get_bot_pinecone_config', array(), $bot_id); return is_array($bot_pinecone_config) ? $bot_pinecone_config : array(); } private function determine_email_collection_state() { // Logged-in users skip the email form if (is_user_logged_in()) { $current_user = wp_get_current_user(); return [ 'show_email_form' => false, 'user_email' => $current_user->user_email, 'user_name' => $current_user->display_name ?: $current_user->first_name ?: '' ]; } // For guests, default to showing the email form. // The session-based check happens client-side via AJAX since the // session ID lives in the browser cookie/localStorage. return [ 'show_email_form' => true, 'user_email' => '', 'user_name' => '' ]; } /** * NEW: Determine if and which chatbot should be displayed */ private function get_display_bot() { // Get page-specific settings from meta box $page_setting = $this->get_page_bot_setting(); // Get global settings - FIXED: Check for 'on' instead of 'on' $global_autoshow = isset($this->options['append_to_body']) && $this->options['append_to_body'] === 'on'; $global_default_bot = isset($this->options['default_bot']) ? $this->options['default_bot'] : 'default'; // If page specifically hides chatbot, don't show anything if ($page_setting && $page_setting['action'] === 'hide') { return false; } // If page specifies a specific bot, use that if ($page_setting && $page_setting['action'] === 'show') { return $page_setting['bot_id']; } // Page setting is 'global' or no page setting exists // Check global auto-show setting if ($global_autoshow) { // Check post type visibility settings if (!$this->should_show_on_current_post_type()) { return false; } // Global auto-show is enabled, return the default bot return $global_default_bot; } // Global auto-show is disabled and no page-specific bot selected // Don't show chatbot (user should use shortcodes) return false; } /** * Check if chatbot should be shown on the current post type */ private function should_show_on_current_post_type() { // Get visibility settings $mode = isset($this->options['post_type_visibility_mode']) ? $this->options['post_type_visibility_mode'] : 'all'; $list = isset($this->options['post_type_visibility_list']) ? $this->options['post_type_visibility_list'] : array(); // Ensure list is an array if (!is_array($list)) { $list = array(); } // If mode is 'all', show on all post types if ($mode === 'all') { return true; } // Get current post type $current_post_type = $this->get_current_post_type(); // If we can't determine post type, default to showing if (empty($current_post_type)) { return true; } // Check based on mode if ($mode === 'include') { // Only show on selected post types return in_array($current_post_type, $list); } elseif ($mode === 'exclude') { // Hide on selected post types return !in_array($current_post_type, $list); } // Default to showing return true; } /** * Get the current post type */ private function get_current_post_type() { // Try to get from queried object first $queried_object = get_queried_object(); if ($queried_object instanceof WP_Post) { return $queried_object->post_type; } // Try get_post_type() $post_type = get_post_type(); if ($post_type) { return $post_type; } // Check if we're on an archive if (is_post_type_archive()) { return get_query_var('post_type'); } // Check common archive types if (is_home() || is_single()) { return 'post'; } if (is_page()) { return 'page'; } return ''; } /** * Get page-specific bot setting using new visibility field with backward compat */ private function get_page_bot_setting($post_id = null) { if (!$post_id) { $post_id = get_the_ID(); } if (!$post_id) { return null; } // Check new visibility field first $visibility = get_post_meta($post_id, '_mxchat_page_visibility', true); if ($visibility === 'hide') { return array('action' => 'hide'); } if ($visibility === 'show') { $selected_bot = get_post_meta($post_id, '_mxchat_selected_bot', true); $bot_id = !empty($selected_bot) ? $selected_bot : 'default'; return array('action' => 'show', 'bot_id' => $bot_id); } // Backward compat: check legacy hide checkbox if no new field set if (empty($visibility)) { $hide_chatbot = get_post_meta($post_id, '_mxchat_hide_chatbot', true); if ($hide_chatbot === '1') { return array('action' => 'hide'); } } // Check if specific bot is selected (legacy path) $selected_bot = get_post_meta($post_id, '_mxchat_selected_bot', true); if (!empty($selected_bot)) { return array('action' => 'show', 'bot_id' => $selected_bot); } // Use global setting return array('action' => 'global'); } /** * NEW: Determine which bot to use for shortcode */ private function determine_bot_for_shortcode($shortcode_bot_id) { // If bot_id explicitly provided in shortcode, use that if (!empty($shortcode_bot_id)) { return $shortcode_bot_id; } // No bot_id in shortcode, check page setting $page_setting = $this->get_page_bot_setting(); if ($page_setting && $page_setting['action'] === 'show') { return $page_setting['bot_id']; } // Fall back to default return 'default'; } /** * NEW: Helper to check if auto-append is enabled globally */ private function is_auto_append_enabled() { return isset($this->options['append_to_body']) && $this->options['append_to_body'] === 'on'; } /** * UPDATED: Debug function with new context info */ /** * NEW: Helper method to get available bots (for admin notices, etc.) */ private function get_available_bots() { $bots = array('default' => __('Default Bot', 'mxchat')); // Check if multi-bot addon is active if (class_exists('MxChat_Multi_Bot_Manager')) { $multi_bot_manager = MxChat_Multi_Bot_Core_Manager::get_instance(); $available_bots = $multi_bot_manager->get_available_bots(); // Add the available bots foreach ($available_bots as $bot_id => $bot_name) { $bots[$bot_id] = $bot_name; } } return $bots; } } ?>