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

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

791 lines 43.4 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 if (!defined('ABSPATH')) {
3 exit; // Exit if accessed directly
4 }
5
6 class MxChat_Public {
7 private $options;
8
9 public function __construct() {
10 // Simply get the options without defining duplicated defaults
11 $this->options = get_option('mxchat_options', array());
12 add_shortcode('mxchat_chatbot', array($this, 'render_chatbot_shortcode'));
13 add_action('wp_footer', array($this, 'append_chatbot_to_body'));
14
15 // Initialize testing panel for admins
16 add_action('wp_enqueue_scripts', array($this, 'enqueue_testing_assets'));
17
18 // Add debug hook
19 add_action('wp_footer', array($this, 'debug_display_logic'));
20 }
21
22 /**
23 * Enqueue testing panel assets for admin users
24 */
25 public function enqueue_testing_assets() {
26 // Check if frontend debugger is enabled in settings
27 $options = get_option('mxchat_options', array());
28 $show_debugger = isset($options['show_frontend_debugger']) ? $options['show_frontend_debugger'] : 'on';
29
30 // Only load if setting is enabled AND (user is admin or testing parameter is present)
31 if ($show_debugger === 'on' && (current_user_can('administrator') || isset($_GET['mxchat_test']))) {
32
33 // Get plugin URL for assets
34 $plugin_url = plugin_dir_url(dirname(__FILE__));
35
36 // Enqueue test panel CSS
37 wp_enqueue_style(
38 'mxchat-test-panel',
39 $plugin_url . 'css/test-panel.css',
40 array(),
41 '2.5.2'
42 );
43
44 // Enqueue test panel JS
45 wp_enqueue_script(
46 'mxchat-test-panel',
47 $plugin_url . 'js/test-panel.js',
48 array('jquery'),
49 '2.5.2',
50 true
51 );
52
53 // Pass data to JavaScript
54 wp_localize_script('mxchat-test-panel', 'mxchatTestData', array(
55 'ajaxUrl' => admin_url('admin-ajax.php'),
56 'nonce' => wp_create_nonce('mxchat_test_nonce'),
57 'isAdmin' => current_user_can('administrator'),
58 'testingEnabled' => true
59 ));
60
61 // Add JavaScript flag to enable testing
62 add_action('wp_footer', array($this, 'add_testing_flag'));
63 }
64 }
65
66 /**
67 * Add JavaScript flag to enable testing panel
68 */
69 public function add_testing_flag() {
70 echo '<script>window.mxchatTestingEnabled = true;</script>';
71 }
72
73 /**
74 * Check if testing mode should be enabled
75 */
76 private function is_testing_mode_enabled() {
77 return (current_user_can('administrator') || isset($_GET['mxchat_test']));
78 }
79
80 /**
81 * UPDATED: Enhanced should_hide_chatbot method - only blocks auto-append, not shortcodes
82 */
83 private function should_hide_chatbot($context = 'auto') {
84 global $post;
85
86 if (!$post) {
87 return false;
88 }
89
90 $hide_chatbot = get_post_meta($post->ID, '_mxchat_hide_chatbot', true);
91
92 // Only hide if it's the auto-append context (floating="yes" from global setting)
93 // Allow shortcodes to work regardless of this setting
94 if ($context === 'auto' && $hide_chatbot === '1') {
95 return true;
96 }
97
98 return false;
99 }
100
101 /**
102 * UPDATED: Enhanced append_chatbot_to_body method with context
103 */
104 public function append_chatbot_to_body() {
105 // Only run on public pages
106 if (is_admin() || wp_doing_ajax()) {
107 return;
108 }
109
110 // Check if auto-append chatbot should be hidden on this page
111 if ($this->should_hide_chatbot('auto')) {
112 return; // Don't show auto-appended chatbot
113 }
114
115 // Get the bot that should be displayed using new logic
116 $bot_to_show = $this->get_display_bot();
117
118 // Don't show chatbot if determination is false
119 if ($bot_to_show === false) {
120 return;
121 }
122
123 // Handle consent for display
124 $consent_category = 'marketing';
125 $has_consent = true;
126
127 if (
128 isset($this->options['complianz_toggle']) &&
129 $this->options['complianz_toggle'] === 'on' &&
130 function_exists('cmplz_has_consent')
131 ) {
132 $has_consent = cmplz_has_consent($consent_category);
133 }
134
135 // Display the appropriate chatbot (always floating for auto-append)
136 if ($bot_to_show && $bot_to_show !== 'default') {
137 // Show specific bot
138 echo do_shortcode('[mxchat_chatbot floating="yes" bot_id="' . esc_attr($bot_to_show) . '" has_consent="' . ($has_consent ? 'yes' : 'no') . '"]');
139 } else {
140 // Show default bot
141 echo do_shortcode('[mxchat_chatbot floating="yes" has_consent="' . ($has_consent ? 'yes' : 'no') . '"]');
142 }
143 }
144
145 private function mxchat_get_user_identifier() {
146 return sanitize_text_field($_SERVER['REMOTE_ADDR']);
147 }
148
149 /**
150 * UPDATED: Enhanced shortcode with context-aware hiding
151 */
152 public function render_chatbot_shortcode($atts) {
153 // UPDATED: Add bot_id parameter support and improve logic
154 $attributes = shortcode_atts(array(
155 'floating' => 'yes',
156 'has_consent' => 'yes',
157 'bot_id' => '' // Support for multi-bot functionality - empty means auto-detect
158 ), $atts);
159
160 // Determine which bot to use
161 $bot_id = $this->determine_bot_for_shortcode($attributes['bot_id']);
162
163 // UPDATED: Only check hiding for floating shortcodes that could conflict with auto-append
164 // Non-floating shortcodes should always work
165 if ($attributes['floating'] === 'yes') {
166 // For floating shortcodes, check if auto-append is hidden
167 // This prevents duplicate floating chatbots
168 if ($this->should_hide_chatbot('auto') && $this->is_auto_append_enabled()) {
169 // If auto-append is enabled but hidden on this page,
170 // allow the floating shortcode to work (user is overriding)
171 // But if auto-append is disabled globally, also allow shortcode
172 }
173 }
174
175 // Non-floating shortcodes (floating="no") should NEVER be blocked by the hide setting
176 // This allows embedded chatbots even when floating is hidden
177
178 $is_floating = $attributes['floating'] === 'yes';
179 $bot_id = sanitize_key($bot_id); // Sanitize bot ID
180
181 // Rest of your existing shortcode rendering logic continues unchanged...
182 // [All the existing HTML generation code remains the same]
183
184 // Get bot-specific options if multi-bot add-on is active
185 $bot_options = $this->get_bot_options($bot_id);
186
187 // Use bot-specific options or fall back to default options
188 $current_options = !empty($bot_options) ? $bot_options : $this->options;
189
190 // [Rest of your existing rendering code stays exactly the same]
191 // Just remove the old should_hide_chatbot() check from the beginning
192
193 // Check for Complianz consent if the toggle is enabled
194 $initial_visibility = 'hidden';
195 $additional_class = '';
196
197 if (isset($current_options['complianz_toggle']) && $current_options['complianz_toggle'] === 'on') {
198 $additional_class = ' no-consent';
199 }
200 $visibility_class = $initial_visibility . $additional_class;
201
202 $theme_options = get_option('mxchat_theme_options', array());
203 $custom_send_image = isset($theme_options['custom_send_button_image']) ? esc_url($theme_options['custom_send_button_image']) : '';
204 $send_width = isset($theme_options['send_button_width']) ? intval($theme_options['send_button_width']) : 24;
205 $send_height = isset($theme_options['send_button_height']) ? intval($theme_options['send_button_height']) : 24;
206 $send_rotation = isset($theme_options['send_button_rotation']) ? intval($theme_options['send_button_rotation']) : 0;
207
208 // Check if an AI theme is active (global or bot-specific) - if so, skip inline color styles
209 $ai_theme_active = !empty($theme_options['active_ai_theme_css']);
210 $bot_has_theme = isset($theme_options['bot_theme_assignments'][$bot_id]);
211 $skip_inline_colors = $ai_theme_active || $bot_has_theme;
212
213 // UPDATED: Use current_options instead of $this->options throughout
214 $bg_color = $current_options['chatbot_background_color'] ?? '#fff';
215 $user_message_bg_color = $current_options['user_message_bg_color'] ?? '#fff';
216 $user_message_font_color = $current_options['user_message_font_color'] ?? '#212121';
217 $bot_message_bg_color = $current_options['bot_message_bg_color'] ?? '#212121';
218 $bot_message_font_color = $current_options['bot_message_font_color'] ?? '#fff';
219 $top_bar_bg_color = $current_options['top_bar_bg_color'] ?? '#212121';
220 $send_button_font_color = $current_options['send_button_font_color'] ?? '#212121';
221 $intro_message = $current_options['intro_message'] ?? esc_html__('Hello! How can I assist you today?', 'mxchat');
222 $top_bar_title = $current_options['top_bar_title'] ?? esc_html__('MxChat: Basic', 'mxchat');
223 $chatbot_background_color = $current_options['chatbot_background_color'] ?? '#212121';
224 $icon_color = $current_options['icon_color'] ?? '#fff';
225 $chat_input_font_color = $current_options['chat_input_font_color'] ?? '#212121';
226 $close_button_color = $current_options['close_button_color'] ?? '#fff';
227 $chatbot_bg_color = $current_options['chatbot_bg_color'] ?? '#fff';
228 $pre_chat_message = isset($current_options['pre_chat_message']) ? sanitize_text_field(trim($current_options['pre_chat_message'])) : '';
229 $user_id = sanitize_key($this->mxchat_get_user_identifier());
230 $email_state = $this->determine_email_collection_state();
231 $show_email_form = $email_state['show_email_form'];
232 $user_email = $email_state['user_email'] ?? '';
233 $user_name = $email_state['user_name'] ?? '';
234 $transient_key = 'mxchat_pre_chat_message_dismissed_' . $user_id;
235 $input_copy = isset($current_options['input_copy']) ? esc_attr($current_options['input_copy']) : esc_attr__('How can I assist?', 'mxchat');
236 $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');
237 $mode_indicator_bg_color = $current_options['mode_indicator_bg_color'] ?? '#212121';
238 $mode_indicator_font_color = $current_options['mode_indicator_font_color'] ?? '#fff';
239 $quick_questions_toggle_color = $current_options['quick_questions_toggle_color'] ?? '#212121';
240
241 $privacy_toggle = isset($current_options['privacy_toggle']) && $current_options['privacy_toggle'] === 'on';
242 $privacy_text = isset($current_options['privacy_text']) ? wp_kses_post($current_options['privacy_text']) : wp_kses_post(__('By chatting, you agree to our <a href="https://example.com/privacy-policy" target="_blank">privacy policy</a>.', 'mxchat'));
243
244 $popular_question_1 = isset($current_options['popular_question_1']) ? esc_html($current_options['popular_question_1']) : '';
245 $popular_question_2 = isset($current_options['popular_question_2']) ? esc_html($current_options['popular_question_2']) : '';
246 $popular_question_3 = isset($current_options['popular_question_3']) ? esc_html($current_options['popular_question_3']) : '';
247 $additional_questions = isset($current_options['additional_popular_questions']) ? $current_options['additional_popular_questions'] : [];
248 $custom_icon = isset($current_options['custom_icon']) ? esc_url($current_options['custom_icon']) : '';
249 $title_icon = isset($current_options['title_icon']) ? esc_url($current_options['title_icon']) : '';
250 // AI agent text - if explicitly set to empty string, hide the indicator entirely
251 $ai_agent_text = isset($current_options['ai_agent_text']) ? $current_options['ai_agent_text'] : __('AI Agent', 'mxchat');
252
253 $live_agent_message_bg_color = $current_options['live_agent_message_bg_color'] ?? '#212121';
254 $live_agent_message_font_color = $current_options['live_agent_message_font_color'] ?? '#fff';
255 $enable_email_block = isset($current_options['enable_email_block']) &&
256 ($current_options['enable_email_block'] === '1' || $current_options['enable_email_block'] === 'on');
257
258 // Add name field variables
259 $enable_name_field = isset($current_options['enable_name_field']) &&
260 ($current_options['enable_name_field'] === '1' || $current_options['enable_name_field'] === 'on');
261 $name_field_placeholder = isset($current_options['name_field_placeholder']) ?
262 esc_attr($current_options['name_field_placeholder']) :
263 esc_attr__('Enter your name', 'mxchat');
264
265 ob_start();
266
267 // Check if floating attribute is set to 'yes' and wrap accordingly
268 if ($is_floating) {
269 echo '<div id="floating-chatbot-' . esc_attr($bot_id) . '" class="floating-chatbot ' . $initial_visibility . $additional_class . '">';
270 }
271
272 // Add bot_id to the chatbot wrapper as a data attribute
273 echo '<div id="mxchat-chatbot-wrapper-' . esc_attr($bot_id) . '" class="mxchat-chatbot-wrapper" data-bot-id="' . esc_attr($bot_id) . '">';
274
275 echo ' <div class="chatbot-top-bar" id="exit-chat-button-' . esc_attr($bot_id) . '"' . ($skip_inline_colors ? '' : ' style="background: ' . esc_attr($top_bar_bg_color) . ';"') . '>';
276 echo ' <div class="chatbot-title-container">';
277 echo ' <div class="chatbot-title-group">';
278 if (!empty($title_icon)) {
279 echo ' <img src="' . esc_url($title_icon) . '" alt="" class="chatbot-title-icon">';
280 }
281 echo ' <p class="chatbot-title"' . ($skip_inline_colors ? '' : ' style="color: ' . esc_attr($close_button_color) . ';"') . '>' . esc_html($top_bar_title) . '</p>';
282 echo ' </div>';
283 // Only show mode indicator if ai_agent_text is not empty
284 if (!empty(trim($ai_agent_text))) {
285 echo '<span class="chat-mode-indicator" id="chat-mode-indicator-' . esc_attr($bot_id) . '" data-ai-text="' . esc_attr($ai_agent_text) . '"' . ($skip_inline_colors ? '' : ' style="color: ' . esc_attr($mode_indicator_font_color) . '; background-color: ' . esc_attr($mode_indicator_bg_color) . ';"') . '>' . esc_html($ai_agent_text) . '</span>';
286 }
287 echo ' </div>';
288 echo ' <button class="exit-chat" type="button" aria-label="' . esc_attr__('Minimize', 'mxchat') . '"' . ($skip_inline_colors ? '' : ' style="color: ' . esc_attr($close_button_color) . ';"') . '>';
289 echo ' <svg xmlns="http://www.w3.org/2000/svg" height="24" viewBox="0 0 24 24" width="24" id="ic-minimize"' . ($skip_inline_colors ? '' : ' style="fill: ' . esc_attr($close_button_color) . ';"') . '>';
290 echo ' <path d="M0 0h24v24H0z" fill="none"></path>';
291 echo ' <path d="M11.67 3.87L9.9 2.1 0 12l9.9 9.9 1.77-1.77L3.54 12z"></path>';
292 echo ' </svg>';
293 echo ' <span>' . esc_html__('Minimize', 'mxchat') . '</span>';
294 echo ' </button>';
295 echo ' </div>';
296
297 // 3b) Main chatbot container
298 echo ' <div id="mxchat-chatbot-' . esc_attr($bot_id) . '" class="mxchat-chatbot"' . ($skip_inline_colors ? '' : ' style="background-color: ' . esc_attr($chatbot_bg_color) . ';"') . '>';
299
300 if ($enable_email_block) {
301 echo '<div id="email-blocker-' . esc_attr($bot_id) . '" class="email-blocker" style="' . ($show_email_form ? '' : 'display: none;') . '">';
302 echo ' <div class="email-blocker-header">';
303
304 $header_html = isset($current_options['email_blocker_header_content'])
305 ? $current_options['email_blocker_header_content']
306 : '';
307 echo wp_kses_post($header_html);
308
309 echo ' </div>';
310 echo ' <form id="email-collection-form-' . esc_attr($bot_id) . '" class="email-collection-form" method="POST" action="">';
311
312 // Add name field if enabled
313 if ($enable_name_field) {
314 echo ' <label for="user-name-' . esc_attr($bot_id) . '" class="sr-only mxchat-name-label">' . esc_html__('Name', 'mxchat') . '</label>';
315 echo ' <input type="text" id="user-name-' . esc_attr($bot_id) . '" name="user_name" class="mxchat-name-input" required placeholder="' . $name_field_placeholder . '" />';
316 }
317
318 echo ' <label for="user-email-' . esc_attr($bot_id) . '" class="sr-only">' . esc_html__('Email Address', 'mxchat') . '</label>';
319 echo ' <input type="email" id="user-email-' . esc_attr($bot_id) . '" name="user_email" class="mxchat-email-input" required placeholder="' . esc_attr__('Enter your email address', 'mxchat') . '" />';
320 echo '<button type="submit" id="email-submit-button-' . esc_attr($bot_id) . '" class="email-submit-button">';
321 $button_text = isset($current_options['email_blocker_button_text'])
322 ? $current_options['email_blocker_button_text']
323 : esc_html__('Start Chat', 'mxchat');
324 echo esc_html($button_text);
325 echo '</button>';
326 echo ' </form>';
327 echo '</div>';
328 }
329
330 echo ' <div id="chat-container-' . esc_attr($bot_id) . '" class="chat-container" style="' . ($enable_email_block && $show_email_form ? 'display: none;' : '') . '">';
331 echo ' <div id="chat-box-' . esc_attr($bot_id) . '" class="chat-box">';
332 echo ' <div class="bot-message"' . ($skip_inline_colors ? '' : ' style="background: ' . esc_attr($bot_message_bg_color) . ';"') . '>';
333 echo ' <div dir="auto"' . ($skip_inline_colors ? '' : ' style="color: ' . esc_attr($bot_message_font_color) . ';"') . '>';
334 echo wp_kses_post($intro_message);
335 echo ' </div>';
336 echo ' </div>';
337 echo ' </div>'; // end #chat-box
338
339
340 // Replace the existing popular questions section with this:
341 echo ' <div id="mxchat-popular-questions-' . esc_attr($bot_id) . '" class="mxchat-popular-questions">';
342 echo ' <div class="mxchat-popular-questions-container">';
343
344 // Collapse button (down arrow) - shows when open, centered at top
345 echo ' <button class="questions-collapse-btn" aria-label="' . esc_attr__('Hide Quick Questions', 'mxchat') . '">';
346 echo ' <svg width="25" height="25" viewBox="0 0 24 24" fill="none"' . ($skip_inline_colors ? '' : ' stroke="' . esc_attr($quick_questions_toggle_color) . '"') . ' stroke-width="2">';
347 echo ' <polyline points="6,9 12,15 18,9"></polyline>';
348 echo ' </svg>';
349 echo ' </button>';
350
351 // Expand button (up arrow) - shows when collapsed
352 echo ' <button class="questions-toggle-btn" aria-label="' . esc_attr__('Show Quick Questions', 'mxchat') . '">';
353 echo ' <svg width="25" height="25" viewBox="0 0 24 24" fill="none"' . ($skip_inline_colors ? '' : ' stroke="' . esc_attr($quick_questions_toggle_color) . '"') . ' stroke-width="2">';
354 echo ' <polyline points="18,15 12,9 6,15"></polyline>';
355 echo ' </svg>';
356 echo ' </button>';
357
358 if (!empty($popular_question_1)) {
359 echo '<button class="mxchat-popular-question" dir="auto">' . esc_html($popular_question_1) . '</button>';
360 }
361 if (!empty($popular_question_2)) {
362 echo '<button class="mxchat-popular-question" dir="auto">' . esc_html($popular_question_2) . '</button>';
363 }
364 if (!empty($popular_question_3)) {
365 echo '<button class="mxchat-popular-question" dir="auto">' . esc_html($popular_question_3) . '</button>';
366 }
367
368 if (!empty($additional_questions) && is_array($additional_questions)) {
369 foreach ($additional_questions as $index => $question) {
370 if (!empty($question)) {
371 echo '<button class="mxchat-popular-question" dir="auto">' . esc_html($question) . '</button>';
372 }
373 }
374 }
375
376 echo ' </div>';
377 echo ' </div>';
378
379 echo ' <div id="input-container-' . esc_attr($bot_id) . '" class="input-container">';
380 echo ' <textarea id="chat-input-' . esc_attr($bot_id) . '" class="chat-input" dir="auto" placeholder="' . esc_attr($input_copy) . '"' . ($skip_inline_colors ? '' : ' style="color: ' . esc_attr($chat_input_font_color) . ';"') . '></textarea>';
381 echo ' <button id="send-button-' . esc_attr($bot_id) . '" class="send-button" aria-label="' . esc_attr__('Send message', 'mxchat') . '">';
382 if (!empty($custom_send_image)) {
383 echo ' <img src="' . esc_url($custom_send_image) . '" alt="' . esc_attr__('Send', 'mxchat') . '" style="width: ' . intval($send_width) . 'px; height: ' . intval($send_height) . 'px; transform: rotate(' . intval($send_rotation) . 'deg);" />';
384 } else {
385 $send_svg_style = 'width: ' . intval($send_width) . 'px; height: ' . intval($send_height) . 'px; transform: rotate(' . intval($send_rotation) . 'deg);';
386 if (!$skip_inline_colors) {
387 $send_svg_style = 'fill: ' . esc_attr($send_button_font_color) . '; ' . $send_svg_style;
388 }
389 echo ' <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" style="' . $send_svg_style . '">';
390 echo ' <path d="M498.1 5.6c10.1 7 15.4 19.1 13.5 31.2l-64 416c-1.5 9.7-7.4 18.2-16 23s-18.9 5.4-28 1.6L284 427.7l-68.5 74.1c-8.9 9.7-22.9 12.9-35.2 8.1S160 493.2 160 480V396.4c0-4 1.5-7.8 4.2-10.7L331.8 202.8c5.8-6.3 5.6-16-.4-22s-15.7-6.4-22-.7L106 360.8 17.7 316.6C7.1 311.3 .3 300.7 0 288.9s5.9-22.8 16.1-28.7l448-256c10.7-6.1 23.9-5.5 34 1.4z"></path>';
391 echo ' </svg>';
392 }
393 echo ' </button>';
394 echo ' </div>';
395
396 echo ' <div class="chat-toolbar">';
397
398 // PDF Upload Button - wrapped in conditional using current_options
399 $show_pdf_button = isset($current_options['show_pdf_upload_button']) ? $current_options['show_pdf_upload_button'] : 'on';
400 if ($show_pdf_button === 'on') {
401 echo ' <input type="file" id="pdf-upload-' . esc_attr($bot_id) . '" class="pdf-upload" accept=".pdf" style="display: none;">';
402 echo ' <button id="pdf-upload-btn-' . esc_attr($bot_id) . '" class="toolbar-btn pdf-upload-btn" title="' . esc_attr__('Upload PDF', 'mxchat') . '">';
403 echo ' <!-- Icon from Font Awesome Free: https://fontawesome.com/license/free -->';
404 echo ' <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" stroke="currentColor">';
405 echo ' <path d="M64 464l48 0 0 48-48 0c-35.3 0-64-28.7-64-64L0 64C0 28.7 28.7 0 64 0L229.5 0c17 0 33.3 6.7 45.3 18.7l90.5 90.5c12 12 18.7 28.3 18.7 45.3L384 304l-48 0 0-144-80 0c-17.7 0-32-14.3-32-32l0-80L64 48c-8.8 0-16 7.2-16 16l0 384c0 8.8 7.2 16 16 16zM176 352l32 0c30.9 0 56 25.1 56 56s-25.1 56-56 56l-16 0 0 32c0 8.8-7.2 16-16 16s-16-7.2-16-16l0-48 0-80c0-8.8 7.2-16 16-16zm32 80c13.3 0 24-10.7 24-24s-10.7-24-24-24l-16 0 0 48 16 0zm96-80l32 0c26.5 0 48 21.5 48 48l0 64c0 26.5-21.5 48-48 48l-32 0c-8.8 0-16-7.2-16-16l0-128c0-8.8 7.2-16 16-16zm32 128c8.8 0 16-7.2 16-16l0-64c0-8.8-7.2-16-16-16l-16 0 0 96 16 0zm80-112c0-8.8 7.2-16 16-16l48 0c8.8 0 16 7.2 16 16s-7.2 16-16 16l-32 0 0 32 32 0c8.8 0 16 7.2 16 16s-7.2 16-16 16l-32 0 0 48c0 8.8-7.2 16-16 16s-16-7.2-16-16l0-64 0-64z"></path>';
406 echo ' </svg>';
407 echo ' </button>';
408 }
409
410 // Word Upload Button - wrapped in conditional using current_options
411 $show_word_button = isset($current_options['show_word_upload_button']) ? $current_options['show_word_upload_button'] : 'on';
412 if ($show_word_button === 'on') {
413 echo ' <input type="file" id="word-upload-' . esc_attr($bot_id) . '" class="word-upload" accept=".docx" style="display: none;">';
414 echo ' <button id="word-upload-btn-' . esc_attr($bot_id) . '" class="toolbar-btn word-upload-btn" title="' . esc_attr__('Upload Word Document', 'mxchat') . '">';
415 echo ' <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 384 512" stroke="currentColor">';
416 echo ' <path d="M48 448L48 64c0-8.8 7.2-16 16-16l160 0 0 80c0 17.7 14.3 32 32 32l80 0 0 288c0 8.8-7.2 16-16 16L64 464c-8.8 0-16-7.2-16-16zM64 0C28.7 0 0 28.7 0 64L0 448c0 35.3 28.7 64 64 64l256 0c35.3 0 64-28.7 64-64l0-293.5c0-17-6.7-33.3-18.7-45.3L274.7 18.7C262.7 6.7 246.5 0 229.5 0L64 0zm55 241.1c-3.8-12.7-17.2-19.9-29.9-16.1s-19.9 17.2-16.1 29.9l48 160c3 10.2 12.4 17.1 23 17.1s19.9-7 23-17.1l25-83.4 25 83.4c3 10.2 12.4 17.1 23 17.1s19.9-7 23-17.1l48-160c3.8-12.7-3.4-26.1-16.1-29.9s-26.1 3.4-29.9 16.1l-25 83.4-25-83.4c-3-10.2-12.4-17.1-23-17.1s-19.9 7-23 17.1l-25 83.4-25-83.4z"/></svg>';
417 echo ' </button>';
418 }
419
420 // File containers
421 echo ' <div id="active-pdf-container-' . esc_attr($bot_id) . '" class="active-pdf-container" style="display: none;">';
422 echo ' <span id="active-pdf-name-' . esc_attr($bot_id) . '" class="active-pdf-name"></span>';
423 echo ' <button id="remove-pdf-btn-' . esc_attr($bot_id) . '" class="remove-pdf-btn" title="' . esc_attr__('Remove PDF', 'mxchat') . '">';
424 echo ' <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="12" height="12" fill="none" stroke="currentColor" stroke-width="2">';
425 echo ' <line x1="18" y1="6" x2="6" y2="18"></line>';
426 echo ' <line x1="6" y1="6" x2="18" y2="18"></line>';
427 echo ' </svg>';
428 echo ' </button>';
429 echo ' </div>';
430
431 echo ' <div id="active-word-container-' . esc_attr($bot_id) . '" class="active-word-container" style="display: none;">';
432 echo ' <span id="active-word-name-' . esc_attr($bot_id) . '" class="active-word-name"></span>';
433 echo ' <button id="remove-word-btn-' . esc_attr($bot_id) . '" class="remove-word-btn" title="' . esc_attr__('Remove Word Document', 'mxchat') . '">';
434 echo ' <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="12" height="12" fill="none" stroke="currentColor" stroke-width="2">';
435 echo ' <line x1="18" y1="6" x2="6" y2="18"></line>';
436 echo ' <line x1="6" y1="6" x2="18" y2="18"></line>';
437 echo ' </svg>';
438 echo ' </button>';
439 echo ' </div>';
440
441 // Perplexity Button
442 if (apply_filters('mxchat_perplexity_should_show_logo', true)) {
443 echo ' <button id="perplexity-search-btn-' . esc_attr($bot_id) . '" class="toolbar-btn perplexity-search-btn" title="' . esc_attr__('Search with Perplexity', 'mxchat-perplexity') . '">';
444 echo ' <svg fill="currentColor" height="1em" viewBox="0 0 24 24" width="1em" xmlns="http://www.w3.org/2000/svg">';
445 echo ' <path d="M19.785 0v7.272H22.5V17.62h-2.935V24l-7.037-6.194v6.145h-1.091v-6.152L4.392 24v-6.465H1.5V7.188h2.884V0l7.053 6.494V.19h1.09v6.49L19.786 0zm-7.257 9.044v7.319l5.946 5.234V14.44l-5.946-5.397zm-1.099-.08l-5.946 5.398v7.235l5.946-5.234V8.965zm8.136 7.58h1.844V8.349H13.46l6.105 5.54v2.655zm-8.982-8.28H2.59v8.195h1.8v-2.576l6.192-5.62zM5.475 2.476v4.71h5.115l-5.115-4.71zm13.219 0l-5.115 4.71h5.115v-4.71z"></path>';
446 echo ' </svg>';
447 echo ' </button>';
448 }
449
450
451 // Image Analysis Button - hidden by default, controlled by MxChat Vision add-on
452 echo ' <input type="file" id="image-upload-' . esc_attr($bot_id) . '" class="image-upload" accept="image/*" style="display: none;" multiple>';
453 echo ' <button id="image-upload-btn-' . esc_attr($bot_id) . '" class="toolbar-btn image-upload-btn" title="' . esc_attr__('Upload Image for Analysis', 'mxchat') . '" style="display: none;">';
454 echo ' <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="fill: none !important;">';
455 echo ' <path d="M14.5 4h-5L7 7H4a2 2 0 0 0-2 2v9a2 2 0 0 0 2 2h16a2 2 0 0 0 2-2V9a2 2 0 0 0-2-2h-3l-2.5-3z" style="fill: none !important;"/>';
456 echo ' <circle cx="12" cy="13" r="3" style="fill: none !important;"/>';
457 echo ' </svg>';
458 echo ' </button>';
459
460
461 echo ' </div>';
462
463 echo ' <div class="chatbot-footer">';
464
465 // Output the privacy notice if enabled
466 if ($privacy_toggle && !empty($privacy_text)) {
467 echo '<p class="privacy-notice">' . $privacy_text . '</p>';
468 }
469
470 echo ' </div>';
471 echo ' </div>';
472 echo ' </div>';
473 echo '</div>';
474
475 if ($is_floating) {
476 echo '</div>';
477
478 if (!empty($pre_chat_message) && !get_transient($transient_key)) {
479 echo '<div id="pre-chat-message-' . esc_attr($bot_id) . '" class="pre-chat-message">';
480 echo esc_html($pre_chat_message);
481 echo '<button class="close-pre-chat-message" aria-label="' . esc_attr__('Close', 'mxchat') . '">&times;</button>';
482 echo '</div>';
483 }
484
485 echo '<div class="floating-chatbot-button ' . esc_attr($visibility_class) . '" id="floating-chatbot-button-' . esc_attr($bot_id) . '"' . ($skip_inline_colors ? '' : ' style="background: ' . esc_attr($chatbot_background_color) . '; color: ' . esc_attr($send_button_font_color) . ';"') . '>';
486 echo '<div id="chat-notification-badge-' . esc_attr($bot_id) . '" class="chat-notification-badge" style="display: none; position: absolute; top: -8px; right: -8px; background-color: #ff4444; color: white; border-radius: 50%; padding: 4px 8px; font-size: 12px; font-weight: bold; z-index: 10001;">1</div>';
487
488 if (!empty($custom_icon)) {
489 echo '<img src="' . $custom_icon . '" alt="' . esc_attr__('Chatbot Icon', 'mxchat') . '" style="height: 48px; width: 48px; object-fit: contain;" />';
490 } else {
491 $widget_icon_style = 'height: 48px; width: 48px;';
492 if (!$skip_inline_colors) {
493 $widget_icon_style .= ' fill: ' . esc_attr($icon_color) . ';';
494 }
495 echo '<svg id="widget_icon_10" style="' . $widget_icon_style . '" viewBox="0 0 1120 1120" fill="none" xmlns="http://www.w3.org/2000/svg">';
496 echo ' <path fill-rule="evenodd" clip-rule="evenodd" d="M252 434C252 372.144 302.144 322 364 322H770C831.856 322 882 372.144 882 434V614.459L804.595 585.816C802.551 585.06 800.94 583.449 800.184 581.405L763.003 480.924C760.597 474.424 751.403 474.424 748.997 480.924L711.816 581.405C711.06 583.449 709.449 585.06 707.405 585.816L606.924 622.997C600.424 625.403 600.424 634.597 606.924 637.003L707.405 674.184C709.449 674.94 711.06 676.551 711.816 678.595L740.459 756H629.927C629.648 756.476 629.337 756.945 628.993 757.404L578.197 825.082C572.597 832.543 561.403 832.543 555.803 825.082L505.007 757.404C504.663 756.945 504.352 756.476 504.073 756H364C302.144 756 252 705.856 252 644V434ZM633.501 471.462C632.299 468.212 627.701 468.212 626.499 471.462L619.252 491.046C618.874 492.068 618.068 492.874 617.046 493.252L597.462 500.499C594.212 501.701 594.212 506.299 597.462 507.501L617.046 514.748C618.068 515.126 618.874 515.932 619.252 516.954L626.499 536.538C627.701 539.788 632.299 539.788 633.501 536.538L640.748 516.954C641.126 515.932 641.932 515.126 642.954 514.748L662.538 507.501C665.788 506.299 665.788 501.701 662.538 500.499L642.954 493.252C641.932 492.874 641.126 492.068 640.748 491.046L633.501 471.462Z" ></path>';
497 echo ' <path d="M771.545 755.99C832.175 755.17 881.17 706.175 881.99 645.545L804.595 674.184C802.551 674.94 800.94 676.551 800.184 678.595L771.545 755.99Z" ></path>';
498 echo '</svg>';
499 }
500 echo '</div>';
501 }
502
503 return ob_get_clean();
504 }
505
506 /**
507 * Get bot-specific options for multi-bot functionality
508 * Falls back to default options if bot_id is 'default' or multi-bot add-on is not active
509 */
510 private function get_bot_options($bot_id = 'default') {
511 // If default bot or multi-bot add-on not active, return empty (use default options)
512 if ($bot_id === 'default' || !class_exists('MxChat_Multi_Bot_Manager')) {
513 return array();
514 }
515
516 //Hook for multi-bot add-on to provide bot-specific options
517 $bot_options = apply_filters('mxchat_get_bot_options', array(), $bot_id);
518
519 return is_array($bot_options) ? $bot_options : array();
520 }
521
522 /**
523 * Get bot-specific Pinecone configuration
524 * Used in the knowledge retrieval functions
525 */
526 private function get_bot_pinecone_config($bot_id = 'default') {
527 // If default bot or multi-bot add-on not active, use default Pinecone config
528 if ($bot_id === 'default' || !class_exists('MxChat_Multi_Bot_Manager')) {
529 $addon_options = get_option('mxchat_pinecone_addon_options', array());
530 return array(
531 'use_pinecone' => (isset($addon_options['mxchat_use_pinecone']) && $addon_options['mxchat_use_pinecone'] === '1'),
532 'api_key' => $addon_options['mxchat_pinecone_api_key'] ?? '',
533 'host' => $addon_options['mxchat_pinecone_host'] ?? '',
534 'namespace' => $addon_options['mxchat_pinecone_namespace'] ?? ''
535 );
536 }
537
538 // Hook for multi-bot add-on to provide bot-specific Pinecone config
539 $bot_pinecone_config = apply_filters('mxchat_get_bot_pinecone_config', array(), $bot_id);
540
541 return is_array($bot_pinecone_config) ? $bot_pinecone_config : array();
542 }
543
544
545 private function determine_email_collection_state() {
546 // Get session ID
547 $session_id = 'mxchat_chat_' . wp_generate_uuid4(); // You'll need to use your actual session generation logic
548
549 // Check if user is logged in first
550 if (is_user_logged_in()) {
551 $current_user = wp_get_current_user();
552 return [
553 'show_email_form' => false,
554 'user_email' => $current_user->user_email,
555 'user_name' => $current_user->display_name ?: $current_user->first_name ?: ''
556 ];
557 }
558
559 // Check stored email for session
560 $stored_email = get_option("mxchat_email_{$session_id}", '');
561 $stored_name = get_option("mxchat_name_{$session_id}", '');
562
563 // Check if name is required
564 $name_field_enabled = isset($this->options['enable_name_field']) &&
565 ($this->options['enable_name_field'] === '1' || $this->options['enable_name_field'] === 'on');
566
567 $has_required_info = !empty($stored_email);
568 if ($name_field_enabled) {
569 $has_required_info = $has_required_info && !empty($stored_name);
570 }
571
572 return [
573 'show_email_form' => !$has_required_info,
574 'user_email' => $stored_email,
575 'user_name' => $stored_name
576 ];
577 }
578
579
580 /**
581 * NEW: Determine if and which chatbot should be displayed
582 */
583 private function get_display_bot() {
584 // Get page-specific settings from meta box
585 $page_setting = $this->get_page_bot_setting();
586
587 // Get global settings - FIXED: Check for 'on' instead of 'on'
588 $global_autoshow = isset($this->options['append_to_body']) && $this->options['append_to_body'] === 'on';
589 $global_default_bot = isset($this->options['default_bot']) ? $this->options['default_bot'] : 'default';
590
591 // If page specifically hides chatbot, don't show anything
592 if ($page_setting && $page_setting['action'] === 'hide') {
593 return false;
594 }
595
596 // If page specifies a specific bot, use that
597 if ($page_setting && $page_setting['action'] === 'show') {
598 return $page_setting['bot_id'];
599 }
600
601 // Page setting is 'global' or no page setting exists
602 // Check global auto-show setting
603 if ($global_autoshow) {
604 // Check post type visibility settings
605 if (!$this->should_show_on_current_post_type()) {
606 return false;
607 }
608
609 // Global auto-show is enabled, return the default bot
610 return $global_default_bot;
611 }
612
613 // Global auto-show is disabled and no page-specific bot selected
614 // Don't show chatbot (user should use shortcodes)
615 return false;
616 }
617
618 /**
619 * Check if chatbot should be shown on the current post type
620 */
621 private function should_show_on_current_post_type() {
622 // Get visibility settings
623 $mode = isset($this->options['post_type_visibility_mode']) ? $this->options['post_type_visibility_mode'] : 'all';
624 $list = isset($this->options['post_type_visibility_list']) ? $this->options['post_type_visibility_list'] : array();
625
626 // Ensure list is an array
627 if (!is_array($list)) {
628 $list = array();
629 }
630
631 // If mode is 'all', show on all post types
632 if ($mode === 'all') {
633 return true;
634 }
635
636 // Get current post type
637 $current_post_type = $this->get_current_post_type();
638
639 // If we can't determine post type, default to showing
640 if (empty($current_post_type)) {
641 return true;
642 }
643
644 // Check based on mode
645 if ($mode === 'include') {
646 // Only show on selected post types
647 return in_array($current_post_type, $list);
648 } elseif ($mode === 'exclude') {
649 // Hide on selected post types
650 return !in_array($current_post_type, $list);
651 }
652
653 // Default to showing
654 return true;
655 }
656
657 /**
658 * Get the current post type
659 */
660 private function get_current_post_type() {
661 // Try to get from queried object first
662 $queried_object = get_queried_object();
663
664 if ($queried_object instanceof WP_Post) {
665 return $queried_object->post_type;
666 }
667
668 // Try get_post_type()
669 $post_type = get_post_type();
670 if ($post_type) {
671 return $post_type;
672 }
673
674 // Check if we're on an archive
675 if (is_post_type_archive()) {
676 return get_query_var('post_type');
677 }
678
679 // Check common archive types
680 if (is_home() || is_single()) {
681 return 'post';
682 }
683
684 if (is_page()) {
685 return 'page';
686 }
687
688 return '';
689 }
690
691 /**
692 * NEW: Get page-specific bot setting
693 */
694 private function get_page_bot_setting($post_id = null) {
695 if (!$post_id) {
696 $post_id = get_the_ID();
697 }
698
699 if (!$post_id) {
700 return null;
701 }
702
703 // Check if chatbot is hidden on this page
704 $hide_chatbot = get_post_meta($post_id, '_mxchat_hide_chatbot', true);
705 if ($hide_chatbot === '1') {
706 return array('action' => 'hide');
707 }
708
709 // Check if specific bot is selected
710 $selected_bot = get_post_meta($post_id, '_mxchat_selected_bot', true);
711 if (!empty($selected_bot)) {
712 return array('action' => 'show', 'bot_id' => $selected_bot);
713 }
714
715 // Use global setting
716 return array('action' => 'global');
717 }
718
719 /**
720 * NEW: Determine which bot to use for shortcode
721 */
722 private function determine_bot_for_shortcode($shortcode_bot_id) {
723 // If bot_id explicitly provided in shortcode, use that
724 if (!empty($shortcode_bot_id)) {
725 return $shortcode_bot_id;
726 }
727
728 // No bot_id in shortcode, check page setting
729 $page_setting = $this->get_page_bot_setting();
730 if ($page_setting && $page_setting['action'] === 'show') {
731 return $page_setting['bot_id'];
732 }
733
734 // Fall back to default
735 return 'default';
736 }
737
738 /**
739 * NEW: Helper to check if auto-append is enabled globally
740 */
741 private function is_auto_append_enabled() {
742 return isset($this->options['append_to_body']) && $this->options['append_to_body'] === 'on';
743 }
744
745 /**
746 * UPDATED: Debug function with new context info
747 */
748 public function debug_display_logic() {
749 if (current_user_can('manage_options') && isset($_GET['mxchat_debug'])) {
750 $bot_to_show = $this->get_display_bot();
751 $page_setting = $this->get_page_bot_setting();
752 $global_autoshow = isset($this->options['append_to_body']) && $this->options['append_to_body'] === 'on';
753 $hide_auto = $this->should_hide_chatbot('auto');
754
755 echo '<div style="position: fixed; top: 50px; right: 20px; background: white; border: 2px solid red; padding: 10px; z-index: 9999; max-width: 300px; font-size: 12px;">';
756 echo '<h4 style="margin: 0 0 10px 0;">MxChat Debug Info</h4>';
757 echo '<p><strong>Raw append_to_body value:</strong> "' . ($this->options['append_to_body'] ?? 'NOT SET') . '"</p>';
758 echo '<p><strong>Page Setting:</strong><br><pre>' . print_r($page_setting, true) . '</pre></p>';
759 echo '<p><strong>Global Auto-show:</strong> ' . ($global_autoshow ? 'ON' : 'OFF') . '</p>';
760 echo '<p><strong>Hide Auto-Append:</strong> ' . ($hide_auto ? 'YES' : 'NO') . '</p>';
761 echo '<p><strong>Bot to Show:</strong> ' . ($bot_to_show === false ? 'NONE' : $bot_to_show) . '</p>';
762 echo '<p><strong>Shortcodes:</strong> floating="no" always works</p>';
763 echo '<p><small>Add ?mxchat_debug=1 to URL to see this</small></p>';
764 echo '</div>';
765 }
766 }
767
768 /**
769 * NEW: Helper method to get available bots (for admin notices, etc.)
770 */
771 private function get_available_bots() {
772 $bots = array('default' => __('Default Bot', 'mxchat'));
773
774 // Check if multi-bot addon is active
775 if (class_exists('MxChat_Multi_Bot_Manager')) {
776 $multi_bot_manager = MxChat_Multi_Bot_Core_Manager::get_instance();
777 $available_bots = $multi_bot_manager->get_available_bots();
778
779 // Add the available bots
780 foreach ($available_bots as $bot_id => $bot_name) {
781 $bots[$bot_id] = $bot_name;
782 }
783 }
784
785 return $bots;
786 }
787
788
789
790 }
791 ?>