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

774 lines 40.9 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 // UPDATED: Use current_options instead of $this->options throughout
209 $bg_color = $current_options['chatbot_background_color'] ?? '#fff';
210 $user_message_bg_color = $current_options['user_message_bg_color'] ?? '#fff';
211 $user_message_font_color = $current_options['user_message_font_color'] ?? '#212121';
212 $bot_message_bg_color = $current_options['bot_message_bg_color'] ?? '#212121';
213 $bot_message_font_color = $current_options['bot_message_font_color'] ?? '#fff';
214 $top_bar_bg_color = $current_options['top_bar_bg_color'] ?? '#212121';
215 $send_button_font_color = $current_options['send_button_font_color'] ?? '#212121';
216 $intro_message = $current_options['intro_message'] ?? esc_html__('Hello! How can I assist you today?', 'mxchat');
217 $top_bar_title = $current_options['top_bar_title'] ?? esc_html__('MxChat: Basic', 'mxchat');
218 $chatbot_background_color = $current_options['chatbot_background_color'] ?? '#212121';
219 $icon_color = $current_options['icon_color'] ?? '#fff';
220 $chat_input_font_color = $current_options['chat_input_font_color'] ?? '#212121';
221 $close_button_color = $current_options['close_button_color'] ?? '#fff';
222 $chatbot_bg_color = $current_options['chatbot_bg_color'] ?? '#fff';
223 $pre_chat_message = isset($current_options['pre_chat_message']) ? sanitize_text_field(trim($current_options['pre_chat_message'])) : '';
224 $user_id = sanitize_key($this->mxchat_get_user_identifier());
225 $email_state = $this->determine_email_collection_state();
226 $show_email_form = $email_state['show_email_form'];
227 $user_email = $email_state['user_email'] ?? '';
228 $user_name = $email_state['user_name'] ?? '';
229 $transient_key = 'mxchat_pre_chat_message_dismissed_' . $user_id;
230 $input_copy = isset($current_options['input_copy']) ? esc_attr($current_options['input_copy']) : esc_attr__('How can I assist?', 'mxchat');
231 $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');
232 $mode_indicator_bg_color = $current_options['mode_indicator_bg_color'] ?? '#212121';
233 $mode_indicator_font_color = $current_options['mode_indicator_font_color'] ?? '#fff';
234 $quick_questions_toggle_color = $current_options['quick_questions_toggle_color'] ?? '#212121';
235
236 $privacy_toggle = isset($current_options['privacy_toggle']) && $current_options['privacy_toggle'] === 'on';
237 $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'));
238
239 $popular_question_1 = isset($current_options['popular_question_1']) ? esc_html($current_options['popular_question_1']) : '';
240 $popular_question_2 = isset($current_options['popular_question_2']) ? esc_html($current_options['popular_question_2']) : '';
241 $popular_question_3 = isset($current_options['popular_question_3']) ? esc_html($current_options['popular_question_3']) : '';
242 $additional_questions = isset($current_options['additional_popular_questions']) ? $current_options['additional_popular_questions'] : [];
243 $custom_icon = isset($current_options['custom_icon']) ? esc_url($current_options['custom_icon']) : '';
244 $title_icon = isset($current_options['title_icon']) ? esc_url($current_options['title_icon']) : '';
245 $ai_agent_text = isset($current_options['ai_agent_text']) ? esc_html($current_options['ai_agent_text']) : esc_html__('AI Agent', 'mxchat');
246
247 $live_agent_message_bg_color = $current_options['live_agent_message_bg_color'] ?? '#212121';
248 $live_agent_message_font_color = $current_options['live_agent_message_font_color'] ?? '#fff';
249 $enable_email_block = isset($current_options['enable_email_block']) &&
250 ($current_options['enable_email_block'] === '1' || $current_options['enable_email_block'] === 'on');
251
252 // Add name field variables
253 $enable_name_field = isset($current_options['enable_name_field']) &&
254 ($current_options['enable_name_field'] === '1' || $current_options['enable_name_field'] === 'on');
255 $name_field_placeholder = isset($current_options['name_field_placeholder']) ?
256 esc_attr($current_options['name_field_placeholder']) :
257 esc_attr__('Enter your name', 'mxchat');
258
259 ob_start();
260
261 // Check if floating attribute is set to 'yes' and wrap accordingly
262 if ($is_floating) {
263 echo '<div id="floating-chatbot" class="' . $initial_visibility . $additional_class . '">';
264 }
265
266 // Add bot_id to the chatbot wrapper as a data attribute
267 echo '<div id="mxchat-chatbot-wrapper" data-bot-id="' . esc_attr($bot_id) . '">';
268
269 echo ' <div class="chatbot-top-bar" id="exit-chat-button" style="background: ' . esc_attr($top_bar_bg_color) . ';">';
270 echo ' <div class="chatbot-title-container">';
271 echo ' <div class="chatbot-title-group">';
272 if (!empty($title_icon)) {
273 echo ' <img src="' . esc_url($title_icon) . '" alt="" class="chatbot-title-icon">';
274 }
275 echo ' <p class="chatbot-title" style="color: ' . esc_attr($close_button_color) . ';">' . esc_html($top_bar_title) . '</p>';
276 echo ' </div>';
277 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>';
278 echo ' </div>';
279 echo ' <button class="exit-chat" type="button" aria-label="' . esc_attr__('Minimize', 'mxchat') . '" style="color: ' . esc_attr($close_button_color) . ';">';
280 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) . ';">';
281 echo ' <path d="M0 0h24v24H0z" fill="none"></path>';
282 echo ' <path d="M11.67 3.87L9.9 2.1 0 12l9.9 9.9 1.77-1.77L3.54 12z"></path>';
283 echo ' </svg>';
284 echo ' <span>' . esc_html__('Minimize', 'mxchat') . '</span>';
285 echo ' </button>';
286 echo ' </div>';
287
288 // 3b) Main chatbot container
289 echo ' <div id="mxchat-chatbot" style="background-color: ' . esc_attr($chatbot_bg_color) . ';">';
290
291 if ($enable_email_block) {
292 echo '<div id="email-blocker" class="email-blocker" style="' . ($show_email_form ? '' : 'display: none;') . '">';
293 echo ' <div class="email-blocker-header">';
294
295 $header_html = isset($current_options['email_blocker_header_content'])
296 ? $current_options['email_blocker_header_content']
297 : '';
298 echo wp_kses_post($header_html);
299
300 echo ' </div>';
301 echo ' <form id="email-collection-form" method="POST" action="">';
302
303 // Add name field if enabled
304 if ($enable_name_field) {
305 echo ' <label for="user-name" class="sr-only mxchat-name-label">' . esc_html__('Name', 'mxchat') . '</label>';
306 echo ' <input type="text" id="user-name" name="user_name" class="mxchat-name-input" required placeholder="' . $name_field_placeholder . '" />';
307 }
308
309 echo ' <label for="user-email" class="sr-only">' . esc_html__('Email Address', 'mxchat') . '</label>';
310 echo ' <input type="email" id="user-email" name="user_email" required placeholder="' . esc_attr__('Enter your email address', 'mxchat') . '" />';
311 echo '<button type="submit" id="email-submit-button">';
312 $button_text = isset($current_options['email_blocker_button_text'])
313 ? $current_options['email_blocker_button_text']
314 : esc_html__('Start Chat', 'mxchat');
315 echo esc_html($button_text);
316 echo '</button>';
317 echo ' </form>';
318 echo '</div>';
319 }
320
321 echo ' <div id="chat-container" style="' . ($enable_email_block && $show_email_form ? 'display: none;' : '') . '">';
322 echo ' <div id="chat-box">';
323 echo ' <div class="bot-message" style="background: ' . esc_attr($bot_message_bg_color) . ';">';
324 echo ' <div dir="auto" style="color: ' . esc_attr($bot_message_font_color) . ';">';
325 echo wp_kses_post($intro_message);
326 echo ' </div>';
327 echo ' </div>';
328 echo ' </div>'; // end #chat-box
329
330
331 // Replace the existing popular questions section with this:
332 echo ' <div id="mxchat-popular-questions">';
333 echo ' <div class="mxchat-popular-questions-container">';
334
335 // Collapse button (down arrow) - shows when open, centered at top
336 echo ' <button class="questions-collapse-btn" aria-label="' . esc_attr__('Hide Quick Questions', 'mxchat') . '">';
337 echo ' <svg width="25" height="25" viewBox="0 0 24 24" fill="none" stroke="' . esc_attr($quick_questions_toggle_color) . '" stroke-width="2">';
338 echo ' <polyline points="6,9 12,15 18,9"></polyline>';
339 echo ' </svg>';
340 echo ' </button>';
341
342 // Expand button (up arrow) - shows when collapsed
343 echo ' <button class="questions-toggle-btn" aria-label="' . esc_attr__('Show Quick Questions', 'mxchat') . '">';
344 echo ' <svg width="25" height="25" viewBox="0 0 24 24" fill="none" stroke="' . esc_attr($quick_questions_toggle_color) . '" stroke-width="2">';
345 echo ' <polyline points="18,15 12,9 6,15"></polyline>';
346 echo ' </svg>';
347 echo ' </button>';
348
349 if (!empty($popular_question_1)) {
350 echo '<button class="mxchat-popular-question" dir="auto">' . esc_html($popular_question_1) . '</button>';
351 }
352 if (!empty($popular_question_2)) {
353 echo '<button class="mxchat-popular-question" dir="auto">' . esc_html($popular_question_2) . '</button>';
354 }
355 if (!empty($popular_question_3)) {
356 echo '<button class="mxchat-popular-question" dir="auto">' . esc_html($popular_question_3) . '</button>';
357 }
358
359 if (!empty($additional_questions) && is_array($additional_questions)) {
360 foreach ($additional_questions as $index => $question) {
361 if (!empty($question)) {
362 echo '<button class="mxchat-popular-question" dir="auto">' . esc_html($question) . '</button>';
363 }
364 }
365 }
366
367 echo ' </div>';
368 echo ' </div>';
369
370 echo ' <div id="input-container">';
371 echo ' <textarea id="chat-input" dir="auto" placeholder="' . esc_attr($input_copy) . '" style="color: ' . esc_attr($chat_input_font_color) . ';"></textarea>';
372 echo ' <button id="send-button" aria-label="' . esc_attr__('Send message', 'mxchat') . '">';
373 if (!empty($custom_send_image)) {
374 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);" />';
375 } else {
376 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);">';
377 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>';
378 echo ' </svg>';
379 }
380 echo ' </button>';
381 echo ' </div>';
382
383 echo ' <div class="chat-toolbar">';
384
385 // PDF Upload Button - wrapped in conditional using current_options
386 $show_pdf_button = isset($current_options['show_pdf_upload_button']) ? $current_options['show_pdf_upload_button'] : 'on';
387 if ($show_pdf_button === 'on') {
388 echo ' <input type="file" id="pdf-upload" accept=".pdf" style="display: none;">';
389 echo ' <button id="pdf-upload-btn" class="toolbar-btn" title="' . esc_attr__('Upload PDF', 'mxchat') . '">';
390 echo ' <!-- Icon from Font Awesome Free: https://fontawesome.com/license/free -->';
391 echo ' <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" stroke="currentColor">';
392 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>';
393 echo ' </svg>';
394 echo ' </button>';
395 }
396
397 // Word Upload Button - wrapped in conditional using current_options
398 $show_word_button = isset($current_options['show_word_upload_button']) ? $current_options['show_word_upload_button'] : 'on';
399 if ($show_word_button === 'on') {
400 echo ' <input type="file" id="word-upload" accept=".docx" style="display: none;">';
401 echo ' <button id="word-upload-btn" class="toolbar-btn" title="' . esc_attr__('Upload Word Document', 'mxchat') . '">';
402 echo ' <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 384 512" stroke="currentColor">';
403 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>';
404 echo ' </button>';
405 }
406
407 // File containers (unchanged)
408 echo ' <div id="active-pdf-container" class="active-pdf-container" style="display: none;">';
409 echo ' <span id="active-pdf-name" class="active-pdf-name"></span>';
410 echo ' <button id="remove-pdf-btn" class="remove-pdf-btn" title="' . esc_attr__('Remove PDF', 'mxchat') . '">';
411 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">';
412 echo ' <line x1="18" y1="6" x2="6" y2="18"></line>';
413 echo ' <line x1="6" y1="6" x2="18" y2="18"></line>';
414 echo ' </svg>';
415 echo ' </button>';
416 echo ' </div>';
417
418 echo ' <div id="active-word-container" class="active-pdf-container" style="display: none;">';
419 echo ' <span id="active-word-name" class="active-pdf-name"></span>';
420 echo ' <button id="remove-word-btn" class="remove-pdf-btn" title="' . esc_attr__('Remove Word Document', 'mxchat') . '">';
421 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">';
422 echo ' <line x1="18" y1="6" x2="6" y2="18"></line>';
423 echo ' <line x1="6" y1="6" x2="18" y2="18"></line>';
424 echo ' </svg>';
425 echo ' </button>';
426 echo ' </div>';
427
428 // Perplexity Button (unchanged except for the conditional)
429 if (apply_filters('mxchat_perplexity_should_show_logo', true)) {
430 echo ' <button id="perplexity-search-btn" class="toolbar-btn" title="' . esc_attr__('Search with Perplexity', 'mxchat-perplexity') . '">';
431 echo ' <svg fill="currentColor" height="1em" viewBox="0 0 24 24" width="1em" xmlns="http://www.w3.org/2000/svg">';
432 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>';
433 echo ' </svg>';
434 echo ' </button>';
435 }
436
437
438 // Image Analysis Button - hidden by default, controlled by MxChat Vision add-on
439 echo ' <input type="file" id="image-upload" accept="image/*" style="display: none;" multiple>';
440 echo ' <button id="image-upload-btn" class="toolbar-btn" title="' . esc_attr__('Upload Image for Analysis', 'mxchat') . '" style="display: none;">';
441 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;">';
442 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;"/>';
443 echo ' <circle cx="12" cy="13" r="3" style="fill: none !important;"/>';
444 echo ' </svg>';
445 echo ' </button>';
446
447
448 echo ' </div>';
449
450 echo ' <div class="chatbot-footer">';
451
452 // Output the privacy notice if enabled
453 if ($privacy_toggle && !empty($privacy_text)) {
454 echo '<p class="privacy-notice">' . $privacy_text . '</p>';
455 }
456
457 echo ' </div>';
458 echo ' </div>';
459 echo ' </div>';
460 echo '</div>';
461
462 if ($is_floating) {
463 echo '</div>';
464
465 if (!empty($pre_chat_message) && !get_transient($transient_key)) {
466 echo '<div id="pre-chat-message">';
467 echo esc_html($pre_chat_message);
468 echo '<button class="close-pre-chat-message" aria-label="' . esc_attr__('Close', 'mxchat') . '">&times;</button>';
469 echo '</div>';
470 }
471
472 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) . ';">';
473 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>';
474
475 if (!empty($custom_icon)) {
476 echo '<img src="' . $custom_icon . '" alt="' . esc_attr__('Chatbot Icon', 'mxchat') . '" style="height: 48px; width: 48px; object-fit: contain;" />';
477 } else {
478 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">';
479 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>';
480 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>';
481 echo '</svg>';
482 }
483 echo '</div>';
484 }
485
486 return ob_get_clean();
487 }
488
489 /**
490 * Get bot-specific options for multi-bot functionality
491 * Falls back to default options if bot_id is 'default' or multi-bot add-on is not active
492 */
493 private function get_bot_options($bot_id = 'default') {
494 // If default bot or multi-bot add-on not active, return empty (use default options)
495 if ($bot_id === 'default' || !class_exists('MxChat_Multi_Bot_Manager')) {
496 return array();
497 }
498
499 //Hook for multi-bot add-on to provide bot-specific options
500 $bot_options = apply_filters('mxchat_get_bot_options', array(), $bot_id);
501
502 return is_array($bot_options) ? $bot_options : array();
503 }
504
505 /**
506 * Get bot-specific Pinecone configuration
507 * Used in the knowledge retrieval functions
508 */
509 private function get_bot_pinecone_config($bot_id = 'default') {
510 // If default bot or multi-bot add-on not active, use default Pinecone config
511 if ($bot_id === 'default' || !class_exists('MxChat_Multi_Bot_Manager')) {
512 $addon_options = get_option('mxchat_pinecone_addon_options', array());
513 return array(
514 'use_pinecone' => (isset($addon_options['mxchat_use_pinecone']) && $addon_options['mxchat_use_pinecone'] === '1'),
515 'api_key' => $addon_options['mxchat_pinecone_api_key'] ?? '',
516 'host' => $addon_options['mxchat_pinecone_host'] ?? '',
517 'namespace' => $addon_options['mxchat_pinecone_namespace'] ?? ''
518 );
519 }
520
521 // Hook for multi-bot add-on to provide bot-specific Pinecone config
522 $bot_pinecone_config = apply_filters('mxchat_get_bot_pinecone_config', array(), $bot_id);
523
524 return is_array($bot_pinecone_config) ? $bot_pinecone_config : array();
525 }
526
527
528 private function determine_email_collection_state() {
529 // Get session ID
530 $session_id = 'mxchat_chat_' . wp_generate_uuid4(); // You'll need to use your actual session generation logic
531
532 // Check if user is logged in first
533 if (is_user_logged_in()) {
534 $current_user = wp_get_current_user();
535 return [
536 'show_email_form' => false,
537 'user_email' => $current_user->user_email,
538 'user_name' => $current_user->display_name ?: $current_user->first_name ?: ''
539 ];
540 }
541
542 // Check stored email for session
543 $stored_email = get_option("mxchat_email_{$session_id}", '');
544 $stored_name = get_option("mxchat_name_{$session_id}", '');
545
546 // Check if name is required
547 $name_field_enabled = isset($this->options['enable_name_field']) &&
548 ($this->options['enable_name_field'] === '1' || $this->options['enable_name_field'] === 'on');
549
550 $has_required_info = !empty($stored_email);
551 if ($name_field_enabled) {
552 $has_required_info = $has_required_info && !empty($stored_name);
553 }
554
555 return [
556 'show_email_form' => !$has_required_info,
557 'user_email' => $stored_email,
558 'user_name' => $stored_name
559 ];
560 }
561
562
563 /**
564 * NEW: Determine if and which chatbot should be displayed
565 */
566 private function get_display_bot() {
567 // Get page-specific settings from meta box
568 $page_setting = $this->get_page_bot_setting();
569
570 // Get global settings - FIXED: Check for 'on' instead of 'on'
571 $global_autoshow = isset($this->options['append_to_body']) && $this->options['append_to_body'] === 'on';
572 $global_default_bot = isset($this->options['default_bot']) ? $this->options['default_bot'] : 'default';
573
574 // If page specifically hides chatbot, don't show anything
575 if ($page_setting && $page_setting['action'] === 'hide') {
576 return false;
577 }
578
579 // If page specifies a specific bot, use that
580 if ($page_setting && $page_setting['action'] === 'show') {
581 return $page_setting['bot_id'];
582 }
583
584 // Page setting is 'global' or no page setting exists
585 // Check global auto-show setting
586 if ($global_autoshow) {
587 // Check post type visibility settings
588 if (!$this->should_show_on_current_post_type()) {
589 return false;
590 }
591
592 // Global auto-show is enabled, return the default bot
593 return $global_default_bot;
594 }
595
596 // Global auto-show is disabled and no page-specific bot selected
597 // Don't show chatbot (user should use shortcodes)
598 return false;
599 }
600
601 /**
602 * Check if chatbot should be shown on the current post type
603 */
604 private function should_show_on_current_post_type() {
605 // Get visibility settings
606 $mode = isset($this->options['post_type_visibility_mode']) ? $this->options['post_type_visibility_mode'] : 'all';
607 $list = isset($this->options['post_type_visibility_list']) ? $this->options['post_type_visibility_list'] : array();
608
609 // Ensure list is an array
610 if (!is_array($list)) {
611 $list = array();
612 }
613
614 // If mode is 'all', show on all post types
615 if ($mode === 'all') {
616 return true;
617 }
618
619 // Get current post type
620 $current_post_type = $this->get_current_post_type();
621
622 // If we can't determine post type, default to showing
623 if (empty($current_post_type)) {
624 return true;
625 }
626
627 // Check based on mode
628 if ($mode === 'include') {
629 // Only show on selected post types
630 return in_array($current_post_type, $list);
631 } elseif ($mode === 'exclude') {
632 // Hide on selected post types
633 return !in_array($current_post_type, $list);
634 }
635
636 // Default to showing
637 return true;
638 }
639
640 /**
641 * Get the current post type
642 */
643 private function get_current_post_type() {
644 // Try to get from queried object first
645 $queried_object = get_queried_object();
646
647 if ($queried_object instanceof WP_Post) {
648 return $queried_object->post_type;
649 }
650
651 // Try get_post_type()
652 $post_type = get_post_type();
653 if ($post_type) {
654 return $post_type;
655 }
656
657 // Check if we're on an archive
658 if (is_post_type_archive()) {
659 return get_query_var('post_type');
660 }
661
662 // Check common archive types
663 if (is_home() || is_single()) {
664 return 'post';
665 }
666
667 if (is_page()) {
668 return 'page';
669 }
670
671 return '';
672 }
673
674 /**
675 * NEW: Get page-specific bot setting
676 */
677 private function get_page_bot_setting($post_id = null) {
678 if (!$post_id) {
679 $post_id = get_the_ID();
680 }
681
682 if (!$post_id) {
683 return null;
684 }
685
686 // Check if chatbot is hidden on this page
687 $hide_chatbot = get_post_meta($post_id, '_mxchat_hide_chatbot', true);
688 if ($hide_chatbot === '1') {
689 return array('action' => 'hide');
690 }
691
692 // Check if specific bot is selected
693 $selected_bot = get_post_meta($post_id, '_mxchat_selected_bot', true);
694 if (!empty($selected_bot)) {
695 return array('action' => 'show', 'bot_id' => $selected_bot);
696 }
697
698 // Use global setting
699 return array('action' => 'global');
700 }
701
702 /**
703 * NEW: Determine which bot to use for shortcode
704 */
705 private function determine_bot_for_shortcode($shortcode_bot_id) {
706 // If bot_id explicitly provided in shortcode, use that
707 if (!empty($shortcode_bot_id)) {
708 return $shortcode_bot_id;
709 }
710
711 // No bot_id in shortcode, check page setting
712 $page_setting = $this->get_page_bot_setting();
713 if ($page_setting && $page_setting['action'] === 'show') {
714 return $page_setting['bot_id'];
715 }
716
717 // Fall back to default
718 return 'default';
719 }
720
721 /**
722 * NEW: Helper to check if auto-append is enabled globally
723 */
724 private function is_auto_append_enabled() {
725 return isset($this->options['append_to_body']) && $this->options['append_to_body'] === 'on';
726 }
727
728 /**
729 * UPDATED: Debug function with new context info
730 */
731 public function debug_display_logic() {
732 if (current_user_can('manage_options') && isset($_GET['mxchat_debug'])) {
733 $bot_to_show = $this->get_display_bot();
734 $page_setting = $this->get_page_bot_setting();
735 $global_autoshow = isset($this->options['append_to_body']) && $this->options['append_to_body'] === 'on';
736 $hide_auto = $this->should_hide_chatbot('auto');
737
738 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;">';
739 echo '<h4 style="margin: 0 0 10px 0;">MxChat Debug Info</h4>';
740 echo '<p><strong>Raw append_to_body value:</strong> "' . ($this->options['append_to_body'] ?? 'NOT SET') . '"</p>';
741 echo '<p><strong>Page Setting:</strong><br><pre>' . print_r($page_setting, true) . '</pre></p>';
742 echo '<p><strong>Global Auto-show:</strong> ' . ($global_autoshow ? 'ON' : 'OFF') . '</p>';
743 echo '<p><strong>Hide Auto-Append:</strong> ' . ($hide_auto ? 'YES' : 'NO') . '</p>';
744 echo '<p><strong>Bot to Show:</strong> ' . ($bot_to_show === false ? 'NONE' : $bot_to_show) . '</p>';
745 echo '<p><strong>Shortcodes:</strong> floating="no" always works</p>';
746 echo '<p><small>Add ?mxchat_debug=1 to URL to see this</small></p>';
747 echo '</div>';
748 }
749 }
750
751 /**
752 * NEW: Helper method to get available bots (for admin notices, etc.)
753 */
754 private function get_available_bots() {
755 $bots = array('default' => __('Default Bot', 'mxchat'));
756
757 // Check if multi-bot addon is active
758 if (class_exists('MxChat_Multi_Bot_Manager')) {
759 $multi_bot_manager = MxChat_Multi_Bot_Core_Manager::get_instance();
760 $available_bots = $multi_bot_manager->get_available_bots();
761
762 // Add the available bots
763 foreach ($available_bots as $bot_id => $bot_name) {
764 $bots[$bot_id] = $bot_name;
765 }
766 }
767
768 return $bots;
769 }
770
771
772
773 }
774 ?>