PluginProbe
FormLayer / trunk
FormLayer vtrunk
1.0.9 1.0.8 1.0.7 1.0.6 trunk 1.0.3 1.0.4 1.0.5
formlayer / main / settings / ui.php

ui.php in FormLayer trunk, at main/settings/ui.php

748 lines 33.7 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 namespace FormLayer\Settings;
3
4 if(!defined('ABSPATH')){
5 exit;
6 }
7
8 class UI{
9
10 static function header(){
11 echo '<div class="formlayer-admin-wrapper">
12 <header class="formlayer-admin-header main-header-sticky">
13 <div class="formlayer-header-left">
14 <div class="formlayer-sidebar-logo" style="padding: 0; margin-right: 25px; border: none; background: none;">
15 <div class="formlayer-logo-icon">
16 <img alt="' . esc_html__('FormLayer logo', 'formlayer') . '" height="52" src="' . esc_url(FORMLAYER_ASSETS_URL) . '/img/formlayer-logo.png' . '" width="58" style="filter: drop-shadow(0 4px 6px rgba(0,0,0,0.05));"/>
17 </div>
18 </div>
19
20 <nav class="formlayer-header-tabs glass-tabs" id="formlayer-main-nav">';
21
22 self::tab_item('forms', 'Forms', '<span class="dashicons dashicons-feedback"></span>');
23 self::tab_item('formbuilder', 'Form Builder', '<span class="dashicons dashicons-welcome-add-page"></span>');
24
25 if(defined('FORMLAYER_PRO_VERSION')){
26 $unread = \FormLayerPro\Util::get_unread_count();
27 $unread_badge = $unread > 0 ? ' <span class="formlayer-unread-count formlayer-unread-badge">' . $unread . '</span>' : '';
28 } else {
29 $unread_badge = '';
30 }
31
32 self::tab_item('entries', 'Entries' . $unread_badge, '<span class="dashicons dashicons-database-view"></span>');
33 self::tab_item('reports', 'Reports', '<span class="dashicons dashicons-chart-bar"></span>');
34 self::tab_item('integrations', 'Integrations', '<span class="dashicons dashicons-admin-links"></span>');
35 self::tab_item('tools', 'Tools', '<span class="dashicons dashicons-migrate"></span>');
36 self::tab_item('settings', 'Settings', '<span class="dashicons dashicons-admin-settings"></span>');
37 self::tab_item('support', 'Support', '<span class="dashicons dashicons-sos"></span>');
38 if (defined('FORMLAYER_PRO_VERSION')) {
39 self::tab_item('license', 'License', '<span class="dashicons dashicons-admin-network"></span>');
40 }
41
42 echo '</nav>
43 </div>
44 <div class="formlayer-header-right">
45 <div class="formlayer-header-version-badge">v' . esc_html(FORMLAYER_VERSION) . '</div>
46 </div>
47 </header>
48 <main class="formlayer-admin-main-content">';
49 }
50
51 static function tab_item($slug, $label, $icon){
52 $url = '#' . $slug;
53 echo '<a href="' . esc_url($url) . '" class="formlayer-tab-item" data-tab="' . esc_attr($slug) . '">' . wp_kses_post($icon) . '<span>' . wp_kses_post($label) . '</span></a>';
54 }
55
56 static function forms_tab(){
57 $forms = get_posts([
58 'post_type' => 'formlayer_form',
59 'posts_per_page' => -1,
60 'post_status' => 'any'
61 ]);
62
63 $count = is_array($forms) ? count($forms) : 0;
64
65
66 echo '<div class="formlayer-table-card">
67 <div class="formlayer-table-card-header">
68 <div class="formlayer-bulk-action-wrap">
69 <select id="formlayer-bulk-action" class="formlayer-select formlayer-select-compact">
70 <option value="">' . esc_html__('Bulk Actions', 'formlayer') . '</option>
71 <option value="delete">' . esc_html__('Delete Permanently', 'formlayer') . '</option>
72 </select>
73 <button id="formlayer-apply-bulk" class="formlayer-btn formlayer-btn-outline">' . esc_html__('Apply', 'formlayer') . '</button>
74 </div>
75 <a href="#formbuilder" id="formlayer-add-new-form" class="formlayer-btn formlayer-btn-primary">+ ' . esc_html__('Add New Form', 'formlayer') . '</a>
76 </div>
77
78 <div style="padding: 0 32px 32px 32px;">
79 <table class="formlayer-table">
80 <thead>
81 <tr>
82 <th style="width:40px;"><input type="checkbox" id="formlayer-select-all"></th>
83 <th>'.esc_html__('Name', 'formlayer') . '</th>
84 <th>'.esc_html__('Last Modified', 'formlayer') . '</th>
85 <th>'.esc_html__('Shortcode', 'formlayer') . '</th>
86 <th>'.esc_html__('Actions', 'formlayer') . '</th>
87 </tr>
88 </thead>
89 <tbody>';
90
91 if(empty($forms)){
92 echo '<tr>
93 <td colspan="7" style="text-align:center; padding:60px 0; color:var(--formlayer-text-muted);">
94 <div class="formlayer-empty-title">' . esc_html__('No forms found', 'formlayer') . '</div>
95 <p style="margin:0;">' . esc_html__('Create your first form to start collecting data.', 'formlayer') . '</p>
96 </td>
97 </tr>';
98
99 } else {
100 foreach ($forms as $form) {
101 self::render_form_row($form);
102 }
103 }
104
105 echo '</tbody>
106 </table>
107 </div>
108 </div>';
109 }
110
111 static function formbuilder_tab(){
112 echo '<div id="formlayer-formbuilder-app">
113 <!-- Templates View (Hidden by default or shown based on state) -->
114 <div id="formlayer-templates-view" style="display:none;">
115 <div class="formlayer-templates-wrapper">
116 <div class="formlayer-templates-sidebar">
117 <h3>' . esc_html__('Categories', 'formlayer') . '</h3>
118 <ul class="formlayer-template-cats" id="formlayer-template-cats-list">
119 <!-- Populated by JS -->
120 </ul>
121 </div>
122 <div class="formlayer-templates-main">
123 <div class="formlayer-templates-header">
124 <div class="formlayer-templates-header-row">
125 <div>
126 <h3>' . esc_html__('Select a Template', 'formlayer') . '</h3>
127 <p style="margin: 0;">' . esc_html__('Choose a base to start from or build a custom form from scratch.', 'formlayer') . '</p>
128 </div>
129 <div class="formlayer-template-search-wrapper" style="width: 300px; position: relative;">
130 <input type="text" id="formlayer-template-search" class="formlayer-input formlayer-template-search-input" placeholder="' . esc_attr__('Search templates...', 'formlayer') . '">
131 </div>
132 </div>
133 </div>
134 <div class="formlayer-templates-grid" id="formlayer-templates-grid">
135 <!-- Populated by JS -->
136 </div>
137 </div>
138 </div>
139 </div>
140
141 <!-- Builder View -->
142 <div id="formlayer-builder-view" style="display:none;">
143 <div class="formlayer-builder-wrapper">
144 <div class="formlayer-builder-card">
145 <div class="formlayer-builder-header-info formlayer-builder-header-info-wrap">
146 <button class="formlayer-btn-back-templates">
147 <span class="dashicons dashicons-arrow-left-alt2"></span>
148 ' . esc_html__('Back', 'formlayer') . '
149 </button>
150 <div class="formlayer-title-edit-wrapper formlayer-title-edit-container">
151 <h2 id="formlayer-builder-title">' . esc_html__('Untitled Form', 'formlayer') . '</h2>
152 <input type="text" id="formlayer-builder-title-input" class="formlayer-builder-title-input-el">
153 <span class="dashicons dashicons-edit" id="formlayer-edit-title-btn" style="color: #94a3b8; cursor: pointer; font-size: 18px; margin-top: 2px;"></span>
154 </div>
155 <div class="info-right formlayer-builder-info-right">
156 <button id="formlayer-btn-form-settings" class="formlayer-btn formlayer-btn-outline" style="display: flex; align-items: center; gap: 8px;">
157 <span class="dashicons dashicons-admin-settings" style="font-size: 16px; width: 16px; height: 16px; margin-top: 2px;"></span>
158 ' . esc_html__('Form Settings', 'formlayer') . '
159 </button>
160
161 <div class="formlayer-shortcode-box">
162 <div style="margin-right: 15px;">
163 <input type="text" value="" readonly id="formlayer-shortcode-val" > </div>
164 <button class="formlayer-copy-shortcode">
165 <span class="dashicons dashicons-admin-page" style="font-size: 18px; width: 18px; height: 18px; color: #64748b;"></span>' . esc_html__('Copy', 'formlayer') . '
166 </button>
167 <button type="button" class="formlayer-fullscreen-toggle formlayer-fullscreen-toggle-btn" title="' . esc_attr__('Toggle Fullscreen', 'formlayer') . '">
168 <span class="dashicons dashicons-fullscreen-alt" style="font-size: 20px; width: 20px; height: 20px; color: #64748b;"></span>
169 </button>
170 </div>
171
172 <div class="formlayer-builder-action-bar">
173 <div class="action-right">
174 <a href="#forms" class="formlayer-btn-all-forms btn-primary">
175 ' . esc_html__('All Forms', 'formlayer') . '
176 </a>
177 <button class="formlayer-btn-save btn-primary ">
178 ' . esc_html__('Save Form', 'formlayer') . '
179 </button>
180 </div>
181 </div>
182 </div>
183 </div>
184
185 <div class="formlayer-builder-main">
186 <div class="formlayer-preview-column">
187 <div class="formlayer-preview-container">
188 <div class="formlayer-preview-header">
189 <div class="formlayer-device-toggles">
190 <button class="formlayer-device-btn active" data-device="desktop"><span class="dashicons dashicons-desktop"></span></button>
191 <button class="formlayer-device-btn" data-device="tablet"><span class="dashicons dashicons-tablet"></span></button>
192 <button class="formlayer-device-btn" data-device="mobile"><span class="dashicons dashicons-smartphone"></span></button>
193 </div>
194 </div>
195 <div class="formlayer-canvas-wrapper">
196 <div class="formlayer-builder-canvas">
197 <div class="formlayer-canvas-inner">
198 <div class="formlayer-dropzone" id="formlayer-dropzone">
199 <!-- Fields rendered by JS -->
200 </div>
201 </div>
202 </div>
203 </div>
204 </div>
205 </div>
206
207 <div class="formlayer-sidebar-column">
208 <div class="formlayer-sidebar-tabs">
209 <button class="formlayer-sidebar-tab active" data-tab="input-fields">
210 ' . esc_html__('General', 'formlayer') . '
211 </button>
212 <button class="formlayer-sidebar-tab" data-tab="input-customization">
213 ' . esc_html__('Advanced', 'formlayer') . '
214 </button>
215 </div>
216
217 <div class="formlayer-sidebar-panes">
218 <div class="formlayer-sidebar-pane active" id="formlayer-pane-fields">
219 <div class="formlayer-search-wrapper">
220 <span class="dashicons dashicons-search"></span>
221 <input type="text" class="formlayer-fields-search" placeholder="' . esc_attr__('Search (press / to focus)', 'formlayer') . '">
222 </div>
223 <div class="formlayer-categories" id="formlayer-builder-categories">
224 <!-- Categories and fields by JS -->
225 </div>
226 </div>
227
228 <div class="formlayer-sidebar-pane" id="formlayer-pane-customization">
229 <!-- Customization form by JS -->
230 </div>
231 </div>
232 </div>
233 </div>
234 </div>
235 </div>
236 </div>
237 </div>';
238 }
239
240 static function render_form_row($post){
241
242 $display_id = get_post_meta($post->ID, '_formlayer_display_id', true);
243 if (!$display_id) {
244 $counter = get_option('formlayer_id_counter', 0);
245 $counter++;
246 update_option('formlayer_id_counter', $counter);
247 update_post_meta($post->ID, '_formlayer_display_id', $counter);
248 $display_id = $counter;
249 }
250
251 $shortcode = '[formlayer id="' . $display_id . '"]';
252 $time = human_time_diff(get_the_modified_time('U', $post->ID), current_time('timestamp')) . ' ago';
253
254
255 echo '<tr>
256 <td><input type="checkbox" class="formlayer-row-cb" value="' . esc_attr($display_id) . '"></td>
257 <td>
258 <div style="font-weight:600;">' . esc_html(get_the_title($post->ID)) . '</div>
259 </td>
260 <td>' . esc_html($time) . '</td>
261 <td>
262 <code style="background:#f1f5f9; padding:4px 8px; border-radius:4px; font-size:12px;">' . esc_html($shortcode) . '</code>
263 </td>
264 <td>
265 <div style="display:flex; gap:12px; color:var(--formlayer-text-muted);">
266 <a href="#" class="formlayer-copy-shortcode-list" data-shortcode="' . esc_attr($shortcode) . '" title="Copy Shortcode" style="color:inherit; cursor:pointer;">
267 <span class="dashicons dashicons-admin-page"></span>
268 </a>
269 <a href="' . esc_url(admin_url('admin.php?page=formlayer&tab=formbuilder&form_id=' . $display_id)) . '" class="formlayer-action-btns" title="Edit" style="color:inherit;">
270 <span class="dashicons dashicons-edit"></span>
271 </a>
272 <a href="#" class="formlayer-delete-form" data-form-id="' . esc_attr($display_id) . '" title="Delete" style="color:inherit; cursor:pointer;">
273 <span class="dashicons dashicons-trash"></span>
274 </a>
275 </div>
276 </td>
277 </tr>';
278 }
279
280 static function entries_tab(){
281
282 if (defined('FORMLAYER_PRO_VERSION')) {
283 do_action('formlayer_render_entries_tab');
284 } else {
285 self::pro_placeholder_page();
286 }
287 }
288
289 static function reports_tab(){
290
291 if(defined('FORMLAYER_PRO_VERSION')){
292 do_action('formlayer_render_reports_tab');
293 } else {
294 self::pro_placeholder_page();
295 }
296 }
297
298 static function integrations_tab(){
299
300 if (defined('FORMLAYER_PRO_VERSION')) {
301 do_action('formlayer_render_integrations');
302 } else {
303 self::pro_placeholder_page();
304 }
305 }
306
307 static function pro_placeholder_page(){
308 echo '<div class="formlayer-placeholder-page">
309 <div class="notice notice-warning">
310 <p>' . esc_html__('This is a part of FormLayer Pro, so update/upgrade to pro to utilize this feature', 'formlayer') . '</p>
311 </div>
312 </div>';
313 }
314
315 static function support_tab(){
316 echo '<div class="formlayer-support-page">
317 <div class="formlayer-logo">
318 <img alt="' . esc_html__('formlayer logo', 'formlayer') . '" style="max-width: 280px; height: auto;" src="' . esc_url(FORMLAYER_ASSETS_URL) . '/img/formlayer-banner.png' . '"/>
319 </div>
320 <h2>' . esc_html__('Help & Support', 'formlayer') . '</h2>
321 <p>' . esc_html__('You can contact the FormLayer team via email at ', 'formlayer') . '<a href="mailto:support@formlayer.net">support@formlayer.net</a> ' . esc_html__('or through our Support Ticket System.', 'formlayer') . '</p>
322 <p>' . esc_html__('You can also check the documentation here:', 'formlayer') . ' <a href="https://formlayer.net/docs" target="_blank" rel="noopener noreferrer">https://formlayer.net/docs</a></p>
323 </div>';
324 }
325
326 static function settings_tab(){
327 $settings = get_option('formlayer_settings', []);
328
329 // Defaults
330 $defaults = [
331 'msg_success' => __('Thank you! Your form has been submitted successfully.', 'formlayer'),
332 'msg_error' => __('Something went wrong. Please try again.', 'formlayer'),
333 'msg_required' => __('This field is required.', 'formlayer'),
334 'msg_email' => __('Please enter a valid email address.', 'formlayer'),
335 'msg_url' => __('Please enter a valid URL.', 'formlayer'),
336 'msg_number' => __('Please enter a valid number.', 'formlayer'),
337 'msg_file_type' => __('This file type is not permitted.', 'formlayer'),
338 'msg_file_size' => __('The file is too large.', 'formlayer'),
339 'msg_terms' => __('You must accept the terms and conditions.', 'formlayer'),
340 'captcha_provider' => 'none',
341 'captcha_h_site_key' => '',
342 'captcha_h_secret_key' => '',
343 'captcha_h_theme' => 'light',
344 'captcha_t_site_key' => '',
345 'captcha_t_secret_key' => '',
346 'captcha_t_theme' => 'light',
347 'captcha_r_site_key' => '',
348 'captcha_r_secret_key' => '',
349 'captcha_r_theme' => 'light',
350 ];
351 $settings = array_merge($defaults, $settings);
352
353 echo'<div class="formlayer-settings-container">
354 <!-- Validation Section -->
355 <div class="formlayer-settings-card">
356 <div class="formlayer-settings-header">
357 <div style="display: flex; align-items: center; gap: 12px;">
358 <div style="background: var(--fl-primary-light); color: var(--fl-primary); width: 40px; height: 40px; border-radius: 10px; display: flex; align-items: center; justify-content: center;">
359 <span class="dashicons dashicons-yes-alt"></span>
360 </div>
361 <div>
362 <h3>' . esc_html__('Form Validation & Messages', 'formlayer') . '</h3>
363 <p>' . esc_html__('Customize error and success messages for all forms.', 'formlayer') . '</p>
364 </div>
365 </div>
366 </div>
367 <div class="formlayer-settings-body">
368 <div style="display: grid; grid-template-columns: 1fr 1fr; gap: 30px;">
369 <!-- Left Column -->
370 <div>
371 <div class="formlayer-setting-row-v">
372 <label>' . esc_html__('Success Message', 'formlayer') . '</label>
373 <textarea name="msg_success" class="formlayer-input" rows="2">' . esc_textarea($settings['msg_success']) . '</textarea>
374 </div>
375 <div class="formlayer-setting-row-v">
376 <label>' . esc_html__('General Error', 'formlayer') . '</label>
377 <textarea name="msg_error" class="formlayer-input" rows="2">' . esc_textarea($settings['msg_error']) . '</textarea>
378 </div>
379 <div class="formlayer-setting-row-v">
380 <label>' . esc_html__('Required Field', 'formlayer') . '</label>
381 <input type="text" name="msg_required" class="formlayer-input" value="' . esc_attr($settings['msg_required']) . '">
382 </div>
383 <div class="formlayer-setting-row-v">
384 <label>' . esc_html__('Terms Acceptance', 'formlayer') . '</label>
385 <input type="text" name="msg_terms" class="formlayer-input" value="' . esc_attr($settings['msg_terms']) . '">
386 </div>
387 </div>
388 <!-- Right Column -->
389 <div>
390 <div class="formlayer-setting-row-v">
391 <label>' . esc_html__('Invalid Email', 'formlayer') . '</label>
392 <input type="text" name="msg_email" class="formlayer-input" value="' . esc_attr($settings['msg_email']) . '">
393 </div>
394 <div class="formlayer-setting-row-v">
395 <label>' . esc_html__('Invalid URL', 'formlayer') . '</label>
396 <input type="text" name="msg_url" class="formlayer-input" value="' . esc_attr($settings['msg_url']) . '">
397 </div>
398 <div class="formlayer-setting-row-v">
399 <label>' . esc_html__('Invalid Number', 'formlayer') . '</label>
400 <input type="text" name="msg_number" class="formlayer-input" value="' . esc_attr($settings['msg_number']) . '">
401 </div>
402 <div class="formlayer-setting-row-v">
403 <label>' . esc_html__('Invalid File Type', 'formlayer') . '</label>
404 <input type="text" name="msg_file_type" class="formlayer-input" value="' . esc_attr($settings['msg_file_type']) . '">
405 </div>
406 <div class="formlayer-setting-row-v">
407 <label>' . esc_html__('File Too Large', 'formlayer') . '</label>
408 <input type="text" name="msg_file_size" class="formlayer-input" value="' . esc_attr($settings['msg_file_size']) . '">
409 </div>
410 </div>
411 </div>
412 </div>
413 </div>
414
415 <!-- Captcha Section -->
416 <div class="formlayer-settings-card" style="margin-top: 30px;">
417 <div class="formlayer-settings-header">
418 <div class="formlayer-captcha-header-left">
419 <div class="formlayer-captcha-icon-box">
420 <span class="dashicons dashicons-shield"></span>
421 </div>
422 <div>
423 <h3 style="margin: 0; font-size: 18px; font-weight: 700;">' . esc_html__('Spam Protection (Captcha)', 'formlayer') . '</h3>
424 <p style="margin: 4px 0 0 0; font-size: 13px; color: var(--fl-text-light);">' . esc_html__('Configure and select your preferred captcha service to block bots.', 'formlayer') . '</p>
425 </div>
426 </div>
427 </div>
428 <div class="formlayer-settings-body" style="padding: 0 32px 32px 32px;">
429
430 <div class="formlayer-captcha-tabs-wrapper">
431 <div class="formlayer-captcha-tabs-nav">
432 <div class="captcha-tab-item active" data-target="hcaptcha">
433 <div class="tab-icon-wrap" style="background: #f0fdf4; color: #22c55e;">
434 <span class="dashicons dashicons-shield"></span>
435 </div>
436 <span>hCaptcha</span>
437 </div>
438 <div class="captcha-tab-item" data-target="turnstile">';
439 if(!defined('FORMLAYER_PRO_VERSION')){
440 echo'<span class="dashicons dashicons-lock" style="opacity:0.5;margin-right:3px;"></span>';
441 }
442 echo'<span>Turnstile</span>
443 </div>
444 <div class="captcha-tab-item" data-target="recaptcha">
445 <div class="tab-icon-wrap" style="background: #fff7ed; color: #f97316;">
446 <span class="dashicons dashicons-google"></span>
447 </div>
448 <span>reCAPTCHA</span>
449 </div>
450 </div>
451
452 <div class="formlayer-captcha-tab-content">
453 <!-- hCaptcha Details -->
454 <div class="captcha-pane active" id="pane-hcaptcha">
455 <div class="pane-header">
456 <h4 style="margin: 0; font-size: 15px;">hCaptcha Configuration</h4>
457 <p>' . esc_html__('hCaptcha is a free, privacy-focused alternative to Google reCAPTCHA. Visit hcaptcha.com to get your keys.', 'formlayer') . '</p>
458 </div>
459
460 <div class="formlayer-setting-row-v">
461 <label>' . esc_html__('Site Key', 'formlayer') . '</label>
462 <input type="text" name="captcha_h_site_key" class="formlayer-input" value="' . esc_attr($settings['captcha_h_site_key']) . '" placeholder="Enter your hCaptcha site key">
463 </div>
464 <div class="formlayer-setting-row-v">
465 <label>' . esc_html__('Secret Key', 'formlayer') . '</label>
466 <input type="password" name="captcha_h_secret_key" class="formlayer-input" value="' . esc_attr($settings['captcha_h_secret_key']) . '" placeholder="••••••••••••••••">
467 </div>
468 <div class="formlayer-setting-row-v">
469 <label>' . esc_html__('Default Theme', 'formlayer') . '</label>
470 <select name="captcha_h_theme" class="formlayer-select">
471 <option value="light" ' . selected($settings['captcha_h_theme'], 'light', false) . '>Light</option>
472 <option value="dark" ' . selected($settings['captcha_h_theme'], 'dark', false) . '>Dark</option>
473 </select>
474 </div>
475 </div>
476
477 <!-- Turnstile Details -->
478 <div class="captcha-pane" id="pane-turnstile">';
479 if(!defined('FORMLAYER_PRO_VERSION')){
480 echo'<div class="formlayer-pro-lock-pane">
481 <div class="lock-inner">
482 <div class="lock-icon">
483 <span class="dashicons dashicons-lock"></span>
484 </div>
485 <h4>'.esc_html__('Cloudflare Turnstile is Pro', 'formlayer').'</h4>
486 <p>'.esc_html__('Enjoy the seamless, non-intrusive CAPTCHA experience of Cloudflare Turnstile by upgrading to FormLayer Pro.', 'formlayer').'</p>
487 <a href="#" class="formlayer-btn formlayer-btn-primary">'.esc_html__('Get FormLayer Pro', 'formlayer').'</a>
488 </div>
489 </div>';
490 } else{
491 do_action('formlayer_render_turnstile_settings', $settings);
492 }
493
494 echo'</div>
495
496 <!-- reCAPTCHA Details -->
497 <div class="captcha-pane" id="pane-recaptcha">';
498 if(!defined('FORMLAYER_PRO_VERSION')){
499 echo'<div class="formlayer-pro-lock-pane">
500 <div class="lock-inner">
501 <div class="lock-icon">
502 <span class="dashicons dashicons-lock"></span>
503 </div>
504 <h4>'.esc_html__('Google reCAPTCHA is Pro', 'formlayer').'</h4>
505 <p>'.esc_html__('Enjoy the legacy and advanced features of Google reCAPTCHA v2 and v3 by upgrading to FormLayer Pro.', 'formlayer').'</p>
506 <a href="#" class="formlayer-btn formlayer-btn-primary">'.esc_html__('Get FormLayer Pro', 'formlayer').'</a>
507 </div>
508 </div>';
509 } else {
510 do_action('formlayer_render_recaptcha_settings', $settings);
511 }
512 echo'</div>
513 </div>
514 </div>
515
516 <div class="captcha-notice-box formlayer-captcha-notice-box">
517 <span class="dashicons dashicons-info" style="color: #0284c7; margin-top: 2px;"></span>
518 <p style="margin: 0; font-size: 13px; color: #0369a1; line-height: 1.5;">
519 ' . esc_html__('Configure your credentials above. You can then add a "Captcha" field to your individual forms and select which provider to use for that specific form.', 'formlayer') . '
520 </p>
521 </div>
522
523 </div>
524 </div>
525
526 <div class="formlayer-settings-footer">
527 <div class="formlayer-footer-status" id="formlayer-settings-status"></div>
528 <button id="formlayer-save-settings" class="formlayer-btn formlayer-btn-primary" style="padding: 12px 30px; font-size: 15px;">
529 ' . esc_html__('Save Settings', 'formlayer') . '
530 </button>
531 </div>
532 </div>';
533 }
534
535 static function footer(){
536 echo '</main></div>'; // Close main and wrapper
537 self::modals();
538 }
539
540 static function modals(){
541 $settings = get_option('formlayer_settings', []);
542
543 // Entry Detail Modal
544 echo '<div id="formlayer-entry-modal" class="formlayer-modal-overlay formlayer-entry-modal">
545 <div class="formlayer-modal-content">
546 <button class="formlayer-modal-close formlayer-modal-close-btn">&times;</button>
547 <div id="formlayer-entry-detail-body">
548 <!-- Loaded via AJAX -->
549 </div>
550 </div>
551 </div>';
552
553 // Form Settings Modal
554 echo '<div id="formlayer-form-settings-modal" class="formlayer-modal-overlay">
555 <div class="formlayer-modal-panel">
556 <div class="formlayer-modal-header">
557 <div class="header-left">
558 <span class="dashicons dashicons-admin-settings"></span>
559 <h2>' . esc_html__('Form Settings', 'formlayer') . '</h2>
560 </div>
561 <div class="header-right">
562 <button class="formlayer-btn formlayer-btn-primary" id="formlayer-settings-apply-btn">' . esc_html__('Apply Settings', 'formlayer') . '</button>
563 <button class="formlayer-modal-close" id="formlayer-settings-close-btn">&times;</button>
564 </div>
565 </div>
566 <div class="formlayer-modal-body">
567 <div class="formlayer-modal-sidebar">
568 <ul>
569 <li class="active" data-section="notifications">
570 <span class="dashicons dashicons-email"></span>' . esc_html__('Email Notifications', 'formlayer') . '
571 </li>
572 <li data-section="email_confirmation">
573 <span class="dashicons dashicons-email-alt"></span>' . esc_html__('Email Confirmation', 'formlayer') . '
574 </li>
575 <li data-section="confirmations">
576 <span class="dashicons dashicons-yes"></span>' . esc_html__('Form Confirmations', 'formlayer') . '
577 </li>
578 <li data-section="integrations">
579 <span class="dashicons dashicons-admin-links"></span>' . esc_html__('Integrations', 'formlayer') . '
580 </li>
581 <li data-section="custom_css">
582 <span class="dashicons dashicons-editor-code"></span>' . esc_html__('Custom CSS', 'formlayer') . '
583 </li>
584 </ul>
585 </div>
586 <div class="formlayer-modal-main">
587 <!-- Notifications Section -->
588 <div class="formlayer-settings-section active" id="formlayer-settings-notifications">
589 <div class="section-header">
590 <h3>' . esc_html__('Email Notifications', 'formlayer') . '</h3>
591 <p>' . esc_html__('Configure how you want to be notified when a form is submitted.', 'formlayer') . '</p>
592 </div>
593 <div class="formlayer-settings-field">
594 <label>' . esc_html__('Enabled', 'formlayer') . '</label>
595 <div class="formlayer-switch-wrapper">
596 <label class="formlayer-switch">
597 <input type="checkbox" id="form-setting-notif-enabled" checked>
598 <span class="slider round"></span>
599 </label>
600 </div>
601 </div>
602 <div style="display: grid; grid-template-columns: 1fr 1fr; gap: 20px;">
603 <div class="formlayer-settings-field">
604 <label>' . esc_html__('Send To Email', 'formlayer') . '</label>
605 <input type="text" id="form-setting-notif-email" class="formlayer-input" placeholder="{admin_email}">
606 </div>
607 <div class="formlayer-settings-field">
608 <label>' . esc_html__('Reply To', 'formlayer') . '</label>
609 <input type="text" id="form-setting-notif-replyto" class="formlayer-input" placeholder="e.g. {field_email}">
610 </div>
611 </div>
612 <div style="display: grid; grid-template-columns: 1fr 1fr; gap: 20px;">
613 <div class="formlayer-settings-field">
614 <label>' . esc_html__('From Name', 'formlayer') . '</label>
615 <input type="text" id="form-setting-notif-fromname" class="formlayer-input" placeholder="FormLayer">
616 </div>
617 <div class="formlayer-settings-field">
618 <label>' . esc_html__('From Email', 'formlayer') . '</label>
619 <input type="text" id="form-setting-notif-fromemail" class="formlayer-input" placeholder="{admin_email}">
620 </div>
621 </div>
622 <div class="formlayer-settings-field">
623 <label>' . esc_html__('BCC', 'formlayer') . '</label>
624 <input type="text" id="form-setting-notif-bcc" class="formlayer-input" placeholder="comma separated emails">
625 </div>
626 <div class="formlayer-settings-field">
627 <label>' . esc_html__('Subject', 'formlayer') . '</label>
628 <input type="text" id="form-setting-notif-subject" class="formlayer-input" placeholder="New Form Submission">
629 </div>
630 <div class="formlayer-settings-field">
631 <label>' . esc_html__('Message Format', 'formlayer') . '</label>
632 <select id="form-setting-notif-format" class="formlayer-select">
633 <option value="html">HTML (Recommended)</option>
634 <option value="plain">Plain Text</option>
635 </select>
636 </div>
637 <div class="formlayer-settings-field">
638 <label style="display:flex; justify-content:space-between;">
639 <span>'.esc_html__('Message Body', 'formlayer').'</span>
640 </label>
641 <textarea id="form-setting-notif-message" class="formlayer-input" style="height:120px;"></textarea>
642 <div class="formlayer-merge-tags-wrapper" style="margin-top: 10px; background: #f8fafc; padding: 10px; border-radius: 6px; border: 1px solid #e2e8f0;">
643 <div style="font-size: 12px; font-weight: 600; margin-bottom: 8px; color: #475569;">Available Merge Tags (Click to insert)</div>
644 <div id="formlayer-dynamic-merge-tags" style="display: flex; flex-wrap: wrap; gap: 6px;"></div>
645 </div>
646 </div>
647 </div>
648
649 <!-- Email Confirmation Section -->
650 <div class="formlayer-settings-section" id="formlayer-settings-email_confirmation" style="display:none;">
651 <div class="section-header">
652 <h3>' . esc_html__('Email Confirmation', 'formlayer') . '</h3>
653 <p>' . esc_html__('Send an automatic confirmation email to the person who submitted the form.', 'formlayer') . '</p>
654 </div>';
655
656 if(defined("FORMLAYER_PRO_VERSION")){
657 do_action('formlayer_render_email_confirmation');
658 } else {
659 echo'<div class="formlayer-pro-lock-pane formlayer-pro-lock-pane-wrap">
660 <div class="formlayer-pro-lock-icon-box">
661 <span class="dashicons dashicons-lock" style="font-size:32px; height:32px; width:32px; color:var(--fl-primary);"></span>
662 </div>
663 <h4 class="formlayer-empty-title">' . esc_html__('Unlock Email Confirmations', 'formlayer') . '</h4>
664 <p style="color:#64748b; margin:0 0 20px 0;">' . esc_html__('Automatically send a confirmation email to your users after they submit a form with FormLayer Pro.', 'formlayer') . '</p>
665 <a href="#" class="formlayer-btn formlayer-btn-primary">' . esc_html__('Go Pro', 'formlayer') . '</a>
666 </div>';
667 }
668
669 echo'</div>';
670 echo'<!-- Confirmations Section -->
671 <div class="formlayer-settings-section" id="formlayer-settings-confirmations" style="display:none;">
672 <div class="section-header">
673 <h3>' . esc_html__('Form Confirmations', 'formlayer') . '</h3>
674 <p>' . esc_html__('What happens after a user submits the form?', 'formlayer') . '</p>
675 </div>
676 <div class="formlayer-settings-field">
677 <label>' . esc_html__('Confirmation Type', 'formlayer') . '</label>
678 <select id="form-setting-conf-type" class="formlayer-select">
679 <option value="message">' . esc_html__('Display Message', 'formlayer') . '</option>
680 <option value="redirect">' . esc_html__('Redirect to Page/URL', 'formlayer') . '</option>
681 </select>
682 </div>
683
684 <div id="conf-group-message">
685 <div class="formlayer-settings-field">
686 <label>' . esc_html__('Success Message', 'formlayer') . '</label>
687 <textarea id="form-setting-conf-message" class="formlayer-input" style="height:100px;"></textarea>
688 </div>
689 <div class="formlayer-settings-field">
690 <label>'.esc_html__('Hide form after successful submission', 'formlayer').'</label>
691 <div class="formlayer-switch-wrapper">
692 <label class="formlayer-switch">
693 <input type="checkbox" id="form-setting-conf-hide" checked>
694 <span class="slider round"></span>
695 </label>
696 </div>
697 </div>
698 </div>
699
700 <div id="conf-group-redirect" style="display:none;">
701 <div class="formlayer-settings-field">
702 <label>' . esc_html__('Redirect URL', 'formlayer') . '</label>
703 <input type="text" id="form-setting-conf-url" class="formlayer-input" placeholder="https://example.com/thanks">
704 </div>
705 </div>
706 </div>
707
708 <div class="formlayer-settings-section" id="formlayer-settings-integrations" style="display:none;">
709 <div class="section-header">
710 <h3>' . esc_html__('Integrations', 'formlayer') . '</h3>
711 <p>' . esc_html__('Connect your form to 3rd party services.', 'formlayer') . '</p>
712 </div>';
713
714 if(defined("FORMLAYER_PRO_VERSION")){
715 do_action("formlayer_render_form_integrations");
716 } else {
717 echo'<div class="formlayer-pro-lock-pane formlayer-pro-lock-pane-wrap">
718 <div class="formlayer-pro-lock-icon-box">
719 <span class="dashicons dashicons-lock" style="font-size:32px; height:32px; width:32px; color:var(--fl-primary);"></span>
720 </div>
721 <h4 class="formlayer-empty-title">' . esc_html__('Unlock Pro Integrations', 'formlayer') . '</h4>
722 <p style="color:#64748b; margin:0 0 20px 0;">' . esc_html__('Connect to Slack, Mailchimp, Notion, Trello and more with FormLayer Pro.', 'formlayer') . '</p>
723 <a href="#" class="formlayer-btn formlayer-btn-primary">' . esc_html__('Go Pro', 'formlayer') . '</a>
724 </div>';
725 }
726
727 echo'</div>
728 <!-- Custom CSS Section -->
729 <div class="formlayer-settings-section" id="formlayer-settings-custom_css" style="display:none;">
730 <div class="section-header">
731 <h3>' . esc_html__('Custom CSS', 'formlayer') . '</h3>
732 <p>' . esc_html__('Add custom styles specifically for this form.', 'formlayer') . '</p>
733 </div>
734 <div class="formlayer-settings-field">
735 <textarea id="form-setting-custom-css" class="formlayer-input" style="height:300px; font-family:monospace;" placeholder=".formlayer-form { /* Your styles here */ }"></textarea>
736 </div>
737 </div>
738 </div>
739 </div>
740 </div>
741 </div>';
742
743
744 do_action('formlayer_render_modals');
745
746 }
747 }
748