| 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">×</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">×</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 |
|