PluginProbe
MxChat – AI Chatbot & Content Generation for WordPress / 2.4.6
MxChat – AI Chatbot & Content Generation for WordPress v2.4.6
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 2.4.6, at includes/class-mxchat-public.php

692 lines 38.6 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 // Only load for admin users or if testing parameter is present
27 if (current_user_can('administrator') || isset($_GET['mxchat_test'])) {
28
29 // Get plugin URL for assets
30 $plugin_url = plugin_dir_url(dirname(__FILE__));
31
32 // Enqueue test panel CSS
33 wp_enqueue_style(
34 'mxchat-test-panel',
35 $plugin_url . 'css/test-panel.css',
36 array(),
37 '1.0.0'
38 );
39
40 // Enqueue test panel JS
41 wp_enqueue_script(
42 'mxchat-test-panel',
43 $plugin_url . 'js/test-panel.js',
44 array('jquery'),
45 '1.0.0',
46 true
47 );
48
49 // Pass data to JavaScript
50 wp_localize_script('mxchat-test-panel', 'mxchatTestData', array(
51 'ajaxUrl' => admin_url('admin-ajax.php'),
52 'nonce' => wp_create_nonce('mxchat_test_nonce'),
53 'isAdmin' => current_user_can('administrator'),
54 'testingEnabled' => true
55 ));
56
57 // Add JavaScript flag to enable testing
58 add_action('wp_footer', array($this, 'add_testing_flag'));
59 }
60 }
61
62 /**
63 * Add JavaScript flag to enable testing panel
64 */
65 public function add_testing_flag() {
66 echo '<script>window.mxchatTestingEnabled = true;</script>';
67 }
68
69 /**
70 * Check if testing mode should be enabled
71 */
72 private function is_testing_mode_enabled() {
73 return (current_user_can('administrator') || isset($_GET['mxchat_test']));
74 }
75
76 /**
77 * UPDATED: Enhanced should_hide_chatbot method - only blocks auto-append, not shortcodes
78 */
79 private function should_hide_chatbot($context = 'auto') {
80 global $post;
81
82 if (!$post) {
83 return false;
84 }
85
86 $hide_chatbot = get_post_meta($post->ID, '_mxchat_hide_chatbot', true);
87
88 // Only hide if it's the auto-append context (floating="yes" from global setting)
89 // Allow shortcodes to work regardless of this setting
90 if ($context === 'auto' && $hide_chatbot === '1') {
91 return true;
92 }
93
94 return false;
95 }
96
97 /**
98 * UPDATED: Enhanced append_chatbot_to_body method with context
99 */
100 public function append_chatbot_to_body() {
101 // Only run on public pages
102 if (is_admin() || wp_doing_ajax()) {
103 return;
104 }
105
106 // Check if auto-append chatbot should be hidden on this page
107 if ($this->should_hide_chatbot('auto')) {
108 return; // Don't show auto-appended chatbot
109 }
110
111 // Get the bot that should be displayed using new logic
112 $bot_to_show = $this->get_display_bot();
113
114 // Don't show chatbot if determination is false
115 if ($bot_to_show === false) {
116 return;
117 }
118
119 // Handle consent for display
120 $consent_category = 'marketing';
121 $has_consent = true;
122
123 if (
124 isset($this->options['complianz_toggle']) &&
125 $this->options['complianz_toggle'] === 'on' &&
126 function_exists('cmplz_has_consent')
127 ) {
128 $has_consent = cmplz_has_consent($consent_category);
129 }
130
131 // Display the appropriate chatbot (always floating for auto-append)
132 if ($bot_to_show && $bot_to_show !== 'default') {
133 // Show specific bot
134 echo do_shortcode('[mxchat_chatbot floating="yes" bot_id="' . esc_attr($bot_to_show) . '" has_consent="' . ($has_consent ? 'yes' : 'no') . '"]');
135 } else {
136 // Show default bot
137 echo do_shortcode('[mxchat_chatbot floating="yes" has_consent="' . ($has_consent ? 'yes' : 'no') . '"]');
138 }
139 }
140
141 private function mxchat_get_user_identifier() {
142 return sanitize_text_field($_SERVER['REMOTE_ADDR']);
143 }
144
145 /**
146 * UPDATED: Enhanced shortcode with context-aware hiding
147 */
148 public function render_chatbot_shortcode($atts) {
149 // UPDATED: Add bot_id parameter support and improve logic
150 $attributes = shortcode_atts(array(
151 'floating' => 'yes',
152 'has_consent' => 'yes',
153 'bot_id' => '' // Support for multi-bot functionality - empty means auto-detect
154 ), $atts);
155
156 // Determine which bot to use
157 $bot_id = $this->determine_bot_for_shortcode($attributes['bot_id']);
158
159 // UPDATED: Only check hiding for floating shortcodes that could conflict with auto-append
160 // Non-floating shortcodes should always work
161 if ($attributes['floating'] === 'yes') {
162 // For floating shortcodes, check if auto-append is hidden
163 // This prevents duplicate floating chatbots
164 if ($this->should_hide_chatbot('auto') && $this->is_auto_append_enabled()) {
165 // If auto-append is enabled but hidden on this page,
166 // allow the floating shortcode to work (user is overriding)
167 // But if auto-append is disabled globally, also allow shortcode
168 }
169 }
170
171 // Non-floating shortcodes (floating="no") should NEVER be blocked by the hide setting
172 // This allows embedded chatbots even when floating is hidden
173
174 $is_floating = $attributes['floating'] === 'yes';
175 $bot_id = sanitize_key($bot_id); // Sanitize bot ID
176
177 // Rest of your existing shortcode rendering logic continues unchanged...
178 // [All the existing HTML generation code remains the same]
179
180 // Get bot-specific options if multi-bot add-on is active
181 $bot_options = $this->get_bot_options($bot_id);
182
183 // Use bot-specific options or fall back to default options
184 $current_options = !empty($bot_options) ? $bot_options : $this->options;
185
186 // [Rest of your existing rendering code stays exactly the same]
187 // Just remove the old should_hide_chatbot() check from the beginning
188
189 // Check for Complianz consent if the toggle is enabled
190 $initial_visibility = 'hidden';
191 $additional_class = '';
192
193 if (isset($current_options['complianz_toggle']) && $current_options['complianz_toggle'] === 'on') {
194 $additional_class = ' no-consent';
195 }
196 $visibility_class = $initial_visibility . $additional_class;
197
198 $theme_options = get_option('mxchat_theme_options', array());
199 $custom_send_image = isset($theme_options['custom_send_button_image']) ? esc_url($theme_options['custom_send_button_image']) : '';
200 $send_width = isset($theme_options['send_button_width']) ? intval($theme_options['send_button_width']) : 24;
201 $send_height = isset($theme_options['send_button_height']) ? intval($theme_options['send_button_height']) : 24;
202 $send_rotation = isset($theme_options['send_button_rotation']) ? intval($theme_options['send_button_rotation']) : 0;
203
204 // UPDATED: Use current_options instead of $this->options throughout
205 $bg_color = $current_options['chatbot_background_color'] ?? '#fff';
206 $user_message_bg_color = $current_options['user_message_bg_color'] ?? '#fff';
207 $user_message_font_color = $current_options['user_message_font_color'] ?? '#212121';
208 $bot_message_bg_color = $current_options['bot_message_bg_color'] ?? '#212121';
209 $bot_message_font_color = $current_options['bot_message_font_color'] ?? '#fff';
210 $top_bar_bg_color = $current_options['top_bar_bg_color'] ?? '#212121';
211 $send_button_font_color = $current_options['send_button_font_color'] ?? '#212121';
212 $intro_message = $current_options['intro_message'] ?? esc_html__('Hello! How can I assist you today?', 'mxchat');
213 $top_bar_title = $current_options['top_bar_title'] ?? esc_html__('MxChat: Basic', 'mxchat');
214 $chatbot_background_color = $current_options['chatbot_background_color'] ?? '#212121';
215 $icon_color = $current_options['icon_color'] ?? '#fff';
216 $chat_input_font_color = $current_options['chat_input_font_color'] ?? '#212121';
217 $close_button_color = $current_options['close_button_color'] ?? '#fff';
218 $chatbot_bg_color = $current_options['chatbot_bg_color'] ?? '#fff';
219 $pre_chat_message = isset($current_options['pre_chat_message']) ? sanitize_text_field(trim($current_options['pre_chat_message'])) : '';
220 $user_id = sanitize_key($this->mxchat_get_user_identifier());
221 $email_state = $this->determine_email_collection_state();
222 $show_email_form = $email_state['show_email_form'];
223 $user_email = $email_state['user_email'] ?? '';
224 $user_name = $email_state['user_name'] ?? '';
225 $transient_key = 'mxchat_pre_chat_message_dismissed_' . $user_id;
226 $input_copy = isset($current_options['input_copy']) ? esc_attr($current_options['input_copy']) : esc_attr__('How can I assist?', 'mxchat');
227 $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');
228 $mode_indicator_bg_color = $current_options['mode_indicator_bg_color'] ?? '#212121';
229 $mode_indicator_font_color = $current_options['mode_indicator_font_color'] ?? '#fff';
230 $quick_questions_toggle_color = $current_options['quick_questions_toggle_color'] ?? '#212121';
231
232 $privacy_toggle = isset($current_options['privacy_toggle']) && $current_options['privacy_toggle'] === 'on';
233 $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'));
234
235 $popular_question_1 = isset($current_options['popular_question_1']) ? esc_html($current_options['popular_question_1']) : '';
236 $popular_question_2 = isset($current_options['popular_question_2']) ? esc_html($current_options['popular_question_2']) : '';
237 $popular_question_3 = isset($current_options['popular_question_3']) ? esc_html($current_options['popular_question_3']) : '';
238 $additional_questions = isset($current_options['additional_popular_questions']) ? $current_options['additional_popular_questions'] : [];
239 $custom_icon = isset($current_options['custom_icon']) ? esc_url($current_options['custom_icon']) : '';
240 $title_icon = isset($current_options['title_icon']) ? esc_url($current_options['title_icon']) : '';
241 $ai_agent_text = isset($current_options['ai_agent_text']) ? esc_html($current_options['ai_agent_text']) : esc_html__('AI Agent', 'mxchat');
242
243 $live_agent_message_bg_color = $current_options['live_agent_message_bg_color'] ?? '#212121';
244 $live_agent_message_font_color = $current_options['live_agent_message_font_color'] ?? '#fff';
245 $enable_email_block = isset($current_options['enable_email_block']) &&
246 ($current_options['enable_email_block'] === '1' || $current_options['enable_email_block'] === 'on');
247
248 // Add name field variables
249 $enable_name_field = isset($current_options['enable_name_field']) &&
250 ($current_options['enable_name_field'] === '1' || $current_options['enable_name_field'] === 'on');
251 $name_field_placeholder = isset($current_options['name_field_placeholder']) ?
252 esc_attr($current_options['name_field_placeholder']) :
253 esc_attr__('Enter your name', 'mxchat');
254
255 ob_start();
256
257 // Check if floating attribute is set to 'yes' and wrap accordingly
258 if ($is_floating) {
259 echo '<div id="floating-chatbot" class="' . $initial_visibility . $additional_class . '">';
260 }
261
262 // Add bot_id to the chatbot wrapper as a data attribute
263 echo '<div id="mxchat-chatbot-wrapper" data-bot-id="' . esc_attr($bot_id) . '">';
264
265 echo ' <div class="chatbot-top-bar" id="exit-chat-button" style="background: ' . esc_attr($top_bar_bg_color) . ';">';
266 echo ' <div class="chatbot-title-container">';
267 echo ' <div class="chatbot-title-group">';
268 if (!empty($title_icon)) {
269 echo ' <img src="' . esc_url($title_icon) . '" alt="" class="chatbot-title-icon">';
270 }
271 echo ' <p class="chatbot-title" style="color: ' . esc_attr($close_button_color) . ';">' . esc_html($top_bar_title) . '</p>';
272 echo ' </div>';
273 echo '<span class="chat-mode-indicator" id="chat-mode-indicator" data-ai-text="' . $ai_agent_text . '" style="color: ' . esc_attr($mode_indicator_font_color) . '; background-color: ' . esc_attr($mode_indicator_bg_color) . ';">' . $ai_agent_text . '</span>';
274 echo ' </div>';
275 echo ' <button class="exit-chat" type="button" aria-label="' . esc_attr__('Minimize', 'mxchat') . '" style="color: ' . esc_attr($close_button_color) . ';">';
276 echo ' <svg xmlns="http://www.w3.org/2000/svg" height="24" viewBox="0 0 24 24" width="24" id="ic-minimize" style="fill: ' . esc_attr($close_button_color) . ';">';
277 echo ' <path d="M0 0h24v24H0z" fill="none"></path>';
278 echo ' <path d="M11.67 3.87L9.9 2.1 0 12l9.9 9.9 1.77-1.77L3.54 12z"></path>';
279 echo ' </svg>';
280 echo ' <span>' . esc_html__('Minimize', 'mxchat') . '</span>';
281 echo ' </button>';
282 echo ' </div>';
283
284 // 3b) Main chatbot container
285 echo ' <div id="mxchat-chatbot" style="background-color: ' . esc_attr($chatbot_bg_color) . ';">';
286
287 if ($enable_email_block) {
288 echo '<div id="email-blocker" class="email-blocker" style="' . ($show_email_form ? '' : 'display: none;') . '">';
289 echo ' <div class="email-blocker-header">';
290
291 $header_html = isset($current_options['email_blocker_header_content'])
292 ? $current_options['email_blocker_header_content']
293 : '';
294 echo wp_kses_post($header_html);
295
296 echo ' </div>';
297 echo ' <form id="email-collection-form" method="POST" action="">';
298
299 // Add name field if enabled
300 if ($enable_name_field) {
301 echo ' <label for="user-name" class="sr-only mxchat-name-label">' . esc_html__('Name', 'mxchat') . '</label>';
302 echo ' <input type="text" id="user-name" name="user_name" class="mxchat-name-input" required placeholder="' . $name_field_placeholder . '" />';
303 }
304
305 echo ' <label for="user-email" class="sr-only">' . esc_html__('Email Address', 'mxchat') . '</label>';
306 echo ' <input type="email" id="user-email" name="user_email" required placeholder="' . esc_attr__('Enter your email address', 'mxchat') . '" />';
307 echo '<button type="submit" id="email-submit-button">';
308 $button_text = isset($current_options['email_blocker_button_text'])
309 ? $current_options['email_blocker_button_text']
310 : esc_html__('Start Chat', 'mxchat');
311 echo esc_html($button_text);
312 echo '</button>';
313 echo ' </form>';
314 echo '</div>';
315 }
316
317 echo ' <div id="chat-container" style="' . ($enable_email_block && $show_email_form ? 'display: none;' : '') . '">';
318 echo ' <div id="chat-box">';
319 echo ' <div class="bot-message" style="background: ' . esc_attr($bot_message_bg_color) . ';">';
320 echo ' <div dir="auto" style="color: ' . esc_attr($bot_message_font_color) . ';">';
321 echo wp_kses_post($intro_message);
322 echo ' </div>';
323 echo ' </div>';
324 echo ' </div>'; // end #chat-box
325
326
327 // Replace the existing popular questions section with this:
328 echo ' <div id="mxchat-popular-questions">';
329 echo ' <div class="mxchat-popular-questions-container">';
330
331 // Collapse button (down arrow) - shows when open, centered at top
332 echo ' <button class="questions-collapse-btn" aria-label="' . esc_attr__('Hide Quick Questions', 'mxchat') . '">';
333 echo ' <svg width="25" height="25" viewBox="0 0 24 24" fill="none" stroke="' . esc_attr($quick_questions_toggle_color) . '" stroke-width="2">';
334 echo ' <polyline points="6,9 12,15 18,9"></polyline>';
335 echo ' </svg>';
336 echo ' </button>';
337
338 // Expand button (up arrow) - shows when collapsed
339 echo ' <button class="questions-toggle-btn" aria-label="' . esc_attr__('Show Quick Questions', 'mxchat') . '">';
340 echo ' <svg width="25" height="25" viewBox="0 0 24 24" fill="none" stroke="' . esc_attr($quick_questions_toggle_color) . '" stroke-width="2">';
341 echo ' <polyline points="18,15 12,9 6,15"></polyline>';
342 echo ' </svg>';
343 echo ' </button>';
344
345 if (!empty($popular_question_1)) {
346 echo '<button class="mxchat-popular-question" dir="auto">' . esc_html($popular_question_1) . '</button>';
347 }
348 if (!empty($popular_question_2)) {
349 echo '<button class="mxchat-popular-question" dir="auto">' . esc_html($popular_question_2) . '</button>';
350 }
351 if (!empty($popular_question_3)) {
352 echo '<button class="mxchat-popular-question" dir="auto">' . esc_html($popular_question_3) . '</button>';
353 }
354
355 if (!empty($additional_questions) && is_array($additional_questions)) {
356 foreach ($additional_questions as $index => $question) {
357 if (!empty($question)) {
358 echo '<button class="mxchat-popular-question" dir="auto">' . esc_html($question) . '</button>';
359 }
360 }
361 }
362
363 echo ' </div>';
364 echo ' </div>';
365
366 echo ' <div id="input-container">';
367 echo ' <textarea id="chat-input" dir="auto" placeholder="' . esc_attr($input_copy) . '" style="color: ' . esc_attr($chat_input_font_color) . ';"></textarea>';
368 echo ' <button id="send-button">';
369 if (!empty($custom_send_image)) {
370 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);" />';
371 } else {
372 echo ' <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" style="fill: ' . esc_attr($send_button_font_color) . '; width: ' . intval($send_width) . 'px; height: ' . intval($send_height) . 'px; transform: rotate(' . intval($send_rotation) . 'deg);">';
373 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>';
374 echo ' </svg>';
375 }
376 echo ' </button>';
377 echo ' </div>';
378
379 echo ' <div class="chat-toolbar">';
380
381 // PDF Upload Button - wrapped in conditional using current_options
382 $show_pdf_button = isset($current_options['show_pdf_upload_button']) ? $current_options['show_pdf_upload_button'] : 'on';
383 if ($show_pdf_button === 'on') {
384 echo ' <input type="file" id="pdf-upload" accept=".pdf" style="display: none;">';
385 echo ' <button id="pdf-upload-btn" class="toolbar-btn" title="' . esc_attr__('Upload PDF', 'mxchat') . '">';
386 echo ' <!-- Icon from Font Awesome Free: https://fontawesome.com/license/free -->';
387 echo ' <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" stroke="currentColor">';
388 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>';
389 echo ' </svg>';
390 echo ' </button>';
391 }
392
393 // Word Upload Button - wrapped in conditional using current_options
394 $show_word_button = isset($current_options['show_word_upload_button']) ? $current_options['show_word_upload_button'] : 'on';
395 if ($show_word_button === 'on') {
396 echo ' <input type="file" id="word-upload" accept=".docx" style="display: none;">';
397 echo ' <button id="word-upload-btn" class="toolbar-btn" title="' . esc_attr__('Upload Word Document', 'mxchat') . '">';
398 echo ' <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 384 512" stroke="currentColor">';
399 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>';
400 echo ' </button>';
401 }
402
403 // File containers (unchanged)
404 echo ' <div id="active-pdf-container" class="active-pdf-container" style="display: none;">';
405 echo ' <span id="active-pdf-name" class="active-pdf-name"></span>';
406 echo ' <button id="remove-pdf-btn" class="remove-pdf-btn" title="' . esc_attr__('Remove PDF', 'mxchat') . '">';
407 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">';
408 echo ' <line x1="18" y1="6" x2="6" y2="18"></line>';
409 echo ' <line x1="6" y1="6" x2="18" y2="18"></line>';
410 echo ' </svg>';
411 echo ' </button>';
412 echo ' </div>';
413
414 echo ' <div id="active-word-container" class="active-pdf-container" style="display: none;">';
415 echo ' <span id="active-word-name" class="active-pdf-name"></span>';
416 echo ' <button id="remove-word-btn" class="remove-pdf-btn" title="' . esc_attr__('Remove Word Document', 'mxchat') . '">';
417 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">';
418 echo ' <line x1="18" y1="6" x2="6" y2="18"></line>';
419 echo ' <line x1="6" y1="6" x2="18" y2="18"></line>';
420 echo ' </svg>';
421 echo ' </button>';
422 echo ' </div>';
423
424 // Perplexity Button (unchanged except for the conditional)
425 if (apply_filters('mxchat_perplexity_should_show_logo', true)) {
426 echo ' <button id="perplexity-search-btn" class="toolbar-btn" title="' . esc_attr__('Search with Perplexity', 'mxchat-perplexity') . '">';
427 echo ' <svg fill="currentColor" height="1em" viewBox="0 0 24 24" width="1em" xmlns="http://www.w3.org/2000/svg">';
428 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>';
429 echo ' </svg>';
430 echo ' </button>';
431 }
432
433
434 // Image Analysis Button - hidden by default, controlled by MxChat Vision add-on
435 echo ' <input type="file" id="image-upload" accept="image/*" style="display: none;" multiple>';
436 echo ' <button id="image-upload-btn" class="toolbar-btn" title="' . esc_attr__('Upload Image for Analysis', 'mxchat') . '" style="display: none;">';
437 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;">';
438 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;"/>';
439 echo ' <circle cx="12" cy="13" r="3" style="fill: none !important;"/>';
440 echo ' </svg>';
441 echo ' </button>';
442
443
444 echo ' </div>';
445
446 echo ' <div class="chatbot-footer">';
447
448 // Output the privacy notice if enabled
449 if ($privacy_toggle && !empty($privacy_text)) {
450 echo '<p class="privacy-notice">' . $privacy_text . '</p>';
451 }
452
453 echo ' </div>';
454 echo ' </div>';
455 echo ' </div>';
456 echo '</div>';
457
458 if ($is_floating) {
459 echo '</div>';
460
461 if (!empty($pre_chat_message) && !get_transient($transient_key)) {
462 echo '<div id="pre-chat-message">';
463 echo esc_html($pre_chat_message);
464 echo '<button class="close-pre-chat-message" aria-label="' . esc_attr__('Close', 'mxchat') . '">&times;</button>';
465 echo '</div>';
466 }
467
468 echo '<div class="' . esc_attr($visibility_class) . '" id="floating-chatbot-button" style="background: ' . esc_attr($chatbot_background_color) . '; color: ' . esc_attr($send_button_font_color) . ';">';
469 echo '<div id="chat-notification-badge" 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>';
470
471 if (!empty($custom_icon)) {
472 echo '<img src="' . $custom_icon . '" alt="' . esc_attr__('Chatbot Icon', 'mxchat') . '" style="height: 48px; width: 48px; object-fit: contain;" />';
473 } else {
474 echo '<svg id="widget_icon_10" style="height: 48px; width: 48px; fill: ' . esc_attr($icon_color) . '" viewBox="0 0 1120 1120" fill="none" xmlns="http://www.w3.org/2000/svg">';
475 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>';
476 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>';
477 echo '</svg>';
478 }
479 echo '</div>';
480 }
481
482 return ob_get_clean();
483 }
484
485 /**
486 * Get bot-specific options for multi-bot functionality
487 * Falls back to default options if bot_id is 'default' or multi-bot add-on is not active
488 */
489 private function get_bot_options($bot_id = 'default') {
490 // If default bot or multi-bot add-on not active, return empty (use default options)
491 if ($bot_id === 'default' || !class_exists('MxChat_Multi_Bot_Manager')) {
492 return array();
493 }
494
495 //Hook for multi-bot add-on to provide bot-specific options
496 $bot_options = apply_filters('mxchat_get_bot_options', array(), $bot_id);
497
498 return is_array($bot_options) ? $bot_options : array();
499 }
500
501 /**
502 * Get bot-specific Pinecone configuration
503 * Used in the knowledge retrieval functions
504 */
505 private function get_bot_pinecone_config($bot_id = 'default') {
506 // If default bot or multi-bot add-on not active, use default Pinecone config
507 if ($bot_id === 'default' || !class_exists('MxChat_Multi_Bot_Manager')) {
508 $addon_options = get_option('mxchat_pinecone_addon_options', array());
509 return array(
510 'use_pinecone' => (isset($addon_options['mxchat_use_pinecone']) && $addon_options['mxchat_use_pinecone'] === '1'),
511 'api_key' => $addon_options['mxchat_pinecone_api_key'] ?? '',
512 'host' => $addon_options['mxchat_pinecone_host'] ?? '',
513 'namespace' => $addon_options['mxchat_pinecone_namespace'] ?? ''
514 );
515 }
516
517 // Hook for multi-bot add-on to provide bot-specific Pinecone config
518 $bot_pinecone_config = apply_filters('mxchat_get_bot_pinecone_config', array(), $bot_id);
519
520 return is_array($bot_pinecone_config) ? $bot_pinecone_config : array();
521 }
522
523
524 private function determine_email_collection_state() {
525 // Get session ID
526 $session_id = 'mxchat_chat_' . wp_generate_uuid4(); // You'll need to use your actual session generation logic
527
528 // Check if user is logged in first
529 if (is_user_logged_in()) {
530 $current_user = wp_get_current_user();
531 return [
532 'show_email_form' => false,
533 'user_email' => $current_user->user_email,
534 'user_name' => $current_user->display_name ?: $current_user->first_name ?: ''
535 ];
536 }
537
538 // Check stored email for session
539 $stored_email = get_option("mxchat_email_{$session_id}", '');
540 $stored_name = get_option("mxchat_name_{$session_id}", '');
541
542 // Check if name is required
543 $name_field_enabled = isset($this->options['enable_name_field']) &&
544 ($this->options['enable_name_field'] === '1' || $this->options['enable_name_field'] === 'on');
545
546 $has_required_info = !empty($stored_email);
547 if ($name_field_enabled) {
548 $has_required_info = $has_required_info && !empty($stored_name);
549 }
550
551 return [
552 'show_email_form' => !$has_required_info,
553 'user_email' => $stored_email,
554 'user_name' => $stored_name
555 ];
556 }
557
558
559 /**
560 * NEW: Determine if and which chatbot should be displayed
561 */
562 private function get_display_bot() {
563 // Get page-specific settings from meta box
564 $page_setting = $this->get_page_bot_setting();
565
566 // Get global settings - FIXED: Check for 'on' instead of 'on'
567 $global_autoshow = isset($this->options['append_to_body']) && $this->options['append_to_body'] === 'on';
568 $global_default_bot = isset($this->options['default_bot']) ? $this->options['default_bot'] : 'default';
569
570 // If page specifically hides chatbot, don't show anything
571 if ($page_setting && $page_setting['action'] === 'hide') {
572 return false;
573 }
574
575 // If page specifies a specific bot, use that
576 if ($page_setting && $page_setting['action'] === 'show') {
577 return $page_setting['bot_id'];
578 }
579
580 // Page setting is 'global' or no page setting exists
581 // Check global auto-show setting
582 if ($global_autoshow) {
583 // Global auto-show is enabled, return the default bot
584 return $global_default_bot;
585 }
586
587 // Global auto-show is disabled and no page-specific bot selected
588 // Don't show chatbot (user should use shortcodes)
589 return false;
590 }
591
592 /**
593 * NEW: Get page-specific bot setting
594 */
595 private function get_page_bot_setting($post_id = null) {
596 if (!$post_id) {
597 $post_id = get_the_ID();
598 }
599
600 if (!$post_id) {
601 return null;
602 }
603
604 // Check if chatbot is hidden on this page
605 $hide_chatbot = get_post_meta($post_id, '_mxchat_hide_chatbot', true);
606 if ($hide_chatbot === '1') {
607 return array('action' => 'hide');
608 }
609
610 // Check if specific bot is selected
611 $selected_bot = get_post_meta($post_id, '_mxchat_selected_bot', true);
612 if (!empty($selected_bot)) {
613 return array('action' => 'show', 'bot_id' => $selected_bot);
614 }
615
616 // Use global setting
617 return array('action' => 'global');
618 }
619
620 /**
621 * NEW: Determine which bot to use for shortcode
622 */
623 private function determine_bot_for_shortcode($shortcode_bot_id) {
624 // If bot_id explicitly provided in shortcode, use that
625 if (!empty($shortcode_bot_id)) {
626 return $shortcode_bot_id;
627 }
628
629 // No bot_id in shortcode, check page setting
630 $page_setting = $this->get_page_bot_setting();
631 if ($page_setting && $page_setting['action'] === 'show') {
632 return $page_setting['bot_id'];
633 }
634
635 // Fall back to default
636 return 'default';
637 }
638
639 /**
640 * NEW: Helper to check if auto-append is enabled globally
641 */
642 private function is_auto_append_enabled() {
643 return isset($this->options['append_to_body']) && $this->options['append_to_body'] === 'on';
644 }
645
646 /**
647 * UPDATED: Debug function with new context info
648 */
649 public function debug_display_logic() {
650 if (current_user_can('manage_options') && isset($_GET['mxchat_debug'])) {
651 $bot_to_show = $this->get_display_bot();
652 $page_setting = $this->get_page_bot_setting();
653 $global_autoshow = isset($this->options['append_to_body']) && $this->options['append_to_body'] === 'on';
654 $hide_auto = $this->should_hide_chatbot('auto');
655
656 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;">';
657 echo '<h4 style="margin: 0 0 10px 0;">MxChat Debug Info</h4>';
658 echo '<p><strong>Raw append_to_body value:</strong> "' . ($this->options['append_to_body'] ?? 'NOT SET') . '"</p>';
659 echo '<p><strong>Page Setting:</strong><br><pre>' . print_r($page_setting, true) . '</pre></p>';
660 echo '<p><strong>Global Auto-show:</strong> ' . ($global_autoshow ? 'ON' : 'OFF') . '</p>';
661 echo '<p><strong>Hide Auto-Append:</strong> ' . ($hide_auto ? 'YES' : 'NO') . '</p>';
662 echo '<p><strong>Bot to Show:</strong> ' . ($bot_to_show === false ? 'NONE' : $bot_to_show) . '</p>';
663 echo '<p><strong>Shortcodes:</strong> floating="no" always works</p>';
664 echo '<p><small>Add ?mxchat_debug=1 to URL to see this</small></p>';
665 echo '</div>';
666 }
667 }
668
669 /**
670 * NEW: Helper method to get available bots (for admin notices, etc.)
671 */
672 private function get_available_bots() {
673 $bots = array('default' => __('Default Bot', 'mxchat'));
674
675 // Check if multi-bot addon is active
676 if (class_exists('MxChat_Multi_Bot_Manager')) {
677 $multi_bot_manager = MxChat_Multi_Bot_Core_Manager::get_instance();
678 $available_bots = $multi_bot_manager->get_available_bots();
679
680 // Add the available bots
681 foreach ($available_bots as $bot_id => $bot_name) {
682 $bots[$bot_id] = $bot_name;
683 }
684 }
685
686 return $bots;
687 }
688
689
690
691 }
692 ?>