PluginProbe
MxChat – AI Chatbot & Content Generation for WordPress / 3.2.18
MxChat – AI Chatbot & Content Generation for WordPress v3.2.18
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 / admin-settings-page.php

admin-settings-page.php in MxChat – AI Chatbot & Content Generation for WordPress 3.2.18, at includes/admin-settings-page.php

1,879 lines 131.2 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * MxChat Admin Settings Page - Redesigned with Sidebar Navigation
4 *
5 * @package MxChat
6 * @since 2.7.0
7 */
8
9 if (!defined('ABSPATH')) {
10 exit;
11 }
12
13 /**
14 * Render the new sidebar-based admin settings page
15 */
16 function mxchat_render_settings_page($admin_instance) {
17 $is_activated = $admin_instance->is_activated();
18 $options = get_option('mxchat_options', array());
19 $plugin_url = plugin_dir_url(dirname(__FILE__));
20 ?>
21 <div class="mxch-admin-wrapper">
22 <!-- Mobile Header -->
23 <header class="mxch-mobile-header">
24 <a href="#" class="mxch-mobile-logo">
25 <div class="mxch-mobile-logo-icon">
26 <img src="<?php echo esc_url($plugin_url . 'images/icon-128x128.png'); ?>" alt="MxChat">
27 </div>
28 <span class="mxch-mobile-logo-text">MxChat</span>
29 </a>
30 <button type="button" class="mxch-mobile-menu-btn" aria-label="<?php esc_attr_e('Open menu', 'mxchat'); ?>">
31 <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="1"/><circle cx="12" cy="5" r="1"/><circle cx="12" cy="19" r="1"/></svg>
32 </button>
33 </header>
34
35 <!-- Mobile Menu Overlay -->
36 <div class="mxch-mobile-overlay"></div>
37
38 <!-- Mobile Menu Modal -->
39 <div class="mxch-mobile-menu">
40 <div class="mxch-mobile-menu-header">
41 <span class="mxch-mobile-menu-title"><?php esc_html_e('Settings', 'mxchat'); ?></span>
42 <button type="button" class="mxch-mobile-menu-close" aria-label="<?php esc_attr_e('Close menu', 'mxchat'); ?>">
43 <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><line x1="18" y1="6" x2="6" y2="18"/><line x1="6" y1="6" x2="18" y2="18"/></svg>
44 </button>
45 </div>
46 <nav class="mxch-mobile-menu-nav">
47 <!-- Configuration Section -->
48 <div class="mxch-mobile-nav-section">
49 <div class="mxch-mobile-nav-section-title"><?php esc_html_e('Configuration', 'mxchat'); ?></div>
50 <button class="mxch-mobile-nav-link" data-parent="chatbot">
51 <svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M12 8V4H8"/><rect width="16" height="12" x="4" y="8" rx="2"/><path d="M2 14h2"/><path d="M20 14h2"/><path d="M15 13v2"/><path d="M9 13v2"/></svg>
52 <span><?php esc_html_e('Chatbot', 'mxchat'); ?></span>
53 <svg class="mxch-mobile-nav-arrow" xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="9 18 15 12 9 6"></polyline></svg>
54 </button>
55 <div class="mxch-mobile-nav-sub" data-parent="chatbot">
56 <button class="mxch-mobile-nav-sub-link active" data-target="chatbot-ai-models"><?php esc_html_e('AI Models', 'mxchat'); ?></button>
57 <button class="mxch-mobile-nav-sub-link" data-target="chatbot-behavior"><?php esc_html_e('Behavior', 'mxchat'); ?></button>
58 <button class="mxch-mobile-nav-sub-link" data-target="chatbot-display"><?php esc_html_e('Display', 'mxchat'); ?></button>
59 <button class="mxch-mobile-nav-sub-link" data-target="chatbot-lead-capture"><?php esc_html_e('Lead Capture', 'mxchat'); ?></button>
60 <button class="mxch-mobile-nav-sub-link" data-target="chatbot-quick-questions"><?php esc_html_e('Quick Questions', 'mxchat'); ?></button>
61 <button class="mxch-mobile-nav-sub-link" data-target="chatbot-rate-limits"><?php esc_html_e('Rate Limits', 'mxchat'); ?></button>
62 </div>
63 <button class="mxch-mobile-nav-link" data-target="api-keys">
64 <svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="m21 2-2 2m-7.61 7.61a5.5 5.5 0 1 1-7.778 7.778 5.5 5.5 0 0 1 7.777-7.777zm0 0L15.5 7.5m0 0 3 3L22 7l-3-3m-3.5 3.5L19 4"/></svg>
65 <span><?php esc_html_e('API Keys', 'mxchat'); ?></span>
66 </button>
67 <button class="mxch-mobile-nav-link" data-target="optimization">
68 <svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M13 2L3 14h9l-1 8 10-12h-9l1-8z"/></svg>
69 <span><?php esc_html_e('Optimization', 'mxchat'); ?></span>
70 </button>
71 <button class="mxch-mobile-nav-link" data-target="testing">
72 <svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M9 2v6"/><path d="M15 2v6"/><path d="M12 17v5"/><path d="M5 8h14"/><path d="M6 11v-1a2 2 0 0 1 2-2h8a2 2 0 0 1 2 2v1"/><path d="m9 14 3 3 3-3"/></svg>
73 <span><?php esc_html_e('Testing', 'mxchat'); ?></span>
74 </button>
75 </div>
76 <!-- Integrations Section -->
77 <div class="mxch-mobile-nav-section">
78 <div class="mxch-mobile-nav-section-title"><?php esc_html_e('Integrations', 'mxchat'); ?></div>
79 <button class="mxch-mobile-nav-link" data-parent="integrations">
80 <svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M14.7 6.3a1 1 0 0 0 0 1.4l1.6 1.6a1 1 0 0 0 1.4 0l3.77-3.77a6 6 0 0 1-7.94 7.94l-6.91 6.91a2.12 2.12 0 0 1-3-3l6.91-6.91a6 6 0 0 1 7.94-7.94l-3.76 3.76z"/></svg>
81 <span><?php esc_html_e('Integrations', 'mxchat'); ?></span>
82 <svg class="mxch-mobile-nav-arrow" xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="9 18 15 12 9 6"></polyline></svg>
83 </button>
84 <div class="mxch-mobile-nav-sub" data-parent="integrations">
85 <button class="mxch-mobile-nav-sub-link" data-target="integrations-toolbar"><?php esc_html_e('Toolbar', 'mxchat'); ?></button>
86 <button class="mxch-mobile-nav-sub-link" data-target="integrations-loops"><?php esc_html_e('Loops', 'mxchat'); ?></button>
87 <button class="mxch-mobile-nav-sub-link" data-target="integrations-brave"><?php esc_html_e('Brave Search', 'mxchat'); ?></button>
88 <button class="mxch-mobile-nav-sub-link" data-target="integrations-slack"><?php esc_html_e('Slack', 'mxchat'); ?></button>
89 <button class="mxch-mobile-nav-sub-link" data-target="integrations-telegram"><?php esc_html_e('Telegram', 'mxchat'); ?></button>
90 </div>
91 </div>
92 <!-- Resources Section -->
93 <div class="mxch-mobile-nav-section">
94 <div class="mxch-mobile-nav-section-title"><?php esc_html_e('Resources', 'mxchat'); ?></div>
95 <button class="mxch-mobile-nav-link" data-target="tutorials">
96 <svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polygon points="23 7 16 12 23 17 23 7"/><rect x="1" y="5" width="15" height="14" rx="2" ry="2"/></svg>
97 <span><?php esc_html_e('Tutorials', 'mxchat'); ?></span>
98 </button>
99 </div>
100 <?php if (!$is_activated): ?>
101 <div class="mxch-mobile-menu-footer">
102 <a href="https://mxchat.ai/" target="_blank" class="mxch-mobile-upgrade-btn">
103 <svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M6 9H4.5a2.5 2.5 0 0 1 0-5H6"/><path d="M18 9h1.5a2.5 2.5 0 0 0 0-5H18"/><path d="M4 22h16"/><path d="M10 14.66V17c0 .55-.47.98-.97 1.21C7.85 18.75 7 20.24 7 22"/><path d="M14 14.66V17c0 .55.47.98.97 1.21C16.15 18.75 17 20.24 17 22"/><path d="M18 2H6v7a6 6 0 0 0 12 0V2Z"/></svg>
104 <?php esc_html_e('Upgrade to Pro', 'mxchat'); ?>
105 </a>
106 </div>
107 <?php endif; ?>
108 </nav>
109 </div>
110
111 <!-- Sidebar Navigation -->
112 <aside class="mxch-sidebar">
113 <div class="mxch-sidebar-header">
114 <a href="#" class="mxch-sidebar-logo">
115 <div class="mxch-sidebar-logo-icon">
116 <img src="<?php echo esc_url($plugin_url . 'images/icon-128x128.png'); ?>" alt="MxChat">
117 </div>
118 <span class="mxch-sidebar-logo-text">MxChat</span>
119 <span class="mxch-sidebar-version">v<?php echo esc_html(MXCHAT_VERSION ?? '2.7.0'); ?></span>
120 </a>
121 </div>
122
123 <nav class="mxch-sidebar-nav">
124 <!-- Chatbot Section -->
125 <div class="mxch-nav-section">
126 <div class="mxch-nav-section-title"><?php esc_html_e('Configuration', 'mxchat'); ?></div>
127
128 <div class="mxch-nav-item expanded" data-section="chatbot">
129 <button class="mxch-nav-link active">
130 <span class="mxch-nav-link-icon">
131 <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M12 8V4H8"/><rect width="16" height="12" x="4" y="8" rx="2"/><path d="M2 14h2"/><path d="M20 14h2"/><path d="M15 13v2"/><path d="M9 13v2"/></svg>
132 </span>
133 <span class="mxch-nav-link-text"><?php esc_html_e('Chatbot', 'mxchat'); ?></span>
134 <svg class="mxch-nav-link-arrow" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="9 18 15 12 9 6"></polyline></svg>
135 </button>
136 <div class="mxch-nav-sub">
137 <button class="mxch-nav-sub-link active" data-target="chatbot-ai-models"><?php esc_html_e('AI Models', 'mxchat'); ?></button>
138 <button class="mxch-nav-sub-link" data-target="chatbot-behavior"><?php esc_html_e('Behavior', 'mxchat'); ?></button>
139 <button class="mxch-nav-sub-link" data-target="chatbot-display"><?php esc_html_e('Display', 'mxchat'); ?></button>
140 <button class="mxch-nav-sub-link" data-target="chatbot-lead-capture"><?php esc_html_e('Lead Capture', 'mxchat'); ?></button>
141 <button class="mxch-nav-sub-link" data-target="chatbot-quick-questions"><?php esc_html_e('Quick Questions', 'mxchat'); ?></button>
142 <button class="mxch-nav-sub-link" data-target="chatbot-rate-limits"><?php esc_html_e('Rate Limits', 'mxchat'); ?></button>
143 </div>
144 </div>
145
146 <div class="mxch-nav-item" data-section="api-keys">
147 <button class="mxch-nav-link" data-target="api-keys">
148 <span class="mxch-nav-link-icon">
149 <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="m21 2-2 2m-7.61 7.61a5.5 5.5 0 1 1-7.778 7.778 5.5 5.5 0 0 1 7.777-7.777zm0 0L15.5 7.5m0 0 3 3L22 7l-3-3m-3.5 3.5L19 4"/></svg>
150 </span>
151 <span class="mxch-nav-link-text"><?php esc_html_e('API Keys', 'mxchat'); ?></span>
152 </button>
153 </div>
154
155 <div class="mxch-nav-item" data-section="optimization">
156 <button class="mxch-nav-link" data-target="optimization">
157 <span class="mxch-nav-link-icon">
158 <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M13 2L3 14h9l-1 8 10-12h-9l1-8z"/></svg>
159 </span>
160 <span class="mxch-nav-link-text"><?php esc_html_e('Optimization', 'mxchat'); ?></span>
161 </button>
162 </div>
163
164 <div class="mxch-nav-item" data-section="testing">
165 <button class="mxch-nav-link" data-target="testing">
166 <span class="mxch-nav-link-icon">
167 <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M9 2v6"/><path d="M15 2v6"/><path d="M12 17v5"/><path d="M5 8h14"/><path d="M6 11v-1a2 2 0 0 1 2-2h8a2 2 0 0 1 2 2v1"/><path d="m9 14 3 3 3-3"/></svg>
168 </span>
169 <span class="mxch-nav-link-text"><?php esc_html_e('Testing', 'mxchat'); ?></span>
170 </button>
171 </div>
172 </div>
173
174 <!-- Integrations Section -->
175 <div class="mxch-nav-section">
176 <div class="mxch-nav-section-title"><?php esc_html_e('Integrations', 'mxchat'); ?></div>
177
178 <div class="mxch-nav-item" data-section="integrations">
179 <button class="mxch-nav-link">
180 <span class="mxch-nav-link-icon">
181 <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M14.7 6.3a1 1 0 0 0 0 1.4l1.6 1.6a1 1 0 0 0 1.4 0l3.77-3.77a6 6 0 0 1-7.94 7.94l-6.91 6.91a2.12 2.12 0 0 1-3-3l6.91-6.91a6 6 0 0 1 7.94-7.94l-3.76 3.76z"/></svg>
182 </span>
183 <span class="mxch-nav-link-text"><?php esc_html_e('Integrations', 'mxchat'); ?></span>
184 <svg class="mxch-nav-link-arrow" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="9 18 15 12 9 6"></polyline></svg>
185 </button>
186 <div class="mxch-nav-sub">
187 <button class="mxch-nav-sub-link" data-target="integrations-toolbar"><?php esc_html_e('Toolbar', 'mxchat'); ?></button>
188 <button class="mxch-nav-sub-link" data-target="integrations-loops"><?php esc_html_e('Loops', 'mxchat'); ?></button>
189 <button class="mxch-nav-sub-link" data-target="integrations-brave"><?php esc_html_e('Brave Search', 'mxchat'); ?></button>
190 <button class="mxch-nav-sub-link" data-target="integrations-slack"><?php esc_html_e('Slack', 'mxchat'); ?></button>
191 <button class="mxch-nav-sub-link" data-target="integrations-telegram"><?php esc_html_e('Telegram', 'mxchat'); ?></button>
192 </div>
193 </div>
194 </div>
195
196 <!-- Resources Section -->
197 <div class="mxch-nav-section">
198 <div class="mxch-nav-section-title"><?php esc_html_e('Resources', 'mxchat'); ?></div>
199
200 <div class="mxch-nav-item" data-section="tutorials">
201 <button class="mxch-nav-link" data-target="tutorials">
202 <span class="mxch-nav-link-icon">
203 <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polygon points="23 7 16 12 23 17 23 7"/><rect x="1" y="5" width="15" height="14" rx="2" ry="2"/></svg>
204 </span>
205 <span class="mxch-nav-link-text"><?php esc_html_e('Tutorials', 'mxchat'); ?></span>
206 </button>
207 </div>
208 </div>
209
210 </nav>
211
212 <?php if (!$is_activated): ?>
213 <div class="mxch-sidebar-footer">
214 <a href="https://mxchat.ai/" target="_blank" class="mxch-sidebar-upgrade-v2">
215 <svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polygon points="12 2 15.09 8.26 22 9.27 17 14.14 18.18 21.02 12 17.77 5.82 21.02 7 14.14 2 9.27 8.91 8.26 12 2"/></svg>
216 <?php esc_html_e('Pro Upgrade', 'mxchat'); ?>
217 </a>
218 </div>
219 <?php endif; ?>
220 </aside>
221
222 <!-- Main Content Area -->
223 <main class="mxch-content">
224 <?php if (!$is_activated): ?>
225 <div class="mxch-pro-banner">
226 <div class="mxch-pro-banner-content">
227 <h3 class="mxch-pro-banner-title"><?php esc_html_e('Stop paying $50–200/month for AI chatbot tools.', 'mxchat'); ?></h3>
228 <p class="mxch-pro-banner-text"><?php esc_html_e('One payment unlocks every MxChat Pro add-on for life — MCP server access for Claude / ChatGPT / Claude Code, WooCommerce sales, Google Search Console insights, AI-generated chatbot themes, lead-capture forms, unlimited bots, image analysis, and more. No renewals. No surprise bills.', 'mxchat'); ?></p>
229 </div>
230 <a href="https://mxchat.ai/" target="_blank" class="mxch-pro-banner-btn"><span><?php esc_html_e('Get Lifetime Access →', 'mxchat'); ?></span></a>
231 </div>
232 <?php endif; ?>
233
234 <?php
235 // Show theme migration notice for Pro users
236 $admin_instance->show_theme_migration_banner();
237 ?>
238
239 <!-- ========================================
240 CHATBOT - AI MODELS
241 ======================================== -->
242 <div id="chatbot-ai-models" class="mxch-section active">
243 <div class="mxch-content-header">
244 <h1 class="mxch-content-title"><?php esc_html_e('AI Models', 'mxchat'); ?></h1>
245 <p class="mxch-content-subtitle"><?php esc_html_e('Configure the AI models your chatbot will use for conversations and embeddings.', 'mxchat'); ?></p>
246 </div>
247
248 <div class="mxch-card">
249 <div class="mxch-card-body mxchat-autosave-section">
250 <?php
251 // Chat Model
252 mxchat_render_field_wrapper('model', __('Chat Model', 'mxchat'), function() use ($admin_instance) {
253 $admin_instance->mxchat_model_callback();
254 }, __('Select the AI model your chatbot will use for conversations.', 'mxchat'));
255
256 // Embedding Model
257 mxchat_render_field_wrapper('embedding_model', __('Embedding Model', 'mxchat'), function() use ($admin_instance) {
258 $admin_instance->embedding_model_callback();
259 }, __('Vector embedding model for knowledge base matching. Changing models requires reconfiguring knowledge data.', 'mxchat'));
260
261 // Enable Streaming
262 mxchat_render_field_wrapper('enable_streaming', __('Enable Streaming', 'mxchat'), function() use ($admin_instance) {
263 $admin_instance->enable_streaming_toggle_callback();
264 }, __('Enable real-time streaming responses for supported models (OpenAI, Claude, DeepSeek, Grok).', 'mxchat'));
265
266 // Enable Web Search (OpenAI & Gemini)
267 mxchat_render_field_wrapper('enable_web_search', __('Enable Web Search', 'mxchat'), function() use ($admin_instance) {
268 $admin_instance->enable_web_search_toggle_callback();
269 }, __('Allow the chatbot to search the web for current information (OpenAI and Gemini models).', 'mxchat'));
270 ?>
271 </div>
272 </div>
273 </div>
274
275 <!-- ========================================
276 CHATBOT - BEHAVIOR
277 ======================================== -->
278 <div id="chatbot-behavior" class="mxch-section">
279 <div class="mxch-content-header">
280 <h1 class="mxch-content-title"><?php esc_html_e('Behavior', 'mxchat'); ?></h1>
281 <p class="mxch-content-subtitle"><?php esc_html_e('Control how your AI chatbot responds and processes queries.', 'mxchat'); ?></p>
282 </div>
283
284 <div class="mxch-card">
285 <div class="mxch-card-body mxchat-autosave-section">
286 <?php
287 // AI Instructions
288 mxchat_render_field_wrapper('system_prompt_instructions', __('AI Instructions (Behavior)', 'mxchat'), function() use ($admin_instance) {
289 $admin_instance->system_prompt_instructions_callback();
290 }, __('Provide system-level instructions to guide the AI\'s behavior and responses.', 'mxchat'));
291
292 // Similarity Threshold
293 mxchat_render_field_wrapper('similarity_threshold', __('Similarity Threshold', 'mxchat'), function() use ($admin_instance) {
294 $admin_instance->mxchat_similarity_threshold_callback();
295 }, __('Adjust threshold for content matching. Lower values = more matches, higher values = stricter matching.', 'mxchat'));
296
297 // RAG Sources Limit
298 mxchat_render_field_wrapper('rag_sources_limit', __('RAG Sources Limit', 'mxchat'), function() use ($admin_instance) {
299 $admin_instance->mxchat_rag_sources_limit_callback();
300 }, __('Number of knowledge base sources (pages/documents) to include in AI context. Higher values provide more context but use more tokens.', 'mxchat'));
301
302 // RAG Chunks Limit
303 mxchat_render_field_wrapper('rag_chunks_limit', __('RAG Chunks Limit', 'mxchat'), function() use ($admin_instance) {
304 $admin_instance->mxchat_rag_chunks_limit_callback();
305 }, __('Maximum total content chunks sent to the AI across all sources. Higher values provide more context but increase token usage and cost.', 'mxchat'));
306
307 // Hybrid keyword boost MOVED to Knowledge → Chunking &
308 // Retrieval (plan 11720c) — it is KB retrieval tuning, not
309 // conversation behavior. Same option key over there. The
310 // breadcrumb below is a one-release courtesy: drop it in
311 // the release after 3.2.17.
312 echo '<p class="mxch-field-description">';
313 printf(
314 /* translators: %s: link to the Chunking & Retrieval settings tab. */
315 esc_html__('Hybrid keyword boost has moved to %s.', 'mxchat'),
316 '<a href="' . esc_url(admin_url('admin.php?page=mxchat-prompts#chunking')) . '">' . esc_html__('Knowledge, Chunking & Retrieval', 'mxchat') . '</a>'
317 );
318 echo '</p>';
319
320 // Contextual Awareness
321 mxchat_render_field_wrapper('contextual_awareness', __('Contextual Awareness', 'mxchat'), function() use ($admin_instance) {
322 $admin_instance->mxchat_contextual_awareness_callback();
323 }, __('Allow the chatbot to understand and reference the current page content for more relevant responses.', 'mxchat'));
324
325 // Citation Links
326 mxchat_render_field_wrapper('citation_links', __('Citation Links', 'mxchat'), function() use ($admin_instance) {
327 $admin_instance->mxchat_citation_links_toggle_callback();
328 }, __('Allow the AI to include citation links from your knowledge database in responses. If disabled, ensure your AI Behavior settings do not mention links or the AI may fabricate URLs.', 'mxchat'));
329
330 // Satisfaction Rating Prompt
331 // The toggle callback inline-renders the 5 customization
332 // fields inside a single sub-options wrapper (plan-29caac).
333 // No separate customization group needed — the wrapper handles
334 // its own server-side display state based on the toggle value.
335 mxchat_render_field_wrapper('satisfaction_rating', __('Satisfaction Rating Prompt', 'mxchat'), function() use ($admin_instance) {
336 $admin_instance->mxchat_satisfaction_rating_toggle_callback();
337 }, __('Show a 👍 / 👎 prompt after a conversation has had a couple of bot replies and the visitor has been idle for a moment. Disable to hide the prompt site-wide.', 'mxchat'));
338
339 // Editor Assistant toggle moved to Content → Settings (plan-f7df40):
340 // it's a content feature, so it lives on the screen that owns it.
341 // Rendering is in admin-content-page.php; option + save path unchanged.
342 ?>
343 </div>
344 </div>
345 </div>
346
347 <!-- ========================================
348 CHATBOT - DISPLAY
349 ======================================== -->
350 <div id="chatbot-display" class="mxch-section">
351 <div class="mxch-content-header">
352 <h1 class="mxch-content-title"><?php esc_html_e('Display Settings', 'mxchat'); ?></h1>
353 <p class="mxch-content-subtitle"><?php esc_html_e('Customize how and where your chatbot appears on your website.', 'mxchat'); ?></p>
354 </div>
355
356 <div class="mxch-card">
357 <div class="mxch-card-header">
358 <h3 class="mxch-card-title">
359 <svg class="mxch-card-title-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="3" width="18" height="18" rx="2" ry="2"/><line x1="3" y1="9" x2="21" y2="9"/><line x1="9" y1="21" x2="9" y2="9"/></svg>
360 <?php esc_html_e('Visibility', 'mxchat'); ?>
361 </h3>
362 </div>
363 <div class="mxch-card-body mxchat-autosave-section">
364 <?php
365 // Auto-Display
366 mxchat_render_field_wrapper('auto_display', __('Auto-Display Chatbot', 'mxchat'), function() use ($admin_instance) {
367 $admin_instance->mxchat_append_to_body_callback();
368 }, __('Show chatbot automatically on all pages. Disable to use shortcode [mxchat_chatbot floating="yes"] for floating widget or [mxchat_chatbot floating="no"] for embedded chat.', 'mxchat'));
369
370 // Open Links in New Tab
371 mxchat_render_field_wrapper('link_target', __('Open Links in New Tab', 'mxchat'), function() use ($admin_instance) {
372 $admin_instance->mxchat_link_target_toggle_callback();
373 }, __('Open links clicked in chat responses in a new browser tab.', 'mxchat'));
374
375 // Chat Persistence
376 mxchat_render_field_wrapper('chat_persistence', __('Chat Persistence', 'mxchat'), function() use ($admin_instance) {
377 $admin_instance->mxchat_chat_persistence_toggle_callback();
378 }, __('Keep chat history when users navigate or return within 24 hours.', 'mxchat'));
379
380 // Download Transcript button
381 mxchat_render_field_wrapper('print_button', __('Show Download Transcript Button', 'mxchat'), function() use ($admin_instance) {
382 $admin_instance->mxchat_print_button_toggle_callback();
383 }, __('Show the "Download Transcript" item in the chat window menu.', 'mxchat'));
384
385 // Start-New-Chat button (plan ac2e81) — lets a visitor reset the
386 // conversation without the owner disabling chat persistence globally.
387 mxchat_render_field_wrapper('reset_chat_enabled', __('Show Start-New-Chat Button', 'mxchat'), function() use ($admin_instance) {
388 $admin_instance->mxchat_reset_chat_toggle_callback();
389 }, __('Show a "Start new chat" item in the chat window menu that clears the current conversation and begins a fresh session.', 'mxchat'));
390
391 mxchat_render_field_wrapper('reset_chat_label', __('Start-New-Chat Button Label', 'mxchat'), function() use ($admin_instance) {
392 $admin_instance->mxchat_reset_chat_label_callback();
393 }, __('Label for the Start-New-Chat menu item. Leave blank to use "Start new chat".', 'mxchat'));
394 ?>
395 </div>
396 </div>
397
398 <div class="mxch-card">
399 <div class="mxch-card-header">
400 <h3 class="mxch-card-title">
401 <svg class="mxch-card-title-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z"/></svg>
402 <?php esc_html_e('Text & Labels', 'mxchat'); ?>
403 </h3>
404 </div>
405 <div class="mxch-card-body mxchat-autosave-section">
406 <?php
407 // Top Bar Title
408 mxchat_render_field_wrapper('top_bar_title', __('Top Bar Title', 'mxchat'), function() use ($admin_instance) {
409 $admin_instance->mxchat_top_bar_title_callback();
410 }, __('Title text shown in the chatbot header.', 'mxchat'));
411
412 // AI Agent Text
413 mxchat_render_field_wrapper('ai_agent_text', __('AI Agent Text', 'mxchat'), function() use ($admin_instance) {
414 $admin_instance->mxchat_ai_agent_text_callback();
415 }, __('Text shown for AI agents in the status indicator.', 'mxchat'));
416
417 // Intro Message
418 mxchat_render_field_wrapper('intro_message', __('Introductory Message', 'mxchat'), function() use ($admin_instance) {
419 $admin_instance->mxchat_intro_message_callback();
420 }, __('First message shown when chat opens. HTML allowed.', 'mxchat'));
421
422 // Input Placeholder
423 mxchat_render_field_wrapper('input_copy', __('Input Placeholder', 'mxchat'), function() use ($admin_instance) {
424 $admin_instance->mxchat_input_copy_callback();
425 }, __('Placeholder text in the chat input field.', 'mxchat'));
426
427 // Max Input Length (characters) — plan a3fae2 part C
428 mxchat_render_field_wrapper('max_input_length', __('Max Input Length (characters)', 'mxchat'), function() use ($admin_instance) {
429 $admin_instance->mxchat_max_input_length_callback();
430 }, __('Cap how many characters a visitor can type or paste into a single message. Set to 0 for unlimited (default).', 'mxchat'));
431
432 // Chat Teaser
433 mxchat_render_field_wrapper('pre_chat_message', __('Chat Teaser Pop-up', 'mxchat'), function() use ($admin_instance) {
434 $admin_instance->mxchat_pre_chat_message_callback();
435 }, __('Message shown before users start chatting.', 'mxchat'));
436 ?>
437 </div>
438 </div>
439 </div>
440
441 <!-- ========================================
442 CHATBOT - LEAD CAPTURE
443 ======================================== -->
444 <div id="chatbot-lead-capture" class="mxch-section">
445 <div class="mxch-content-header">
446 <h1 class="mxch-content-title"><?php esc_html_e('Lead Capture', 'mxchat'); ?></h1>
447 <p class="mxch-content-subtitle"><?php esc_html_e('Collect user information and manage privacy settings.', 'mxchat'); ?></p>
448 </div>
449
450 <div class="mxch-card">
451 <div class="mxch-card-header">
452 <h3 class="mxch-card-title">
453 <svg class="mxch-card-title-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="2" y="4" width="20" height="16" rx="2"/><path d="m22 7-8.97 5.7a1.94 1.94 0 0 1-2.06 0L2 7"/></svg>
454 <?php esc_html_e('Email Capture', 'mxchat'); ?>
455 </h3>
456 </div>
457 <div class="mxch-card-body mxchat-autosave-section">
458 <?php
459 // Require Email
460 mxchat_render_field_wrapper('enable_email_block', __('Require Email to Chat', 'mxchat'), function() use ($admin_instance) {
461 $admin_instance->enable_email_block_callback();
462 }, __('Require users to enter their email before chatting. Shows for non-logged-in users.', 'mxchat'));
463
464 // Email Form Content
465 mxchat_render_field_wrapper('email_blocker_header', __('Email Form Content', 'mxchat'), function() use ($admin_instance) {
466 $admin_instance->email_blocker_header_content_callback();
467 }, __('HTML content shown above the email form.', 'mxchat'));
468
469 // Email Button Text
470 mxchat_render_field_wrapper('email_blocker_button', __('Submit Button Text', 'mxchat'), function() use ($admin_instance) {
471 $admin_instance->email_blocker_button_text_callback();
472 }, __('Text for the email form submit button.', 'mxchat'));
473
474 // Require Name
475 mxchat_render_field_wrapper('enable_name_field', __('Also Require Name', 'mxchat'), function() use ($admin_instance) {
476 $admin_instance->enable_name_field_callback();
477 }, __('Also require users to enter their name with email.', 'mxchat'));
478
479 // Name Placeholder
480 mxchat_render_field_wrapper('name_placeholder', __('Name Field Placeholder', 'mxchat'), function() use ($admin_instance) {
481 $admin_instance->name_field_placeholder_callback();
482 }, __('Placeholder text for the name input field.', 'mxchat'));
483 ?>
484 </div>
485 </div>
486
487 <div class="mxch-card">
488 <div class="mxch-card-header">
489 <h3 class="mxch-card-title">
490 <svg class="mxch-card-title-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10z"/></svg>
491 <?php esc_html_e('Privacy & Compliance', 'mxchat'); ?>
492 </h3>
493 </div>
494 <div class="mxch-card-body mxchat-autosave-section">
495 <?php
496 // Privacy Notice
497 mxchat_render_field_wrapper('privacy_toggle', __('Privacy Notice', 'mxchat'), function() use ($admin_instance) {
498 $admin_instance->mxchat_privacy_toggle_callback();
499 }, __('Show privacy notice below the chat widget.', 'mxchat'));
500
501 // Complianz
502 mxchat_render_field_wrapper('complianz_toggle', __('Complianz Integration', 'mxchat'), function() use ($admin_instance) {
503 $admin_instance->mxchat_complianz_toggle_callback();
504 }, __('Apply Complianz consent logic to the chatbot (requires Complianz plugin).', 'mxchat'));
505 ?>
506 </div>
507 </div>
508 </div>
509
510 <!-- ========================================
511 CHATBOT - QUICK QUESTIONS
512 ======================================== -->
513 <div id="chatbot-quick-questions" class="mxch-section">
514 <div class="mxch-content-header">
515 <h1 class="mxch-content-title"><?php esc_html_e('Quick Questions', 'mxchat'); ?></h1>
516 <p class="mxch-content-subtitle"><?php esc_html_e('Pre-defined questions displayed above the chat input to help users get started.', 'mxchat'); ?></p>
517 </div>
518
519 <div class="mxch-card">
520 <div class="mxch-card-body mxchat-autosave-section">
521 <?php
522 // Quick Question 1
523 mxchat_render_field_wrapper('popular_question_1', __('Quick Question 1', 'mxchat'), function() use ($admin_instance) {
524 $admin_instance->mxchat_popular_question_1_callback();
525 });
526
527 // Quick Question 2
528 mxchat_render_field_wrapper('popular_question_2', __('Quick Question 2', 'mxchat'), function() use ($admin_instance) {
529 $admin_instance->mxchat_popular_question_2_callback();
530 });
531
532 // Quick Question 3
533 mxchat_render_field_wrapper('popular_question_3', __('Quick Question 3', 'mxchat'), function() use ($admin_instance) {
534 $admin_instance->mxchat_popular_question_3_callback();
535 });
536
537 // Additional Questions
538 mxchat_render_field_wrapper('additional_questions', __('Additional Questions', 'mxchat'), function() use ($admin_instance) {
539 $admin_instance->mxchat_additional_popular_questions_callback();
540 }, __('Add as many quick questions as you need.', 'mxchat'));
541 ?>
542 </div>
543 </div>
544 </div>
545
546 <!-- ========================================
547 CHATBOT - RATE LIMITS
548 ======================================== -->
549 <div id="chatbot-rate-limits" class="mxch-section">
550 <div class="mxch-content-header">
551 <h1 class="mxch-content-title"><?php esc_html_e('Rate Limits', 'mxchat'); ?></h1>
552 <p class="mxch-content-subtitle"><?php esc_html_e('Set message limits for each user role to manage API usage.', 'mxchat'); ?></p>
553 </div>
554
555 <div class="mxch-notice mxch-notice-info" style="margin-bottom: 24px;">
556 <svg class="mxch-notice-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"/><line x1="12" y1="16" x2="12" y2="12"/><line x1="12" y1="8" x2="12.01" y2="8"/></svg>
557 <div>
558 <strong><?php esc_html_e('Placeholders available:', 'mxchat'); ?></strong>
559 <code>{limit}</code>, <code>{timeframe}</code>, <code>{count}</code>, <code>{remaining}</code>
560 <br>
561 <strong><?php esc_html_e('Markdown links supported:', 'mxchat'); ?></strong>
562 <code>[Link text](https://example.com)</code>
563 </div>
564 </div>
565
566 <div class="mxch-card">
567 <div class="mxch-card-body mxchat-autosave-section">
568 <?php
569 // Render rate limits with accordion
570 mxchat_render_rate_limits_accordion($admin_instance);
571 ?>
572 </div>
573 </div>
574 </div>
575
576 <!-- ========================================
577 API KEYS
578 ======================================== -->
579 <div id="api-keys" class="mxch-section">
580 <div class="mxch-content-header">
581 <h1 class="mxch-content-title"><?php esc_html_e('API Keys', 'mxchat'); ?></h1>
582 <p class="mxch-content-subtitle"><?php esc_html_e('Manage API keys for AI providers and integrations.', 'mxchat'); ?></p>
583 </div>
584
585 <div class="mxch-card">
586 <div class="mxch-card-header">
587 <h3 class="mxch-card-title">
588 <svg class="mxch-card-title-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M12 8V4H8"/><rect width="16" height="12" x="4" y="8" rx="2"/><path d="M2 14h2"/><path d="M20 14h2"/><path d="M15 13v2"/><path d="M9 13v2"/></svg>
589 <?php esc_html_e('AI Providers', 'mxchat'); ?>
590 </h3>
591 </div>
592 <div class="mxch-card-body mxchat-autosave-section">
593 <table class="form-table">
594 <?php do_settings_fields('mxchat-api-keys', 'mxchat_api_keys_section'); ?>
595 </table>
596 </div>
597 </div>
598 </div>
599
600 <!-- ========================================
601 OPTIMIZATION
602 ======================================== -->
603 <div id="optimization" class="mxch-section">
604 <div class="mxch-content-header">
605 <h1 class="mxch-content-title"><?php esc_html_e('Optimization & Diagnostics', 'mxchat'); ?></h1>
606 <p class="mxch-content-subtitle"><?php esc_html_e('Optimize performance, debug issues, and manage plugin settings.', 'mxchat'); ?></p>
607 </div>
608
609 <!-- Script Loading Card -->
610 <div class="mxch-card">
611 <div class="mxch-card-header">
612 <h3 class="mxch-card-title">
613 <svg class="mxch-card-title-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M13 2L3 14h9l-1 8 10-12h-9l1-8z"/></svg>
614 <?php esc_html_e('Script Loading', 'mxchat'); ?>
615 </h3>
616 </div>
617 <div class="mxch-card-body mxchat-autosave-section">
618 <?php
619 $script_loading_strategy = isset($options['script_loading_strategy']) ? $options['script_loading_strategy'] : 'default';
620 ?>
621 <div class="mxch-field">
622 <label class="mxch-field-label"><?php esc_html_e('Script Loading Strategy', 'mxchat'); ?></label>
623 <div class="mxch-field-control">
624 <select name="mxchat_options[script_loading_strategy]" id="script_loading_strategy" class="mxch-select mxchat-autosave-field">
625 <option value="default" <?php selected($script_loading_strategy, 'default'); ?>><?php esc_html_e('Default (Immediate)', 'mxchat'); ?></option>
626 <option value="defer" <?php selected($script_loading_strategy, 'defer'); ?>><?php esc_html_e('Deferred', 'mxchat'); ?></option>
627 <option value="delay_1s" <?php selected($script_loading_strategy, 'delay_1s'); ?>><?php esc_html_e('Delay 1 Second', 'mxchat'); ?></option>
628 <option value="delay_3s" <?php selected($script_loading_strategy, 'delay_3s'); ?>><?php esc_html_e('Delay 3 Seconds', 'mxchat'); ?></option>
629 <option value="delay_5s" <?php selected($script_loading_strategy, 'delay_5s'); ?>><?php esc_html_e('Delay 5 Seconds', 'mxchat'); ?></option>
630 <option value="on_interaction" <?php selected($script_loading_strategy, 'on_interaction'); ?>><?php esc_html_e('On User Interaction', 'mxchat'); ?></option>
631 </select>
632 </div>
633 <p class="mxch-field-description"><?php esc_html_e('Control when the chatbot script loads to improve page performance.', 'mxchat'); ?></p>
634 </div>
635
636 <?php
637 // Smart asset loading (plan-915355; rebuilt on the house toggle
638 // pattern in plan-64d34f). Standalone option — never part of
639 // mxchat_options, so mxchat_sanitize() can't strip it.
640 mxchat_render_field_wrapper('mxchat_smart_asset_loading', __('Only load chatbot files on pages where the chatbot appears', 'mxchat'), function() use ($admin_instance) {
641 $admin_instance->mxchat_smart_asset_loading_toggle_callback();
642 }, __('Skips the chatbot\'s CSS and JavaScript on pages where the widget is hidden (per-page visibility, post type include/exclude, or auto-display disabled). Pages using the chatbot shortcode still load everything automatically. Helps with "reduce unused CSS/JS" audit findings.', 'mxchat'),
643 __('If your theme or page builder inserts the chatbot in an unusual way and it stops appearing, turn this off — or force-load assets with the mxchat_should_load_assets filter.', 'mxchat'));
644 ?>
645
646 <div class="mxch-notice mxch-notice-info" style="margin-top: 16px;">
647 <svg class="mxch-notice-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"/><line x1="12" y1="16" x2="12" y2="12"/><line x1="12" y1="8" x2="12.01" y2="8"/></svg>
648 <div>
649 <strong><?php esc_html_e('Loading Strategies:', 'mxchat'); ?></strong>
650 <ul style="margin: 8px 0 0 0; padding-left: 20px;">
651 <li><strong><?php esc_html_e('Default:', 'mxchat'); ?></strong> <?php esc_html_e('Script loads immediately in the footer. Best for sites where chat is critical.', 'mxchat'); ?></li>
652 <li><strong><?php esc_html_e('Deferred:', 'mxchat'); ?></strong> <?php esc_html_e('Script loads after HTML parsing completes. Good balance of performance and availability.', 'mxchat'); ?></li>
653 <li><strong><?php esc_html_e('Delay:', 'mxchat'); ?></strong> <?php esc_html_e('Script loads after a set delay. Helps improve LCP scores.', 'mxchat'); ?></li>
654 <li><strong><?php esc_html_e('On User Interaction:', 'mxchat'); ?></strong> <?php esc_html_e('Script loads when user scrolls, moves mouse, or touches screen. Best for Core Web Vitals but chat appears with slight delay.', 'mxchat'); ?></li>
655 </ul>
656 </div>
657 </div>
658 </div>
659 </div>
660
661 <!-- Page Cache Compatibility Card -->
662 <div class="mxch-card">
663 <div class="mxch-card-header">
664 <h3 class="mxch-card-title">
665 <svg class="mxch-card-title-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M21 16V8a2 2 0 0 0-1-1.73l-7-4a2 2 0 0 0-2 0l-7 4A2 2 0 0 0 3 8v8a2 2 0 0 0 1 1.73l7 4a2 2 0 0 0 2 0l7-4A2 2 0 0 0 21 16z"/><polyline points="3.27 6.96 12 12.01 20.73 6.96"/><line x1="12" y1="22.08" x2="12" y2="12"/></svg>
666 <?php esc_html_e('Page Cache Compatibility', 'mxchat'); ?>
667 </h3>
668 </div>
669 <div class="mxch-card-body">
670 <p class="mxch-field-description" style="margin-top: 0;"><?php esc_html_e('MxChat\'s chat send (and stream send, plus PDF / Word upload) all POST to /wp-admin/admin-ajax.php. Page-cache plugins occasionally cache those responses, which breaks the per-session nonce flow on the first message. MxChat auto-tells the five most common cache plugins to never cache chat AJAX via their own filter APIs — no setup needed for those. For other cache plugins (or Cloudflare APO), copy the manual exclusion string into your cache plugin\'s exclusion list.', 'mxchat'); ?></p>
671
672 <?php
673 $mxch_cache_rows = array(
674 array('name' => 'WP Rocket', 'state' => 'auto', 'exclusion' => '/wp-admin/admin-ajax\\.php\\?action=mxchat_.*'),
675 array('name' => 'LiteSpeed Cache', 'state' => 'auto', 'exclusion' => '/wp-admin/admin-ajax.php?action=mxchat_*'),
676 array('name' => 'W3 Total Cache', 'state' => 'auto', 'exclusion' => '/wp-admin/admin-ajax.php?action=mxchat_*'),
677 array('name' => 'FlyingPress', 'state' => 'auto', 'exclusion' => '/wp-admin/admin-ajax.php?action=mxchat_*'),
678 array('name' => 'WP Super Cache', 'state' => 'auto', 'exclusion' => 'wp-admin/admin-ajax.php'),
679 array('name' => 'Cloudflare APO', 'state' => 'manual', 'exclusion' => 'Page Rule / Cache Rule: URI Path contains "/wp-admin/admin-ajax.php" → Bypass Cache'),
680 );
681 ?>
682
683 <div class="mxch-cache-compat-grid" style="display: grid; grid-template-columns: 1fr; gap: 12px; margin-top: 16px;">
684 <?php foreach ($mxch_cache_rows as $row) :
685 $is_auto = ($row['state'] === 'auto');
686 $pill_class = $is_auto ? 'mxch-status-pill-active' : 'mxch-status-pill-warning';
687 $pill_label = $is_auto ? __('Auto-handled', 'mxchat') : __('Manual', 'mxchat');
688 ?>
689 <div class="mxch-cache-compat-row" style="display: flex; align-items: center; justify-content: space-between; gap: 12px; padding: 12px 14px; background: #f8fafc; border: 1px solid var(--mxch-card-border); border-radius: var(--mxch-radius-md);">
690 <div style="display: flex; align-items: center; gap: 10px; min-width: 0; flex: 0 0 auto;">
691 <span style="font-weight: 500;"><?php echo esc_html($row['name']); ?></span>
692 <span class="mxch-status-pill <?php echo esc_attr($pill_class); ?>">
693 <span class="mxch-status-dot"></span>
694 <?php echo esc_html($pill_label); ?>
695 </span>
696 </div>
697 <div style="display: flex; align-items: center; gap: 8px; flex: 1 1 auto; min-width: 0;">
698 <code style="background: #fff; border: 1px solid var(--mxch-card-border); padding: 4px 8px; border-radius: var(--mxch-radius-sm); font-size: 12px; color: var(--mxch-text-secondary); flex: 1 1 auto; overflow-x: auto; white-space: nowrap; min-width: 0;"><?php echo esc_html($row['exclusion']); ?></code>
699 <button type="button" class="mxch-btn mxch-btn-secondary mxch-btn-sm" data-mxch-copy="<?php echo esc_attr($row['exclusion']); ?>" style="flex: 0 0 auto;">
700 <?php esc_html_e('Copy', 'mxchat'); ?>
701 </button>
702 </div>
703 </div>
704 <?php endforeach; ?>
705 </div>
706
707 <div class="mxch-notice mxch-notice-info" style="margin-top: 16px;">
708 <svg class="mxch-notice-icon" xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="12" cy="12" r="10"/><line x1="12" y1="16" x2="12" y2="12"/><line x1="12" y1="8" x2="12.01" y2="8"/></svg>
709 <span><?php esc_html_e('Auto-handled plugins receive a filter from MxChat that excludes chat AJAX from their cache. Even so, having the exclusion in your own exclusion list is harmless and acts as a belt-and-suspenders guarantee.', 'mxchat'); ?></span>
710 </div>
711 </div>
712 </div>
713
714 <!-- Provider Reliability Card -->
715 <?php
716 $auto_retry_enabled = !isset($options['auto_retry_on_transient_error']) ||
717 (string) $options['auto_retry_on_transient_error'] !== '0';
718 ?>
719 <div class="mxch-card">
720 <div class="mxch-card-header">
721 <h3 class="mxch-card-title">
722 <svg class="mxch-card-title-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M21 12a9 9 0 1 1-6.219-8.56"/><polyline points="21 4 21 10 15 10"/></svg>
723 <?php esc_html_e('Provider Reliability', 'mxchat'); ?>
724 </h3>
725 <span class="mxch-status-pill <?php echo $auto_retry_enabled ? 'mxch-status-pill-active' : 'mxch-status-pill-disabled'; ?>">
726 <span class="mxch-status-dot"></span>
727 <?php echo $auto_retry_enabled ? esc_html__('Active', 'mxchat') : esc_html__('Disabled', 'mxchat'); ?>
728 </span>
729 </div>
730 <div class="mxch-card-body mxchat-autosave-section">
731 <div class="mxch-field">
732 <label class="mxch-field-label" for="auto_retry_on_transient_error">
733 <?php esc_html_e('Auto-retry on provider overload', 'mxchat'); ?>
734 </label>
735 <div class="mxch-field-control">
736 <label class="mxch-toggle">
737 <input type="checkbox"
738 id="auto_retry_on_transient_error"
739 name="mxchat_options[auto_retry_on_transient_error]"
740 class="mxchat-autosave-field"
741 value="1"
742 <?php checked($auto_retry_enabled); ?> />
743 <span class="mxch-toggle-slider"></span>
744 </label>
745 </div>
746 <p class="mxch-field-description"><?php esc_html_e('When the AI provider returns a transient error (rate-limit / overload / 429 / 503 / Gemini "model overloaded"), MxChat retries the chat-send up to twice before surfacing the error. Visitors see a brief pause instead of a raw provider error in the bot bubble.', 'mxchat'); ?></p>
747 <p class="mxch-field-hint"><?php esc_html_e('Configuration errors (invalid API key, 401/403/404/422) still surface immediately — never retried.', 'mxchat'); ?></p>
748 </div>
749 </div>
750 </div>
751
752 <!-- Debug Mode Card -->
753 <?php
754 $debug_mode = isset($options['debug_mode']) ? $options['debug_mode'] : 'off';
755 $debug_active = ($debug_mode === 'on');
756 ?>
757 <div class="mxch-card">
758 <div class="mxch-card-header">
759 <h3 class="mxch-card-title">
760 <svg class="mxch-card-title-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M12 22c5.523 0 10-4.477 10-10S17.523 2 12 2 2 6.477 2 12s4.477 10 10 10z"/><path d="m9 12 2 2 4-4"/></svg>
761 <?php esc_html_e('Debug Mode', 'mxchat'); ?>
762 </h3>
763 </div>
764 <div class="mxch-card-body">
765 <?php // Deliberate exception to the house .toggle-switch pattern
766 // (audited in plan-64d34f): this card-body is NOT an
767 // autosave section — the toggle saves through its own
768 // dedicated handler (mxchat_toggle_debug_mode, wired at
769 // mxchat-admin.js #mxchat_debug_mode) which appends its own
770 // save indicator inside this label. Converting the markup
771 // would orphan that indicator without touching the JS. ?>
772 <div class="mxch-field">
773 <label class="mxch-toggle">
774 <input type="checkbox" class="mxch-toggle-input" id="mxchat_debug_mode" name="mxchat_options[debug_mode]" value="on" <?php checked($debug_active); ?>>
775 <span class="mxch-toggle-switch"></span>
776 <span class="mxch-toggle-label"><?php esc_html_e('Enable Debug Logging', 'mxchat'); ?></span>
777 </label>
778 <p class="mxch-field-description"><?php esc_html_e('Tracks settings changes, knowledge base errors, API issues, and embedding failures. Enable only when troubleshooting. Max 100 entries stored.', 'mxchat'); ?></p>
779 </div>
780 </div>
781 </div>
782
783 <!-- Debug Log Viewer Card -->
784 <div class="mxch-card">
785 <div class="mxch-card-header" style="display: flex; justify-content: space-between; align-items: center;">
786 <h3 class="mxch-card-title">
787 <svg class="mxch-card-title-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"/><polyline points="14 2 14 8 20 8"/><line x1="16" y1="13" x2="8" y2="13"/><line x1="16" y1="17" x2="8" y2="17"/><polyline points="10 9 9 9 8 9"/></svg>
788 <?php esc_html_e('Debug Log', 'mxchat'); ?>
789 </h3>
790 <div style="display: flex; gap: 8px; align-items: center;">
791 <span id="mxchat-log-count" class="mxch-badge" style="display: none;"></span>
792 <button type="button" class="mxch-btn mxch-btn-secondary mxch-btn-sm" id="mxchat-refresh-log">
793 <svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M21.5 2v6h-6M2.5 22v-6h6M2 11.5a10 10 0 0 1 18.8-4.3M22 12.5a10 10 0 0 1-18.8 4.2"/></svg>
794 <?php esc_html_e('Refresh', 'mxchat'); ?>
795 </button>
796 <button type="button" class="mxch-btn mxch-btn-secondary mxch-btn-sm" id="mxchat-clear-log">
797 <svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="3 6 5 6 21 6"/><path d="M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6m3 0V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2"/></svg>
798 <?php esc_html_e('Clear', 'mxchat'); ?>
799 </button>
800 </div>
801 </div>
802 <div class="mxch-card-body">
803 <div id="mxchat-debug-log" class="mxchat-debug-log-viewer">
804 <div class="mxchat-debug-log-empty">
805 <svg xmlns="http://www.w3.org/2000/svg" width="48" height="48" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1" stroke-linecap="round" stroke-linejoin="round" style="opacity: 0.3;"><path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"/><polyline points="14 2 14 8 20 8"/></svg>
806 <p><?php esc_html_e('No log entries yet. Enable debug mode to start logging.', 'mxchat'); ?></p>
807 </div>
808 </div>
809 </div>
810 </div>
811
812 <!-- Settings Tools Card -->
813 <div class="mxch-card">
814 <div class="mxch-card-header">
815 <h3 class="mxch-card-title">
816 <svg class="mxch-card-title-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M14.7 6.3a1 1 0 0 0 0 1.4l1.6 1.6a1 1 0 0 0 1.4 0l3.77-3.77a6 6 0 0 1-7.94 7.94l-6.91 6.91a2.12 2.12 0 0 1-3-3l6.91-6.91a6 6 0 0 1 7.94-7.94l-3.76 3.76z"/></svg>
817 <?php esc_html_e('Settings Tools', 'mxchat'); ?>
818 </h3>
819 </div>
820 <div class="mxch-card-body">
821 <div class="mxch-tools-grid">
822 <!-- Export Settings -->
823 <div class="mxch-tool-item">
824 <div class="mxch-tool-icon">
825 <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"/><polyline points="7 10 12 15 17 10"/><line x1="12" y1="15" x2="12" y2="3"/></svg>
826 </div>
827 <div class="mxch-tool-content">
828 <h4><?php esc_html_e('Export Settings', 'mxchat'); ?></h4>
829 <p><?php esc_html_e('Download a JSON file of your current settings for backup or support. API keys are masked for security.', 'mxchat'); ?></p>
830 <button type="button" class="mxch-btn mxch-btn-secondary" id="mxchat-export-settings">
831 <svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"/><polyline points="7 10 12 15 17 10"/><line x1="12" y1="15" x2="12" y2="3"/></svg>
832 <?php esc_html_e('Export Settings', 'mxchat'); ?>
833 </button>
834 </div>
835 </div>
836
837 <!-- Reset All Settings -->
838 <div class="mxch-tool-item mxch-tool-item-danger">
839 <div class="mxch-tool-icon">
840 <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M3 6h18"/><path d="M19 6v14c0 1-1 2-2 2H7c-1 0-2-1-2-2V6"/><path d="M8 6V4c0-1 1-2 2-2h4c1 0 2 1 2 2v2"/><line x1="10" y1="11" x2="10" y2="17"/><line x1="14" y1="11" x2="14" y2="17"/></svg>
841 </div>
842 <div class="mxch-tool-content">
843 <h4><?php esc_html_e('Reset All Settings', 'mxchat'); ?></h4>
844 <p><?php esc_html_e('Reset all MxChat settings to their default values. This action cannot be undone.', 'mxchat'); ?></p>
845 <button type="button" class="mxch-btn mxch-btn-danger" id="mxchat-reset-settings">
846 <svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M3 6h18"/><path d="M19 6v14c0 1-1 2-2 2H7c-1 0-2-1-2-2V6"/></svg>
847 <?php esc_html_e('Reset All Settings', 'mxchat'); ?>
848 </button>
849 </div>
850 </div>
851 </div>
852 </div>
853 </div>
854
855 <!-- Reset Confirmation Modal -->
856 <div id="mxchat-reset-modal" class="mxch-modal" style="display: none;">
857 <div class="mxch-modal-backdrop"></div>
858 <div class="mxch-modal-content">
859 <div class="mxch-modal-header">
860 <h3><?php esc_html_e('Reset All Settings', 'mxchat'); ?></h3>
861 <button type="button" class="mxch-modal-close" id="mxchat-reset-modal-close">&times;</button>
862 </div>
863 <div class="mxch-modal-body">
864 <div class="mxch-notice mxch-notice-warning">
865 <svg class="mxch-notice-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M10.29 3.86L1.82 18a2 2 0 0 0 1.71 3h16.94a2 2 0 0 0 1.71-3L13.71 3.86a2 2 0 0 0-3.42 0z"/><line x1="12" y1="9" x2="12" y2="13"/><line x1="12" y1="17" x2="12.01" y2="17"/></svg>
866 <div>
867 <strong><?php esc_html_e('Warning: This action cannot be undone!', 'mxchat'); ?></strong>
868 <p><?php esc_html_e('All your MxChat settings including API keys, customizations, and configurations will be permanently deleted.', 'mxchat'); ?></p>
869 </div>
870 </div>
871 <div class="mxch-field" style="margin-top: 20px;">
872 <label class="mxch-field-label"><?php esc_html_e('Type RESET to confirm:', 'mxchat'); ?></label>
873 <input type="text" id="mxchat-reset-confirmation" class="mxch-input" placeholder="RESET" autocomplete="off">
874 </div>
875 </div>
876 <div class="mxch-modal-footer">
877 <button type="button" class="mxch-btn mxch-btn-secondary" id="mxchat-reset-cancel"><?php esc_html_e('Cancel', 'mxchat'); ?></button>
878 <button type="button" class="mxch-btn mxch-btn-danger" id="mxchat-reset-confirm" disabled><?php esc_html_e('Reset All Settings', 'mxchat'); ?></button>
879 </div>
880 </div>
881 </div>
882 </div>
883
884 <!-- ========================================
885 INTEGRATIONS - TOOLBAR
886 ======================================== -->
887 <div id="integrations-toolbar" class="mxch-section">
888 <div class="mxch-content-header">
889 <h1 class="mxch-content-title"><?php esc_html_e('Toolbar Settings', 'mxchat'); ?></h1>
890 <p class="mxch-content-subtitle"><?php esc_html_e('Configure the chat toolbar and document upload features.', 'mxchat'); ?></p>
891 </div>
892
893 <div class="mxch-card">
894 <div class="mxch-card-body mxchat-autosave-section">
895 <table class="form-table">
896 <?php do_settings_fields('mxchat-embed', 'mxchat_pdf_intent_section'); ?>
897 </table>
898 </div>
899 </div>
900 </div>
901
902 <!-- ========================================
903 INTEGRATIONS - LOOPS
904 ======================================== -->
905 <div id="integrations-loops" class="mxch-section">
906 <div class="mxch-content-header">
907 <h1 class="mxch-content-title"><?php esc_html_e('Loops Integration', 'mxchat'); ?></h1>
908 <p class="mxch-content-subtitle"><?php esc_html_e('Configure email capture with Loops for mailing list growth.', 'mxchat'); ?></p>
909 </div>
910
911 <div class="mxch-card">
912 <div class="mxch-card-body mxchat-autosave-section">
913 <table class="form-table">
914 <?php do_settings_fields('mxchat-embed', 'mxchat_loops_section'); ?>
915 </table>
916 </div>
917 </div>
918 </div>
919
920 <!-- ========================================
921 INTEGRATIONS - BRAVE SEARCH
922 ======================================== -->
923 <div id="integrations-brave" class="mxch-section">
924 <div class="mxch-content-header">
925 <h1 class="mxch-content-title"><?php esc_html_e('Brave Search', 'mxchat'); ?></h1>
926 <p class="mxch-content-subtitle"><?php esc_html_e('Configure Brave Search API for web search capabilities.', 'mxchat'); ?></p>
927 </div>
928
929 <div class="mxch-card">
930 <div class="mxch-card-body mxchat-autosave-section">
931 <table class="form-table">
932 <?php do_settings_fields('mxchat-embed', 'mxchat_brave_section'); ?>
933 </table>
934 </div>
935 </div>
936 </div>
937
938 <!-- ========================================
939 INTEGRATIONS - SLACK
940 ======================================== -->
941 <div id="integrations-slack" class="mxch-section">
942 <div class="mxch-content-header">
943 <h1 class="mxch-content-title"><?php esc_html_e('Slack', 'mxchat'); ?></h1>
944 <p class="mxch-content-subtitle"><?php esc_html_e('Connect your chatbot to Slack for live human support.', 'mxchat'); ?></p>
945 </div>
946
947 <div class="mxch-notice mxch-notice-info" style="margin-bottom: 24px;">
948 <svg class="mxch-notice-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"/><line x1="12" y1="16" x2="12" y2="12"/><line x1="12" y1="8" x2="12.01" y2="8"/></svg>
949 <div>
950 <?php printf(
951 esc_html__('Visit our %s for setup instructions.', 'mxchat'),
952 '<a href="https://mxchat.ai/documentation/mxchat-core#slack-live-agent-handoff" target="_blank">' . esc_html__('documentation page', 'mxchat') . '</a>'
953 ); ?>
954 </div>
955 </div>
956
957 <div class="mxch-card">
958 <div class="mxch-card-body mxchat-autosave-section">
959 <table class="form-table">
960 <?php do_settings_fields('mxchat-embed', 'mxchat_live_agent_section'); ?>
961 </table>
962 </div>
963 </div>
964
965 <div class="mxch-card" style="margin-top: 24px;">
966 <div class="mxch-card-header">
967 <h3 class="mxch-card-title">
968 <svg class="mxch-card-title-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M22 11.08V12a10 10 0 1 1-5.93-9.14"/><polyline points="22 4 12 14.01 9 11.01"/></svg>
969 <?php esc_html_e('Test Connection', 'mxchat'); ?>
970 </h3>
971 </div>
972 <div class="mxch-card-body">
973 <p class="mxch-field-description" style="margin-bottom: 16px;">
974 <?php esc_html_e('Test your Slack bot token to verify it has the required permissions. This will check if the bot can authenticate and create channels.', 'mxchat'); ?>
975 </p>
976 <button type="button" id="mxchat-test-slack-connection" class="mxch-btn mxch-btn-secondary">
977 <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="margin-right: 8px;"><path d="M22 11.08V12a10 10 0 1 1-5.93-9.14"/><polyline points="22 4 12 14.01 9 11.01"/></svg>
978 <?php esc_html_e('Test Slack Connection', 'mxchat'); ?>
979 </button>
980 <div id="mxchat-slack-test-result" style="margin-top: 16px; display: none;"></div>
981 </div>
982 </div>
983
984 <div class="mxch-card" style="margin-top: 24px;">
985 <div class="mxch-card-header">
986 <h3 class="mxch-card-title">
987 <svg class="mxch-card-title-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"/><line x1="12" y1="16" x2="12" y2="12"/><line x1="12" y1="8" x2="12.01" y2="8"/></svg>
988 <?php esc_html_e('Required OAuth Scopes', 'mxchat'); ?>
989 </h3>
990 </div>
991 <div class="mxch-card-body">
992 <p class="mxch-field-description" style="margin-bottom: 12px;">
993 <?php esc_html_e('Your Slack app needs these Bot Token Scopes (OAuth & Permissions > Scopes):', 'mxchat'); ?>
994 </p>
995 <div style="display: grid; grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); gap: 8px; background: #f8f9fa; padding: 16px; border-radius: 8px; font-family: monospace; font-size: 13px;">
996 <code style="background: #e9ecef; padding: 4px 8px; border-radius: 4px;">channels:manage</code>
997 <code style="background: #e9ecef; padding: 4px 8px; border-radius: 4px;">channels:read</code>
998 <code style="background: #e9ecef; padding: 4px 8px; border-radius: 4px;">chat:write</code>
999 <code style="background: #e9ecef; padding: 4px 8px; border-radius: 4px;">chat:write.public</code>
1000 <code style="background: #e9ecef; padding: 4px 8px; border-radius: 4px;">groups:write</code>
1001 <code style="background: #e9ecef; padding: 4px 8px; border-radius: 4px;">users:read</code>
1002 </div>
1003 <p class="mxch-field-description" style="margin-top: 12px;">
1004 <?php esc_html_e('After adding scopes, reinstall the app to your workspace.', 'mxchat'); ?>
1005 </p>
1006 </div>
1007 </div>
1008 </div>
1009
1010 <!-- ========================================
1011 INTEGRATIONS - TELEGRAM
1012 ======================================== -->
1013 <div id="integrations-telegram" class="mxch-section">
1014 <div class="mxch-content-header">
1015 <h1 class="mxch-content-title"><?php esc_html_e('Telegram', 'mxchat'); ?></h1>
1016 <p class="mxch-content-subtitle"><?php esc_html_e('Connect your chatbot to Telegram for live human support.', 'mxchat'); ?></p>
1017 </div>
1018
1019 <div class="mxch-notice mxch-notice-info" style="margin-bottom: 24px;">
1020 <svg class="mxch-notice-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"/><line x1="12" y1="16" x2="12" y2="12"/><line x1="12" y1="8" x2="12.01" y2="8"/></svg>
1021 <div>
1022 <?php esc_html_e('Telegram Live Agent requires a Telegram bot and a supergroup with forum topics enabled.', 'mxchat'); ?>
1023 <a href="https://mxchat.ai/documentation-bot/" target="_blank" style="margin-left: 5px;"><?php esc_html_e('Chat with our advanced doc bot for assistance setting up.', 'mxchat'); ?></a>
1024 </div>
1025 </div>
1026
1027 <div class="mxch-card">
1028 <div class="mxch-card-body mxchat-autosave-section">
1029 <table class="form-table">
1030 <?php do_settings_fields('mxchat-embed', 'mxchat_telegram_section'); ?>
1031 </table>
1032 </div>
1033 </div>
1034
1035 <div class="mxch-card" style="margin-top: 24px;">
1036 <div class="mxch-card-header">
1037 <h3 class="mxch-card-title">
1038 <svg class="mxch-card-title-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M14.7 6.3a1 1 0 0 0 0 1.4l1.6 1.6a1 1 0 0 0 1.4 0l3.77-3.77a6 6 0 0 1-7.94 7.94l-6.91 6.91a2.12 2.12 0 0 1-3-3l6.91-6.91a6 6 0 0 1 7.94-7.94l-3.76 3.76z"/></svg>
1039 <?php esc_html_e('Webhook Setup', 'mxchat'); ?>
1040 </h3>
1041 </div>
1042 <div class="mxch-card-body">
1043 <?php
1044 $telegram_bot_token = $options['telegram_bot_token'] ?? '';
1045 $telegram_webhook_secret = $options['telegram_webhook_secret'] ?? '';
1046 $webhook_url = rest_url('mxchat/v1/telegram-webhook');
1047 ?>
1048
1049 <p class="mxch-field-description" style="margin-bottom: 8px;">
1050 <strong><?php esc_html_e('Your Webhook URL:', 'mxchat'); ?></strong>
1051 </p>
1052 <div class="mxch-webhook-url-display" style="margin-bottom: 20px;">
1053 <code id="mxch-telegram-webhook-url"><?php echo esc_url($webhook_url); ?></code>
1054 <button type="button" class="mxch-btn mxch-btn-secondary mxch-btn-sm" onclick="navigator.clipboard.writeText(document.getElementById('mxch-telegram-webhook-url').textContent); this.textContent='Copied!'; setTimeout(() => this.textContent='Copy', 2000);">
1055 <?php esc_html_e('Copy', 'mxchat'); ?>
1056 </button>
1057 </div>
1058
1059 <?php if (!empty($telegram_bot_token)) : ?>
1060 <p class="mxch-field-description" style="margin-bottom: 8px;">
1061 <strong><?php esc_html_e('Register Webhook URL:', 'mxchat'); ?></strong><br>
1062 <?php esc_html_e('Copy and paste this URL into your browser to register the webhook with Telegram:', 'mxchat'); ?>
1063 </p>
1064 <?php
1065 $registration_url = 'https://api.telegram.org/bot' . $telegram_bot_token . '/setWebhook?url=' . urlencode($webhook_url);
1066 if (!empty($telegram_webhook_secret)) {
1067 $registration_url .= '&secret_token=' . urlencode($telegram_webhook_secret);
1068 }
1069 ?>
1070 <div class="mxch-webhook-url-display" style="margin-bottom: 12px;">
1071 <code id="mxch-telegram-registration-url" style="word-break: break-all; font-size: 12px;"><?php echo esc_url($registration_url); ?></code>
1072 <button type="button" class="mxch-btn mxch-btn-secondary mxch-btn-sm" onclick="navigator.clipboard.writeText(document.getElementById('mxch-telegram-registration-url').textContent); this.textContent='Copied!'; setTimeout(() => this.textContent='Copy', 2000);">
1073 <?php esc_html_e('Copy', 'mxchat'); ?>
1074 </button>
1075 </div>
1076 <p class="mxch-field-description" style="color: #22c55e;">
1077 <svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="vertical-align: middle; margin-right: 4px;"><path d="M22 11.08V12a10 10 0 1 1-5.93-9.14"/><polyline points="22 4 12 14.01 9 11.01"/></svg>
1078 <?php esc_html_e('You should see {"ok":true,"result":true,"description":"Webhook was set"} after visiting the URL.', 'mxchat'); ?>
1079 </p>
1080 <?php else : ?>
1081 <p class="mxch-field-description" style="color: #f59e0b;">
1082 <svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="vertical-align: middle; margin-right: 4px;"><path d="m21.73 18-8-14a2 2 0 0 0-3.48 0l-8 14A2 2 0 0 0 4 21h16a2 2 0 0 0 1.73-3Z"/><path d="M12 9v4"/><path d="M12 17h.01"/></svg>
1083 <?php esc_html_e('Enter your Bot Token above and save to generate the registration URL.', 'mxchat'); ?>
1084 </p>
1085 <?php endif; ?>
1086 </div>
1087 </div>
1088 </div>
1089
1090 <!-- ========================================
1091 TUTORIALS
1092 ======================================== -->
1093 <div id="tutorials" class="mxch-section">
1094 <div class="mxch-content-header">
1095 <h1 class="mxch-content-title"><?php esc_html_e('Video Tutorials', 'mxchat'); ?></h1>
1096 <p class="mxch-content-subtitle"><?php esc_html_e('Learn how to get the most out of MxChat with our video guides.', 'mxchat'); ?></p>
1097 </div>
1098
1099 <?php
1100 // Setup Guide — reopen the onboarding wizard (plan-347916, moved here from Display tab).
1101 // Only shows once the user has dismissed/graduated from the Onboarding page.
1102 if (function_exists('mxchat_onboarding_is_dismissed') && mxchat_onboarding_is_dismissed()):
1103 $auto_grad = function_exists('mxchat_onboarding_is_auto_graduated') && mxchat_onboarding_is_auto_graduated();
1104 ?>
1105 <div class="mxch-card mxch-onboarding-unhide-card" style="margin-bottom: 24px;">
1106 <div class="mxch-card-header">
1107 <h3 class="mxch-card-title">
1108 <svg class="mxch-card-title-icon" xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M22 10v6M2 10l10-5 10 5-10 5z"/><path d="M6 12v5c0 2 3 3 6 3s6-1 6-3v-5"/></svg>
1109 <?php esc_html_e('Setup Guide', 'mxchat'); ?>
1110 </h3>
1111 </div>
1112 <div class="mxch-card-body">
1113 <p style="margin:0 0 12px;color:var(--mxch-text-secondary);font-size:13px;line-height:1.5;">
1114 <?php if ($auto_grad): ?>
1115 <?php esc_html_e('You finished the setup guide. Reopen it any time to revisit the steps or change a setup choice.', 'mxchat'); ?>
1116 <?php else: ?>
1117 <?php esc_html_e('You hid the setup guide from the MxChat menu. Reopen it any time to revisit the steps.', 'mxchat'); ?>
1118 <?php endif; ?>
1119 </p>
1120 <form method="post" action="<?php echo esc_url(admin_url('admin-post.php')); ?>" style="margin:0;">
1121 <?php wp_nonce_field('mxchat_unhide_onboarding'); ?>
1122 <input type="hidden" name="action" value="mxchat_unhide_onboarding" />
1123 <button type="submit" class="mxch-btn mxch-btn-secondary mxch-btn-sm">
1124 <?php esc_html_e('Reopen setup guide', 'mxchat'); ?>
1125 </button>
1126 </form>
1127 </div>
1128 </div>
1129 <?php endif; ?>
1130
1131 <div class="mxch-card" style="margin-bottom: 24px;">
1132 <div class="mxch-card-body">
1133 <div style="display: flex; align-items: flex-start; gap: 16px;">
1134 <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="color: var(--mxch-warning); flex-shrink: 0;"><path d="m21.73 18-8-14a2 2 0 0 0-3.48 0l-8 14A2 2 0 0 0 4 21h16a2 2 0 0 0 1.73-3Z"/><path d="M12 9v4"/><path d="M12 17h.01"/></svg>
1135 <div>
1136 <h3 style="margin: 0 0 8px 0; font-size: 16px; font-weight: 600;"><?php esc_html_e('Need Help?', 'mxchat'); ?></h3>
1137 <p style="margin: 0 0 12px 0; color: var(--mxch-text-secondary);"><?php esc_html_e('If you\'re having trouble or believe something is not working as expected, please submit a support ticket.', 'mxchat'); ?></p>
1138 <a href="https://wordpress.org/support/plugin/mxchat-basic/" target="_blank" class="mxch-btn mxch-btn-secondary mxch-btn-sm">
1139 <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M14 9a2 2 0 0 1-2 2H6l-4 4V4c0-1.1.9-2 2-2h8a2 2 0 0 1 2 2v5Z"/><path d="M18 9h2a2 2 0 0 1 2 2v11l-4-4h-6a2 2 0 0 1-2-2v-1"/></svg>
1140 <?php esc_html_e('Submit Support Ticket', 'mxchat'); ?>
1141 </a>
1142 </div>
1143 </div>
1144 </div>
1145 </div>
1146
1147 <div class="mxch-tutorials-grid">
1148 <?php
1149 $tutorials = array(
1150 array(
1151 'title' => __('Quick Setup with MxChat', 'mxchat'),
1152 'description' => __('Learn how to quickly setup and understand how your chatbot works.', 'mxchat'),
1153 'url' => 'https://www.youtube.com/watch?v=3BqoiyWaQiM&t'
1154 ),
1155 array(
1156 'title' => __('AI Content Generation', 'mxchat'),
1157 'description' => __('Generate full blog posts and landing pages with AI—from prompt to publish in minutes.', 'mxchat'),
1158 'url' => 'https://www.youtube.com/watch?v=n8TeEeHpxs4'
1159 ),
1160 array(
1161 'title' => __('Chat With Your GSC Data', 'mxchat'),
1162 'description' => __('Find content gaps, quick win keywords, and SEO opportunities by chatting with your Google Search Console data using the Admin Assistant add-on.', 'mxchat'),
1163 'url' => 'https://www.youtube.com/watch?v=ytgMou_7SZA&t=2s'
1164 ),
1165 array(
1166 'title' => __('AI Theme Generator', 'mxchat'),
1167 'description' => __('Learn how to instantly restyle your chatbot using plain English prompts with real-time previews.', 'mxchat'),
1168 'url' => 'https://www.youtube.com/watch?v=rSQDW2qbtRU&t'
1169 ),
1170 array(
1171 'title' => __('MxChat Forms', 'mxchat'),
1172 'description' => __('Create and manage smart forms that automatically trigger during chat conversations.', 'mxchat'),
1173 'url' => 'https://www.youtube.com/watch?v=3MrWy5dRalA'
1174 ),
1175 array(
1176 'title' => __('Admin Assistant Add-on', 'mxchat'),
1177 'description' => __('Bring a ChatGPT-like experience directly inside your WordPress dashboard.', 'mxchat'),
1178 'url' => 'https://youtu.be/AdEA1k-UCFM'
1179 ),
1180 array(
1181 'title' => __('Chat Themes', 'mxchat'),
1182 'description' => __('Customize appearance with real-time previews to match your brand.', 'mxchat'),
1183 'url' => 'https://youtu.be/MfbB9mZi6ag'
1184 ),
1185 array(
1186 'title' => __('WooCommerce Integration', 'mxchat'),
1187 'description' => __('Provide product recommendations and shopping assistance to customers.', 'mxchat'),
1188 'url' => 'https://www.youtube.com/watch?v=WsqAppHRGdA'
1189 ),
1190 array(
1191 'title' => __('Knowledge Base Setup', 'mxchat'),
1192 'description' => __('Set up your knowledge base using PDFs, sitemaps, and manual entries.', 'mxchat'),
1193 'url' => 'https://www.youtube.com/watch?v=8Ztjs66-VTo'
1194 ),
1195 array(
1196 'title' => __('Document Chat', 'mxchat'),
1197 'description' => __('Chat with PDF and Word documents for enhanced document analysis.', 'mxchat'),
1198 'url' => 'https://www.youtube.com/watch?v=j_c45WWCTG0'
1199 ),
1200 array(
1201 'title' => __('Perplexity Integration', 'mxchat'),
1202 'description' => __('Enable real-time web search capabilities for your chatbot.', 'mxchat'),
1203 'url' => 'https://youtu.be/wpKkbt24-bo'
1204 ),
1205 array(
1206 'title' => __('Brave Search Intent', 'mxchat'),
1207 'description' => __('Leverage Brave Search for improved query understanding.', 'mxchat'),
1208 'url' => 'https://www.youtube.com/watch?v=7vDL5H7vToc'
1209 ),
1210 array(
1211 'title' => __('Loops Email Capture', 'mxchat'),
1212 'description' => __('Set up email capture with Loops to grow your mailing list.', 'mxchat'),
1213 'url' => 'https://www.youtube.com/watch?v=CNgm5TYDyTc'
1214 ),
1215 array(
1216 'title' => __('AI Agent Testing', 'mxchat'),
1217 'description' => __('Evaluate and improve your chatbot\'s performance and accuracy.', 'mxchat'),
1218 'url' => 'https://www.youtube.com/watch?v=A0jowbpyX54'
1219 ),
1220 );
1221
1222 foreach ($tutorials as $tutorial): ?>
1223 <div class="mxch-tutorial-card">
1224 <div class="mxch-tutorial-content">
1225 <h3 class="mxch-tutorial-title"><?php echo esc_html($tutorial['title']); ?></h3>
1226 <p class="mxch-tutorial-description"><?php echo esc_html($tutorial['description']); ?></p>
1227 <a href="<?php echo esc_url($tutorial['url']); ?>" target="_blank" rel="noopener" class="mxch-tutorial-link">
1228 <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polygon points="5 3 19 12 5 21 5 3"/></svg>
1229 <?php esc_html_e('Watch Tutorial', 'mxchat'); ?>
1230 </a>
1231 </div>
1232 </div>
1233 <?php endforeach; ?>
1234 </div>
1235 </div>
1236
1237 <!-- =====================================================
1238 TESTING SECTION
1239 ===================================================== -->
1240 <div id="testing" class="mxch-section">
1241 <div class="mxch-content-header">
1242 <h1 class="mxch-content-title"><?php esc_html_e('Testing', 'mxchat'); ?></h1>
1243 <p class="mxch-content-subtitle"><?php esc_html_e('Test your chatbot and inspect debug data in real time.', 'mxchat'); ?></p>
1244 </div>
1245
1246 <div class="mxch-testing-layout">
1247 <!-- Left Column: Debug Panel -->
1248 <div class="mxch-testing-debug-panel">
1249 <!-- Quick Actions -->
1250 <div class="mxch-card">
1251 <div class="mxch-card-body">
1252 <h3 class="mxch-testing-section-title"><?php esc_html_e('Quick Actions', 'mxchat'); ?></h3>
1253 <div class="mxch-testing-actions-row">
1254 <button type="button" class="mxch-testing-btn mxch-testing-btn-danger" id="mxch-testing-clear-session">
1255 <svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M3 6h18"/><path d="M19 6v14c0 1-1 2-2 2H7c-1 0-2-1-2-2V6"/><path d="M8 6V4c0-1 1-2 2-2h4c1 0 2 1 2 2v2"/></svg>
1256 <?php esc_html_e('Clear Chat Session', 'mxchat'); ?>
1257 </button>
1258 <button type="button" class="mxch-testing-btn mxch-testing-btn-secondary" id="mxch-testing-clear-debug">
1259 <svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M12 2v20M2 12h20"/></svg>
1260 <?php esc_html_e('Clear Debug Log', 'mxchat'); ?>
1261 </button>
1262 </div>
1263 </div>
1264 </div>
1265
1266 <!-- Last Query Analysis -->
1267 <div class="mxch-card">
1268 <div class="mxch-card-body">
1269 <h3 class="mxch-testing-section-title"><?php esc_html_e('Last Query Analysis', 'mxchat'); ?></h3>
1270
1271 <div class="mxch-testing-field">
1272 <label><?php esc_html_e('Similarity Threshold', 'mxchat'); ?></label>
1273 <span id="mxch-testing-threshold"><?php esc_html_e('Loading...', 'mxchat'); ?></span>
1274 </div>
1275
1276 <div class="mxch-testing-field">
1277 <label><?php esc_html_e('User Query', 'mxchat'); ?></label>
1278 <div id="mxch-testing-last-query" class="mxch-testing-query-display"><?php esc_html_e('Waiting for next query...', 'mxchat'); ?></div>
1279 </div>
1280
1281 <div class="mxch-testing-field">
1282 <label><?php esc_html_e('Approved URLs for Citations', 'mxchat'); ?></label>
1283 <div id="mxch-testing-approved-urls" class="mxch-testing-results">
1284 <div class="mxch-testing-no-data"><?php esc_html_e('No URL data yet', 'mxchat'); ?></div>
1285 </div>
1286 </div>
1287
1288 <div class="mxch-testing-field">
1289 <label><?php esc_html_e('Document Matches', 'mxchat'); ?></label>
1290 <div id="mxch-testing-similarity-scores" class="mxch-testing-results">
1291 <div class="mxch-testing-no-data"><?php esc_html_e('No query data yet', 'mxchat'); ?></div>
1292 </div>
1293 </div>
1294
1295 <div class="mxch-testing-field">
1296 <label><?php esc_html_e('Actions Triggered', 'mxchat'); ?></label>
1297 <div id="mxch-testing-action-scores" class="mxch-testing-results">
1298 <div class="mxch-testing-no-data"><?php esc_html_e('No action data yet', 'mxchat'); ?></div>
1299 </div>
1300 </div>
1301 </div>
1302 </div>
1303
1304 <!-- System Information -->
1305 <div class="mxch-card">
1306 <div class="mxch-card-body">
1307 <h3 class="mxch-testing-section-title"><?php esc_html_e('System Information', 'mxchat'); ?></h3>
1308
1309 <div class="mxch-testing-field">
1310 <label><?php esc_html_e('System Prompt', 'mxchat'); ?></label>
1311 <div id="mxch-testing-system-prompt" class="mxch-testing-system-prompt"><?php esc_html_e('Loading...', 'mxchat'); ?></div>
1312 </div>
1313
1314 <div class="mxch-testing-field">
1315 <label><?php esc_html_e('Knowledge Base', 'mxchat'); ?></label>
1316 <span id="mxch-testing-kb-status"><?php esc_html_e('Checking...', 'mxchat'); ?></span>
1317 </div>
1318 </div>
1319 </div>
1320
1321 <!-- Debug Log -->
1322 <div class="mxch-card">
1323 <div class="mxch-card-body">
1324 <h3 class="mxch-testing-section-title"><?php esc_html_e('Debug Log', 'mxchat'); ?></h3>
1325 <div id="mxch-testing-debug-console" class="mxch-testing-debug-console">
1326 <div class="mxch-testing-debug-entry"><?php esc_html_e('Debug panel ready - send a message to begin...', 'mxchat'); ?></div>
1327 </div>
1328 </div>
1329 </div>
1330 </div>
1331
1332 <!-- Right Column: Chatbot Replica -->
1333 <div class="mxch-testing-chatbot-column">
1334 <div class="mxch-testing-chatbot-scope">
1335 <?php
1336 // Render the chatbot inline for testing
1337 echo do_shortcode('[mxchat_chatbot floating="no" bot_id="testing"]');
1338 ?>
1339 </div>
1340 </div>
1341 </div>
1342 </div>
1343
1344 </main>
1345 </div>
1346
1347 <script>
1348 document.addEventListener('DOMContentLoaded', function() {
1349 // Sidebar navigation
1350 const navLinks = document.querySelectorAll('.mxch-nav-link, .mxch-nav-sub-link');
1351 const sections = document.querySelectorAll('.mxch-section');
1352 const navItems = document.querySelectorAll('.mxch-nav-item');
1353
1354 function showSection(target) {
1355 // Show target section
1356 sections.forEach(section => {
1357 section.classList.remove('active');
1358 if (section.id === target) {
1359 section.classList.add('active');
1360 }
1361 });
1362
1363 // Scroll content area to top
1364 const contentArea = document.querySelector('.mxch-content');
1365 if (contentArea) {
1366 contentArea.scrollTop = 0;
1367 }
1368 }
1369
1370 function setActiveNav(clickedLink) {
1371 // Remove active from all links
1372 navLinks.forEach(l => l.classList.remove('active'));
1373
1374 // Add active to clicked link
1375 clickedLink.classList.add('active');
1376
1377 // If clicking a sub-link, also highlight parent
1378 if (clickedLink.classList.contains('mxch-nav-sub-link')) {
1379 const parent = clickedLink.closest('.mxch-nav-item');
1380 if (parent) {
1381 parent.querySelector('.mxch-nav-link').classList.add('active');
1382 }
1383 }
1384 }
1385
1386 navLinks.forEach(link => {
1387 link.addEventListener('click', function(e) {
1388 e.preventDefault();
1389 e.stopPropagation();
1390 const target = this.dataset.target;
1391 const parentItem = this.closest('.mxch-nav-item');
1392 const hasSubmenu = parentItem && parentItem.querySelector('.mxch-nav-sub');
1393
1394 // If this is a parent nav link WITH children (expandable menu)
1395 if (this.classList.contains('mxch-nav-link') && hasSubmenu) {
1396 const wasExpanded = parentItem.classList.contains('expanded');
1397
1398 // Collapse all other expandable items
1399 navItems.forEach(item => {
1400 if (item !== parentItem && item.querySelector('.mxch-nav-sub')) {
1401 item.classList.remove('expanded');
1402 }
1403 });
1404
1405 // Toggle this item
1406 parentItem.classList.toggle('expanded');
1407
1408 // If expanding, show the first sub-item's content and mark it active
1409 if (!wasExpanded) {
1410 const firstSubLink = parentItem.querySelector('.mxch-nav-sub-link');
1411 if (firstSubLink) {
1412 const firstTarget = firstSubLink.dataset.target;
1413 showSection(firstTarget);
1414 setActiveNav(firstSubLink);
1415 // Also mark parent as active
1416 this.classList.add('active');
1417 history.replaceState(null, null, '#' + firstTarget);
1418 }
1419 }
1420 }
1421 // If this is a nav link WITHOUT children (like API Keys, Tutorials)
1422 else if (this.classList.contains('mxch-nav-link') && !hasSubmenu && target) {
1423 // Collapse all expandable items
1424 navItems.forEach(item => {
1425 if (item.querySelector('.mxch-nav-sub')) {
1426 item.classList.remove('expanded');
1427 }
1428 });
1429
1430 // Show the section
1431 showSection(target);
1432 setActiveNav(this);
1433 history.replaceState(null, null, '#' + target);
1434 }
1435 // If this is a sub-link
1436 else if (this.classList.contains('mxch-nav-sub-link') && target) {
1437 // Ensure parent stays expanded
1438 if (parentItem) {
1439 parentItem.classList.add('expanded');
1440 }
1441 showSection(target);
1442 setActiveNav(this);
1443 history.replaceState(null, null, '#' + target);
1444 }
1445 });
1446 });
1447
1448 // Handle initial deep-link (?tab=<slug> takes precedence over #hash so the
1449 // Onboarding setup-step CTAs land on the right sub-tab). Whitelist of valid
1450 // section ids must stay in sync with the .mxch-section[id] values above.
1451 const validTabs = [
1452 'chatbot-ai-models', 'chatbot-behavior', 'chatbot-display',
1453 'chatbot-lead-capture', 'chatbot-quick-questions', 'chatbot-rate-limits',
1454 'api-keys', 'optimization', 'testing',
1455 'integrations-toolbar', 'integrations-loops', 'integrations-brave',
1456 'integrations-slack', 'integrations-telegram',
1457 'tutorials'
1458 ];
1459 function activateTab(target) {
1460 if (!target) return false;
1461 if (validTabs.indexOf(target) === -1) return false;
1462 const targetLink = document.querySelector('[data-target="' + target + '"]');
1463 if (!targetLink) return false;
1464 const parentItem = targetLink.closest('.mxch-nav-item');
1465 if (parentItem && targetLink.classList.contains('mxch-nav-sub-link')) {
1466 parentItem.classList.add('expanded');
1467 }
1468 showSection(target);
1469 setActiveNav(targetLink);
1470 return true;
1471 }
1472 const urlParams = new URLSearchParams(window.location.search);
1473 const tabParam = urlParams.get('tab');
1474 let tabActivated = false;
1475 if (tabParam) {
1476 tabActivated = activateTab(tabParam);
1477 // Invalid ?tab=… silently falls through to default (#hash or AI Models).
1478 }
1479 if (!tabActivated) {
1480 const hash = window.location.hash.slice(1);
1481 if (hash) {
1482 activateTab(hash);
1483 }
1484 }
1485
1486 // Rate limit accordion
1487 const rateLimitHeaders = document.querySelectorAll('.mxch-rate-limit-header');
1488 rateLimitHeaders.forEach(header => {
1489 header.addEventListener('click', function(e) {
1490 e.preventDefault();
1491 e.stopPropagation();
1492 const item = this.closest('.mxch-rate-limit-item');
1493 item.classList.toggle('expanded');
1494 });
1495 });
1496
1497 // Rate-limit "Custom…" toggle: show/hide the integer input below each
1498 // limit <select> based on whether __custom__ is the active option.
1499 document.querySelectorAll('.mxch-rate-limit-limit-select').forEach(sel => {
1500 const targetId = sel.getAttribute('data-mxch-custom-target');
1501 if (!targetId) return;
1502 const field = document.querySelector('[data-mxch-custom-for="' + targetId + '"]');
1503 if (!field) return;
1504 const sync = () => {
1505 if (sel.value === '__custom__') {
1506 field.hidden = false;
1507 } else {
1508 field.hidden = true;
1509 }
1510 };
1511 sel.addEventListener('change', sync);
1512 sync();
1513 });
1514
1515 // =====================================================
1516 // Mobile Menu Functionality
1517 // =====================================================
1518 const mobileMenuBtn = document.querySelector('.mxch-mobile-menu-btn');
1519 const mobileMenuClose = document.querySelector('.mxch-mobile-menu-close');
1520 const mobileMenu = document.querySelector('.mxch-mobile-menu');
1521 const mobileOverlay = document.querySelector('.mxch-mobile-overlay');
1522 const mobileNavLinks = document.querySelectorAll('.mxch-mobile-nav-link, .mxch-mobile-nav-sub-link');
1523
1524 function openMobileMenu() {
1525 mobileMenu.classList.add('open');
1526 mobileOverlay.classList.add('open');
1527 document.body.style.overflow = 'hidden';
1528 }
1529
1530 function closeMobileMenu() {
1531 mobileMenu.classList.remove('open');
1532 mobileOverlay.classList.remove('open');
1533 document.body.style.overflow = '';
1534 }
1535
1536 if (mobileMenuBtn) {
1537 mobileMenuBtn.addEventListener('click', openMobileMenu);
1538 }
1539
1540 if (mobileMenuClose) {
1541 mobileMenuClose.addEventListener('click', closeMobileMenu);
1542 }
1543
1544 if (mobileOverlay) {
1545 mobileOverlay.addEventListener('click', closeMobileMenu);
1546 }
1547
1548 // Mobile navigation links
1549 mobileNavLinks.forEach(link => {
1550 link.addEventListener('click', function(e) {
1551 e.preventDefault();
1552 e.stopPropagation();
1553
1554 const target = this.dataset.target;
1555 const parentId = this.dataset.parent;
1556
1557 // If this is an expandable parent link
1558 if (parentId && !target) {
1559 const subNav = document.querySelector('.mxch-mobile-nav-sub[data-parent="' + parentId + '"]');
1560 if (subNav) {
1561 const isExpanded = subNav.classList.contains('expanded');
1562 // Collapse all sub navs
1563 document.querySelectorAll('.mxch-mobile-nav-sub').forEach(nav => {
1564 nav.classList.remove('expanded');
1565 });
1566 document.querySelectorAll('.mxch-mobile-nav-link').forEach(l => {
1567 l.classList.remove('expanded');
1568 });
1569 // Toggle this one
1570 if (!isExpanded) {
1571 subNav.classList.add('expanded');
1572 this.classList.add('expanded');
1573 }
1574 }
1575 }
1576 // If this is a direct link or sub-link with a target
1577 else if (target) {
1578 // Update mobile nav active state
1579 document.querySelectorAll('.mxch-mobile-nav-link, .mxch-mobile-nav-sub-link').forEach(l => {
1580 l.classList.remove('active');
1581 });
1582 this.classList.add('active');
1583
1584 // Also update desktop sidebar nav
1585 const desktopLink = document.querySelector('.mxch-sidebar [data-target="' + target + '"]');
1586 if (desktopLink) {
1587 setActiveNav(desktopLink);
1588 const parentItem = desktopLink.closest('.mxch-nav-item');
1589 if (parentItem && desktopLink.classList.contains('mxch-nav-sub-link')) {
1590 parentItem.classList.add('expanded');
1591 }
1592 }
1593
1594 // Show section and close menu
1595 showSection(target);
1596 history.replaceState(null, null, '#' + target);
1597 closeMobileMenu();
1598 }
1599 });
1600 });
1601
1602 // Close mobile menu on escape key
1603 document.addEventListener('keydown', function(e) {
1604 if (e.key === 'Escape' && mobileMenu && mobileMenu.classList.contains('open')) {
1605 closeMobileMenu();
1606 }
1607 });
1608 });
1609 </script>
1610 <?php
1611 }
1612
1613 /**
1614 * Helper function to render a field with consistent wrapper
1615 *
1616 * $hint renders as a .mxch-field-hint line under the description — the
1617 * softer "caveats / fine print" slot (added for plan-64d34f so hint-bearing
1618 * fields don't have to hand-roll the wrapper markup).
1619 */
1620 function mxchat_render_field_wrapper($id, $label, $callback, $description = '', $hint = '') {
1621 ?>
1622 <div class="mxch-field">
1623 <label class="mxch-field-label"><?php echo esc_html($label); ?></label>
1624 <div class="mxch-field-control">
1625 <?php $callback(); ?>
1626 </div>
1627 <?php if ($description): ?>
1628 <p class="mxch-field-description"><?php echo esc_html($description); ?></p>
1629 <?php endif; ?>
1630 <?php if ($hint): ?>
1631 <p class="mxch-field-hint"><?php echo esc_html($hint); ?></p>
1632 <?php endif; ?>
1633 </div>
1634 <?php
1635 }
1636
1637 /**
1638 * Render rate limits as collapsible accordion
1639 */
1640 function mxchat_render_rate_limits_accordion($admin_instance) {
1641 $all_options = get_option('mxchat_options', []);
1642 $rate_limits = array('1', '3', '5', '10', '15', '20', '50', '100', 'unlimited');
1643 $timeframes = array(
1644 'hourly' => __('Per Hour', 'mxchat'),
1645 'daily' => __('Per Day', 'mxchat'),
1646 'weekly' => __('Per Week', 'mxchat'),
1647 'monthly' => __('Per Month', 'mxchat')
1648 );
1649
1650 $roles = wp_roles()->get_names();
1651 $roles['logged_out'] = __('Logged Out Users', 'mxchat');
1652
1653 // Whole-chatbot global cap (sits above per-role; defaults to unlimited so
1654 // existing installs are unchanged). Stored under mxchat_options['rate_limits_global'].
1655 $global_cfg = isset($all_options['rate_limits_global']) && is_array($all_options['rate_limits_global'])
1656 ? $all_options['rate_limits_global']
1657 : array();
1658 $global_limit_raw = isset($global_cfg['limit']) ? (string) $global_cfg['limit'] : 'unlimited';
1659 $global_timeframe = isset($global_cfg['timeframe']) ? (string) $global_cfg['timeframe'] : 'daily';
1660 $global_is_unlimited = ($global_limit_raw === '' || $global_limit_raw === 'unlimited');
1661 $global_is_preset = !$global_is_unlimited && in_array($global_limit_raw, $rate_limits, true);
1662 $global_select_value = $global_is_unlimited ? 'unlimited' : ($global_is_preset ? $global_limit_raw : '__custom__');
1663 $global_custom_value = (!$global_is_unlimited && !$global_is_preset && ctype_digit($global_limit_raw))
1664 ? $global_limit_raw
1665 : '';
1666
1667 echo '<div class="mxch-rate-limits">';
1668
1669 // --- Global cap card -------------------------------------------------
1670 ?>
1671 <div class="mxch-rate-limit-item mxch-rate-limit-global mxchat-autosave-section">
1672 <div class="mxch-rate-limit-header">
1673 <span class="mxch-rate-limit-role"><?php esc_html_e('Total chatbot message limit', 'mxchat'); ?></span>
1674 <div class="mxch-rate-limit-summary">
1675 <span class="mxch-rate-limit-badge mxch-rate-limit-global-badge">
1676 <?php
1677 if ($global_is_unlimited) {
1678 esc_html_e('Unlimited', 'mxchat');
1679 } else {
1680 $tf_label = isset($timeframes[$global_timeframe]) ? $timeframes[$global_timeframe] : $global_timeframe;
1681 echo esc_html(($global_custom_value !== '' ? $global_custom_value : $global_limit_raw) . ' / ' . $tf_label);
1682 }
1683 ?>
1684 </span>
1685 <svg class="mxch-rate-limit-arrow" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="6 9 12 15 18 9"></polyline></svg>
1686 </div>
1687 </div>
1688 <div class="mxch-rate-limit-body">
1689 <p class="mxch-field-description" style="margin: 0 0 12px;">
1690 <?php esc_html_e('A single ceiling across all users and all roles, per timeframe. Independent of the per-role limits below. When both a per-role limit and this global cap are configured, whichever is hit first stops the conversation. Default is Unlimited — existing installs are unchanged.', 'mxchat'); ?>
1691 </p>
1692 <div class="mxch-rate-limit-controls">
1693 <div class="mxch-field">
1694 <label class="mxch-field-label" for="rate_limits_global_limit"><?php esc_html_e('Limit', 'mxchat'); ?></label>
1695 <select id="rate_limits_global_limit"
1696 name="mxchat_options[rate_limits_global][limit]"
1697 class="mxch-select mxchat-autosave-field mxch-rate-limit-limit-select"
1698 data-mxch-custom-target="rate_limits_global_limit_custom">
1699 <?php foreach ($rate_limits as $limit): ?>
1700 <option value="<?php echo esc_attr($limit); ?>" <?php selected($global_select_value, $limit); ?>>
1701 <?php echo esc_html($limit === 'unlimited' ? __('Unlimited', 'mxchat') : $limit); ?>
1702 </option>
1703 <?php endforeach; ?>
1704 <option value="__custom__" <?php selected($global_select_value, '__custom__'); ?>><?php esc_html_e('Custom…', 'mxchat'); ?></option>
1705 </select>
1706 </div>
1707 <div class="mxch-field mxch-rate-limit-custom-field" data-mxch-custom-for="rate_limits_global_limit_custom" <?php echo $global_select_value === '__custom__' ? '' : 'hidden'; ?>>
1708 <label class="mxch-field-label" for="rate_limits_global_limit_custom"><?php esc_html_e('Custom limit', 'mxchat'); ?></label>
1709 <input type="number"
1710 min="1"
1711 step="1"
1712 id="rate_limits_global_limit_custom"
1713 name="mxchat_options[rate_limits_global][limit_custom]"
1714 class="mxch-input mxchat-autosave-field mxch-rate-limit-custom-input"
1715 placeholder="e.g. 250"
1716 value="<?php echo esc_attr($global_custom_value); ?>" />
1717 </div>
1718 <div class="mxch-field">
1719 <label class="mxch-field-label" for="rate_limits_global_timeframe"><?php esc_html_e('Timeframe', 'mxchat'); ?></label>
1720 <select id="rate_limits_global_timeframe"
1721 name="mxchat_options[rate_limits_global][timeframe]"
1722 class="mxch-select mxchat-autosave-field">
1723 <?php foreach ($timeframes as $value => $label): ?>
1724 <option value="<?php echo esc_attr($value); ?>" <?php selected($global_timeframe, $value); ?>><?php echo esc_html($label); ?></option>
1725 <?php endforeach; ?>
1726 </select>
1727 </div>
1728 </div>
1729 <?php
1730 // --- Current usage readout (read-only; mirrors the integrator's
1731 // window-reset math at READ time — never writes the counter here).
1732 // v1 surfaces the DEFAULT bot's pool. TODO: per-bot selector if asked.
1733 $global_usage_limit_int = (!$global_is_unlimited && ctype_digit($global_limit_raw))
1734 ? (int) $global_limit_raw
1735 : 0;
1736 $usage_raw = get_option('mxchat_chat_limit_default_global', array('count' => 0, 'timestamp' => time()));
1737 $usage_count = isset($usage_raw['count']) ? (int) $usage_raw['count'] : 0;
1738 $usage_ts = isset($usage_raw['timestamp']) ? (int) $usage_raw['timestamp'] : time();
1739 $usage_windows = array('hourly' => 3600, 'daily' => 86400, 'weekly' => 604800, 'monthly' => 2592000);
1740 $usage_window = isset($usage_windows[$global_timeframe]) ? $usage_windows[$global_timeframe] : 86400;
1741 $usage_now = time();
1742 if (($usage_now - $usage_ts) >= $usage_window) {
1743 // Window elapsed since the stored timestamp → effective count is 0.
1744 $usage_count = 0;
1745 $usage_reset_at = $usage_now + $usage_window;
1746 } else {
1747 $usage_reset_at = $usage_ts + $usage_window;
1748 }
1749 $usage_left = max(0, $global_usage_limit_int - $usage_count);
1750 $usage_pct = ($global_usage_limit_int > 0)
1751 ? min(100, (int) round(($usage_count / $global_usage_limit_int) * 100))
1752 : 0;
1753 $usage_reset_nonce = wp_create_nonce('mxchat_reset_global_usage');
1754 ?>
1755 <div class="mxch-rate-limit-usage"
1756 id="mxch-global-usage"
1757 data-bot-id="default"
1758 data-reset-nonce="<?php echo esc_attr($usage_reset_nonce); ?>"
1759 <?php echo $global_is_unlimited ? 'hidden' : ''; ?>>
1760 <div class="mxch-rate-limit-usage-head">
1761 <span class="mxch-field-label" style="margin:0;"><?php esc_html_e('Current usage', 'mxchat'); ?></span>
1762 <button type="button" class="mxch-btn mxch-btn-secondary mxch-btn-sm" id="mxch-global-usage-reset"><?php esc_html_e('Reset counter', 'mxchat'); ?></button>
1763 </div>
1764 <div class="mxch-progress-bar">
1765 <div class="mxch-progress-bar-fill" id="mxch-global-usage-fill" style="width: <?php echo esc_attr($usage_pct); ?>%;"></div>
1766 </div>
1767 <p class="mxch-progress-label" id="mxch-global-usage-text" style="margin:0;">
1768 <?php
1769 printf(
1770 /* translators: 1: used count, 2: limit, 3: remaining, 4: human-readable time until reset */
1771 esc_html__('%1$s of %2$s used · %3$s left · resets in %4$s', 'mxchat'),
1772 esc_html(number_format_i18n($usage_count)),
1773 esc_html(number_format_i18n($global_usage_limit_int)),
1774 esc_html(number_format_i18n($usage_left)),
1775 esc_html(human_time_diff($usage_now, $usage_reset_at))
1776 );
1777 ?>
1778 </p>
1779 </div>
1780 <p class="mxch-field-description mxch-rate-limit-usage-unlimited"
1781 id="mxch-global-usage-unlimited"
1782 style="margin: 12px 0 0;"
1783 <?php echo $global_is_unlimited ? '' : 'hidden'; ?>>
1784 <?php esc_html_e('Unlimited — no cap. Usage tracking applies only when a numeric limit is set.', 'mxchat'); ?>
1785 </p>
1786 </div>
1787 </div>
1788 <?php
1789 // ---------------------------------------------------------------------
1790
1791 foreach ($roles as $role_id => $role_name) {
1792 $default_limit = ($role_id === 'logged_out') ? '10' : '100';
1793 $default_timeframe = 'daily';
1794 $default_message = __('Rate limit exceeded. Please try again later.', 'mxchat');
1795
1796 $selected_limit = isset($all_options['rate_limits'][$role_id]['limit'])
1797 ? (string) $all_options['rate_limits'][$role_id]['limit']
1798 : $default_limit;
1799
1800 $selected_timeframe = isset($all_options['rate_limits'][$role_id]['timeframe'])
1801 ? $all_options['rate_limits'][$role_id]['timeframe']
1802 : $default_timeframe;
1803
1804 $custom_message = isset($all_options['rate_limits'][$role_id]['message'])
1805 ? $all_options['rate_limits'][$role_id]['message']
1806 : $default_message;
1807
1808 $timeframe_label = isset($timeframes[$selected_timeframe]) ? $timeframes[$selected_timeframe] : $selected_timeframe;
1809
1810 // Custom-value handling: if the stored limit is not in the preset list
1811 // and not 'unlimited', it's a custom integer. The select shows __custom__
1812 // and the number input below carries the actual value.
1813 $is_preset_limit = in_array($selected_limit, $rate_limits, true);
1814 $role_select_value = $is_preset_limit ? $selected_limit : '__custom__';
1815 $role_custom_value = (!$is_preset_limit && ctype_digit($selected_limit)) ? $selected_limit : '';
1816 $custom_field_id = 'rate_limits_' . $role_id . '_limit_custom';
1817 ?>
1818 <div class="mxch-rate-limit-item">
1819 <div class="mxch-rate-limit-header">
1820 <span class="mxch-rate-limit-role"><?php echo esc_html($role_name); ?></span>
1821 <div class="mxch-rate-limit-summary">
1822 <span class="mxch-rate-limit-badge"><?php echo esc_html($selected_limit . ' / ' . $timeframe_label); ?></span>
1823 <svg class="mxch-rate-limit-arrow" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="6 9 12 15 18 9"></polyline></svg>
1824 </div>
1825 </div>
1826 <div class="mxch-rate-limit-body mxchat-autosave-section">
1827 <div class="mxch-rate-limit-controls">
1828 <div class="mxch-field">
1829 <label class="mxch-field-label" for="rate_limits_<?php echo esc_attr($role_id); ?>_limit"><?php esc_html_e('Limit', 'mxchat'); ?></label>
1830 <select id="rate_limits_<?php echo esc_attr($role_id); ?>_limit"
1831 name="mxchat_options[rate_limits][<?php echo esc_attr($role_id); ?>][limit]"
1832 class="mxch-select mxchat-autosave-field mxch-rate-limit-limit-select"
1833 data-mxch-custom-target="<?php echo esc_attr($custom_field_id); ?>">
1834 <?php foreach ($rate_limits as $limit): ?>
1835 <option value="<?php echo esc_attr($limit); ?>" <?php selected($role_select_value, $limit); ?>>
1836 <?php echo esc_html($limit === 'unlimited' ? __('Unlimited', 'mxchat') : $limit); ?>
1837 </option>
1838 <?php endforeach; ?>
1839 <option value="__custom__" <?php selected($role_select_value, '__custom__'); ?>><?php esc_html_e('Custom…', 'mxchat'); ?></option>
1840 </select>
1841 </div>
1842 <div class="mxch-field mxch-rate-limit-custom-field" data-mxch-custom-for="<?php echo esc_attr($custom_field_id); ?>" <?php echo $role_select_value === '__custom__' ? '' : 'hidden'; ?>>
1843 <label class="mxch-field-label" for="<?php echo esc_attr($custom_field_id); ?>"><?php esc_html_e('Custom limit', 'mxchat'); ?></label>
1844 <input type="number"
1845 min="1"
1846 step="1"
1847 id="<?php echo esc_attr($custom_field_id); ?>"
1848 name="mxchat_options[rate_limits][<?php echo esc_attr($role_id); ?>][limit_custom]"
1849 class="mxch-input mxchat-autosave-field mxch-rate-limit-custom-input"
1850 placeholder="e.g. 250"
1851 value="<?php echo esc_attr($role_custom_value); ?>" />
1852 </div>
1853 <div class="mxch-field">
1854 <label class="mxch-field-label" for="rate_limits_<?php echo esc_attr($role_id); ?>_timeframe"><?php esc_html_e('Timeframe', 'mxchat'); ?></label>
1855 <select id="rate_limits_<?php echo esc_attr($role_id); ?>_timeframe"
1856 name="mxchat_options[rate_limits][<?php echo esc_attr($role_id); ?>][timeframe]"
1857 class="mxch-select mxchat-autosave-field">
1858 <?php foreach ($timeframes as $value => $label): ?>
1859 <option value="<?php echo esc_attr($value); ?>" <?php selected($selected_timeframe, $value); ?>><?php echo esc_html($label); ?></option>
1860 <?php endforeach; ?>
1861 </select>
1862 </div>
1863 </div>
1864 <div class="mxch-field">
1865 <label class="mxch-field-label" for="rate_limits_<?php echo esc_attr($role_id); ?>_message"><?php esc_html_e('Custom Message', 'mxchat'); ?></label>
1866 <textarea id="rate_limits_<?php echo esc_attr($role_id); ?>_message"
1867 name="mxchat_options[rate_limits][<?php echo esc_attr($role_id); ?>][message]"
1868 class="mxch-textarea mxchat-autosave-field"
1869 rows="2"
1870 placeholder="<?php esc_attr_e('Message shown when rate limit is reached', 'mxchat'); ?>"><?php echo esc_textarea($custom_message); ?></textarea>
1871 </div>
1872 </div>
1873 </div>
1874 <?php
1875 }
1876
1877 echo '</div>';
1878 }
1879