PluginProbe
Fluent Forms – Customizable Contact Forms, Survey, Quiz, & Conversational Form Builder / 6.2.13
Fluent Forms – Customizable Contact Forms, Survey, Quiz, & Conversational Form Builder v6.2.13
6.2.15 6.2.14 6.2.13 6.2.12 6.2.10 6.2.11 6.2.9 6.2.8 6.2.7 6.2.6 6.2.5 6.2.4 6.2.3 6.2.2 3.6.22 3.6.31 3.6.40 3.6.41 3.6.42 3.6.50 3.6.51 3.6.60 3.6.61 3.6.62 3.6.64 All 197 releases
fluentform / app / Hooks / actions.php

actions.php in Fluent Forms – Customizable Contact Forms, Survey, Quiz, & Conversational Form Builder 6.2.13, at app/Hooks/actions.php

1,347 lines 47.9 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 defined('ABSPATH') || die;
4
5 use FluentForm\App\Modules\Component\Component;
6 use FluentForm\App\Modules\Acl\Acl;
7 use FluentForm\App\Helpers\Helper;
8 use FluentForm\Framework\Helpers\ArrayHelper;
9
10 /**
11 * All registered action's handlers should be in app\Hooks\Handlers,
12 * addAction is similar to add_action and addCustomAction is just a
13 * wrapper over add_action which will add a prefix to the hook name
14 * using the plugin slug to make it unique in all WordPress plugins,
15 * ex: $app->addCustomAction('foo', ['FooHandler', 'handleFoo']) is
16 * equivalent to add_action('slug-foo', ['FooHandler', 'handleFoo']).
17 */
18
19 /**
20 * Application instance.
21 *
22 * @var $app FluentForm\Framework\Foundation\Application
23 */
24
25 // From MenuProvider.php
26 $app->addAction(
27 'admin_menu',
28 function () use ($app) {
29 (new \FluentForm\App\Modules\Registerer\Menu($app))->register();
30 }
31 );
32
33 $app->addAction(
34 'fluentform/form_application_view_editor',
35 function ($formId) use ($app) {
36 (new \FluentForm\App\Modules\Registerer\Menu($app))->renderEditor($formId);
37 }
38 );
39
40 $app->addAction(
41 'fluentform/form_application_view_settings',
42 function ($formId) use ($app) {
43 (new \FluentForm\App\Modules\Registerer\Menu($app))->renderSettings($formId);
44 }
45 );
46
47 $app->addAction(
48 'fluentform/form_settings_container_form_settings',
49 function ($formId) use ($app) {
50 (new \FluentForm\App\Modules\Registerer\Menu($app))->renderFormSettings($formId);
51 }
52 );
53
54 $app->addAction(
55 'fluentform/global_settings_component_settings',
56 function () use ($app) {
57 (new \FluentForm\App\Modules\Renderer\GlobalSettings\Settings($app))->render();
58 }
59 );
60
61 $app->addAction(
62 'fluentform/global_settings_component_reCaptcha',
63 function () use ($app) {
64 (new \FluentForm\App\Modules\Renderer\GlobalSettings\Settings($app))->render();
65 }
66 );
67
68 $app->addAction(
69 'fluentform/global_settings_component_hCaptcha',
70 function () use ($app) {
71 (new \FluentForm\App\Modules\Renderer\GlobalSettings\Settings($app))->render();
72 }
73 );
74
75 /**
76 * Pro 6.2.13+ supplies the REST API used by Free's Vue license screen. Older
77 * Pro versions keep rendering their PHP page through this component action.
78 */
79 $app->addAction(
80 'fluentform/global_settings_component_license_page',
81 function () use ($app) {
82 if (!defined('FLUENTFORMPRO_VERSION') || version_compare(FLUENTFORMPRO_VERSION, '6.2.13', '<')) {
83 return;
84 }
85
86 (new \FluentForm\App\Modules\Renderer\GlobalSettings\Settings($app))->render('license');
87 }
88 );
89
90 // Register DefaultStyleApplicator on init so it works for REST API requests too
91 add_action('init', function () {
92 new \FluentForm\App\Modules\Form\DefaultStyleApplicator();
93 }, 9);
94
95 // From Backend.php
96 add_action('admin_init', function () use ($app) {
97 (new \FluentForm\App\Modules\Registerer\Menu($app))->reisterScripts();
98 (new \FluentForm\App\Modules\Registerer\AdminBar())->register();
99 (new \FluentForm\App\Modules\Ai\AiController())->boot();
100 (new \FluentForm\App\Modules\Report\ReportHandler())->register($app);
101 }, 9);
102
103 add_action('admin_enqueue_scripts', function () use ($app) {
104 (new \FluentForm\App\Modules\Registerer\Menu($app))->enqueuePageScripts();
105 }, 10);
106
107 // Add Entries Menu
108 $app->addAction('fluentform/form_application_view_entries', function ($form_id) {
109 (new \FluentForm\App\Modules\Entries\EntryViewRenderer())->renderEntries($form_id);
110 });
111
112 $app->addAction('fluentform/after_form_navigation', function ($form_id) use ($app) {
113 (new \FluentForm\App\Modules\Registerer\Menu($app))->addCopyShortcodeButton($form_id);
114 (new \FluentForm\App\Modules\Registerer\Menu($app))->addPreviewButton($form_id);
115 });
116
117 $app->addAction('media_buttons', function () {
118 (new \FluentForm\App\Modules\EditorButtonModule())->addButton();
119 });
120
121 /*
122 * Addons Page
123 */
124 $app->addAction('fluentform/addons_page_render_fluentform_add_ons', function () {
125 (new \FluentForm\App\Modules\AddOnModule())->showFluentAddOns();
126 });
127
128 $app->addAction('fluentform/addons_page_render_suggested_plugins', function () {
129 (new \FluentForm\App\Modules\AddOnModule())->showSuggestedPlugins();
130 });
131
132 $app->addAction('fluentform/global_menu', function () use ($app) {
133 $menu = new \FluentForm\App\Modules\Registerer\Menu($app);
134 $menu->renderGlobalMenu();
135 if ('yes' != get_option('fluentform_scheduled_actions_migrated')) {
136 \FluentForm\Database\Migrations\ScheduledActions::migrate();
137 }
138
139 $hookName = 'fluentform_do_scheduled_tasks';
140 if (!wp_next_scheduled($hookName)) {
141 wp_schedule_event(time(), 'ff_every_five_minutes', $hookName);
142 }
143
144 $emailReportHookName = 'fluentform_do_email_report_scheduled_tasks';
145 if (!wp_next_scheduled($emailReportHookName)) {
146 wp_schedule_event(time(), 'daily', $emailReportHookName);
147 }
148 });
149
150 $app->addAction('wp_dashboard_setup', function () {
151 $acl = new \FluentForm\App\Modules\Acl\Acl();
152
153 if (!$acl::getCurrentUserCapability()) {
154 return;
155 }
156 wp_add_dashboard_widget('fluentform_stat_widget', __('Fluent Forms Latest Form Submissions', 'fluentform'), function () {
157 (new \FluentForm\App\Modules\DashboardWidgetModule())->showStat();
158 }, 10, 1);
159 });
160
161 add_action('admin_init', function () {
162 $disablePages = [
163 'fluent_forms',
164 'fluent_forms_transfer',
165 'fluent_forms_settings',
166 'fluent_forms_add_ons',
167 'fluent_forms_docs',
168 'fluent_forms_all_entries',
169 'msformentries',
170 'fluent_forms_payment_entries',
171 'fluent_forms_reports',
172 ];
173
174 $page = wpFluentForm('request')->get('page');
175
176 if ($page && in_array($page, $disablePages)) {
177 remove_all_actions('admin_notices');
178 \FluentForm\App\Modules\Registerer\ReviewQuery::register();
179 \FluentForm\App\Modules\Registerer\MigrationNotice::register();
180 \FluentForm\App\Modules\Registerer\StripeKeyNotice::register();
181 \FluentForm\App\Modules\Registerer\CaptchaKeyNotice::register();
182 }
183 });
184
185 add_action('wp_print_scripts', function () {
186 if (is_admin()) {
187 if (\FluentForm\App\Helpers\Helper::isFluentAdminPage()) {
188 $option = get_option('_fluentform_global_form_settings');
189 $isSkip = 'no' == \FluentForm\Framework\Helpers\ArrayHelper::get($option, 'misc.noConflictStatus');
190
191 $isSkip = apply_filters_deprecated(
192 'fluentform_skip_no_conflict',
193 [
194 $isSkip,
195 ],
196 FLUENTFORM_FRAMEWORK_UPGRADE,
197 'fluentform/skip_no_conflict',
198 'Use fluentform/skip_no_conflict instead of fluentform_skip_no_conflict.'
199 );
200
201 $isSkip = apply_filters('fluentform/skip_no_conflict', $isSkip);
202
203 if ($isSkip) {
204 return;
205 }
206
207 global $wp_scripts;
208 if (!$wp_scripts) {
209 return;
210 }
211
212 $pluginUrl = plugins_url();
213 // Get an array of slugs to exclude from dequeue
214 $excludeSlugs = apply_filters('fluentform/exclude_js_slugs_from_dequeue', ['fluentform']);
215
216 foreach ($wp_scripts->queue as $script) {
217 if (!isset($wp_scripts->registered[$script])) {
218 continue;
219 }
220
221 $src = $wp_scripts->registered[$script]->src;
222
223 // Check if the script is in the plugins directory
224 if (false !== strpos($src, $pluginUrl)) {
225 // Only dequeue if none of the exclude slugs are in the script src
226 $shouldDequeue = true;
227 foreach ($excludeSlugs as $slug) {
228 if (false !== strpos($src, $slug)) {
229 $shouldDequeue = false;
230 break;
231 }
232 }
233
234 if ($shouldDequeue) {
235 wp_dequeue_script($wp_scripts->registered[$script]->handle);
236 }
237 }
238 }
239 }
240 }
241 }, 1);
242
243 $app->addAction('fluentform/loading_editor_assets', function ($form) {
244 add_filter('fluentform/editor_init_element_input_name', function ($field) {
245 if (empty($field['settings']['label_placement'])) {
246 $field['settings']['label_placement'] = '';
247 }
248 return $field;
249 });
250
251 add_filter('fluentform/editor_init_element_step_start', function ($item) {
252 if (!isset($item['settings']['progress_layout'])) {
253 $item['settings']['progress_layout'] = 'top';
254 }
255
256 if (!isset($item['settings']['tabs_show_progress_bar'])) {
257 $item['settings']['tabs_show_progress_bar'] = 'no';
258 }
259
260 return $item;
261 });
262
263 $upgradableCheckInputs = [
264 'input_radio',
265 'select',
266 'select_country',
267 'input_checkbox',
268 ];
269 foreach ($upgradableCheckInputs as $upgradeElement) {
270 add_filter('fluentform/editor_init_element_' . $upgradeElement, function ($element) use ($upgradeElement, $form) {
271
272 if (!\FluentForm\Framework\Helpers\ArrayHelper::get($element, 'settings.advanced_options')) {
273 $formattedOptions = [];
274 $oldOptions = \FluentForm\Framework\Helpers\ArrayHelper::get($element, 'options', []);
275 foreach ($oldOptions as $value => $label) {
276 $formattedOptions[] = [
277 'label' => $label,
278 'value' => $value,
279 'calc_value' => '',
280 'image' => '',
281 ];
282 }
283 $element['settings']['advanced_options'] = $formattedOptions;
284 $element['settings']['enable_image_input'] = false;
285 $element['settings']['calc_value_status'] = false;
286 unset($element['options']);
287
288 if ('input_radio' == $upgradeElement || 'input_checkbox' == $upgradeElement) {
289 $element['editor_options']['template'] = 'inputCheckable';
290 }
291 }
292
293 if (!isset($element['settings']['layout_class']) && in_array($upgradeElement, ['input_radio', 'input_checkbox'])) {
294 $element['settings']['layout_class'] = '';
295 }
296
297 if (!isset($element['settings']['dynamic_default_value'])) {
298 $element['settings']['dynamic_default_value'] = '';
299 }
300
301 // The editor only renders a rule the field already carries, so forms
302 // built before selection limits existed need the keys backfilled.
303 $isMultiSelect = 'select' == $upgradeElement
304 && \FluentForm\Framework\Helpers\ArrayHelper::get($element, 'attributes.multiple');
305
306 if ('input_checkbox' == $upgradeElement || $isMultiSelect) {
307 $rules = \FluentForm\Framework\Helpers\ArrayHelper::get($element, 'settings.validation_rules', []);
308
309 foreach (['max_selection', 'min_selection'] as $selectionRule) {
310 if (isset($rules[$selectionRule])) {
311 continue;
312 }
313
314 $globalMessage = \FluentForm\App\Helpers\Helper::getGlobalDefaultMessage($selectionRule);
315
316 // Carry the legacy ceiling across, or the editor would show
317 // "no limit" on a form that has one and drop it on save.
318 $value = '';
319 if ('max_selection' === $selectionRule && $isMultiSelect) {
320 $value = \FluentForm\Framework\Helpers\ArrayHelper::get($element, 'settings.max_selection', '');
321 }
322
323 $rules[$selectionRule] = [
324 'value' => $value,
325 'message' => $globalMessage,
326 'global_message' => $globalMessage,
327 'global' => true,
328 ];
329 }
330
331 // Key order is the panel's layout order. Rebuilt rather than
332 // appended, so forms saved by an earlier build get it too.
333 $ordered = [];
334 foreach (['required', 'max_selection', 'min_selection'] as $key) {
335 if (isset($rules[$key])) {
336 $ordered[$key] = $rules[$key];
337 }
338 }
339
340 $element['settings']['validation_rules'] = $ordered + $rules;
341 }
342
343 if ('select_country' != $upgradeElement && !isset($element['settings']['randomize_options'])) {
344 $element['settings']['randomize_options'] = 'no';
345 }
346
347 if ('select' == $upgradeElement && \FluentForm\Framework\Helpers\ArrayHelper::get($element, 'attributes.multiple')) {
348 if (empty($element['settings']['max_selection'])) {
349 $element['settings']['max_selection'] = '';
350 }
351 if (isset($element['settings']['enable_select_2'])) {
352 \FluentForm\Framework\Helpers\ArrayHelper::forget($element, 'settings.enable_select_2');
353 }
354 }
355
356 if (
357 (
358 (
359 'select' == $upgradeElement &&
360 !\FluentForm\Framework\Helpers\ArrayHelper::get($element, 'attributes.multiple')
361 ) ||
362 'select_country' == $upgradeElement
363 ) &&
364 !isset($element['settings']['enable_select_2'])
365 ) {
366 $element['settings']['enable_select_2'] = 'no';
367 }
368
369 if ('select_country' != $upgradeElement && !isset($element['settings']['values_visible'])) {
370 $element['settings']['values_visible'] = false;
371 }
372
373 if ('select' == $upgradeElement && !isset($element['settings']['enable_option_groups'])) {
374 $element['settings']['enable_option_groups'] = 'no';
375 }
376
377 return $element;
378 });
379 }
380
381 $upgradableFileInputs = [
382 'input_file',
383 'input_image',
384 ];
385 foreach ($upgradableFileInputs as $upgradeElement) {
386 add_filter('fluentform/editor_init_element_' . $upgradeElement, function ($element) {
387 if (!isset($element['settings']['upload_file_location'])) {
388 $element['settings']['upload_file_location'] = 'default';
389 }
390 if (!isset($element['settings']['file_location_type'])) {
391 $element['settings']['file_location_type'] = 'follow_global_settings';
392 }
393 if ('input_image' === $element['element']) {
394 if (!isset($element['settings']['enable_crop'])) {
395 $element['settings']['enable_crop'] = 'no';
396 }
397 if (!isset($element['settings']['crop_mode'])) {
398 $element['settings']['crop_mode'] = (
399 isset($element['settings']['enforce_image_dimensions']) &&
400 'yes' === $element['settings']['enforce_image_dimensions']
401 ) ? 'dimensions' : 'ratio';
402 }
403 if (!isset($element['settings']['crop_ratio'])) {
404 $element['settings']['crop_ratio'] = 'free';
405 }
406 if (!isset($element['settings']['enforce_image_dimensions'])) {
407 $element['settings']['enforce_image_dimensions'] = 'no';
408 }
409 if (!isset($element['settings']['crop_width'])) {
410 $element['settings']['crop_width'] = '';
411 }
412 if (!isset($element['settings']['crop_height'])) {
413 $element['settings']['crop_height'] = '';
414 }
415 }
416 return $element;
417 });
418 }
419
420 $prefixSuffixInputs = [
421 'textarea',
422 'input_url',
423 'input_password',
424 ];
425
426 foreach ($prefixSuffixInputs as $inputType) {
427 add_filter('fluentform/editor_init_element_' . $inputType, function ($item) {
428 if (!isset($item['settings']['prefix_label'])) {
429 $item['settings']['prefix_label'] = '';
430 }
431 if (!isset($item['settings']['suffix_label'])) {
432 $item['settings']['suffix_label'] = '';
433 }
434 return $item;
435 });
436 }
437
438 add_filter('fluentform/editor_init_element_gdpr_agreement', function ($element) {
439 if (!isset($element['settings']['required_field_message'])) {
440 $element['settings']['required_field_message'] = '';
441 }
442 return $element;
443 });
444
445 add_filter('fluentform/editor_init_element_input_text', function ($element) {
446 if (!isset($element['attributes']['maxlength'])) {
447 $element['attributes']['maxlength'] = '';
448 }
449 return $element;
450 });
451
452 add_filter('fluentform/editor_init_element_textarea', function ($element) {
453 if (!isset($element['attributes']['maxlength'])) {
454 $element['attributes']['maxlength'] = '';
455 }
456 return $element;
457 });
458
459 add_filter('fluentform/editor_init_element_input_date', function ($item) {
460 if (!isset($item['settings']['date_config'])) {
461 $item['settings']['date_config'] = '';
462 }
463 return $item;
464 });
465
466 add_filter('fluentform/editor_init_element_ratings', function ($item) {
467 if (!isset($item['settings']['icon_source'])) {
468 $item['settings']['icon_source'] = 'preset';
469 }
470
471 if (!isset($item['settings']['icon_type'])) {
472 $item['settings']['icon_type'] = \FluentForm\App\Services\FormBuilder\RatingIcon::DEFAULT_ICON;
473 }
474
475 if (!isset($item['settings']['custom_icon_svg'])) {
476 $item['settings']['custom_icon_svg'] = '';
477 }
478
479 if (!isset($item['settings']['inactive_color'])) {
480 $item['settings']['inactive_color'] = \FluentForm\App\Services\FormBuilder\RatingIcon::DEFAULT_INACTIVE_COLOR;
481 }
482
483 if (!isset($item['settings']['active_color'])) {
484 $item['settings']['active_color'] = \FluentForm\App\Services\FormBuilder\RatingIcon::DEFAULT_ACTIVE_COLOR;
485 }
486
487 return $item;
488 });
489
490 add_filter('fluentform/editor_init_element_container', function ($item) {
491 if (!isset($item['settings']['conditional_logics'])) {
492 $item['settings']['conditional_logics'] = [];
493 }
494
495 if (!isset($item['settings']['container_width'])) {
496 $item['settings']['container_width'] = '';
497 }
498
499 if (!isset($item['settings']['is_width_auto_calc'])) {
500 $item['settings']['is_width_auto_calc'] = true;
501 }
502
503 if (!isset($item['settings']['render_recaptcha_v3_badge'])) {
504 $item['settings']['render_recaptcha_v3_badge'] = false;
505 }
506
507 $shouldSetWidth = !empty($item['columns']) && (!isset($item['columns'][0]['width']) || !$item['columns'][0]['width']);
508
509 if ($shouldSetWidth) {
510 $perColumn = round(100 / count($item['columns']), 2);
511
512 foreach ($item['columns'] as &$column) {
513 $column['width'] = $perColumn;
514 }
515 }
516
517 return $item;
518 });
519
520 add_filter('fluentform/editor_init_element_input_number', function ($item) {
521 if (!isset($item['settings']['number_step'])) {
522 $item['settings']['number_step'] = '';
523 }
524 if (!isset($item['settings']['numeric_formatter'])) {
525 $item['settings']['numeric_formatter'] = '';
526 }
527 if (!isset($item['settings']['prefix_label'])) {
528 $item['settings']['prefix_label'] = '';
529 }
530 if (!isset($item['settings']['suffix_label'])) {
531 $item['settings']['suffix_label'] = '';
532 }
533 if (!isset($item['settings']['mobile_keyboard_type_number'])) {
534 $item['settings']['mobile_keyboard_type_number'] = '';
535 }
536
537 return $item;
538 });
539
540 add_filter('fluentform/editor_init_element_input_mask', function ($item) {
541 if (!isset($item['settings']['mobile_keyboard_type'])) {
542 $item['settings']['mobile_keyboard_type'] = '';
543 }
544 return $item;
545 });
546
547 add_filter('fluentform/editor_init_element_input_email', function ($item) {
548 if (!isset($item['settings']['is_unique'])) {
549 $item['settings']['is_unique'] = 'no';
550 }
551 if (!isset($item['settings']['unique_validation_message'])) {
552 $item['settings']['unique_validation_message'] = __('Email address need to be unique.', 'fluentform');
553 }
554 if (!isset($item['settings']['prefix_label'])) {
555 $item['settings']['prefix_label'] = '';
556 }
557 if (!isset($item['settings']['suffix_label'])) {
558 $item['settings']['suffix_label'] = '';
559 }
560 return $item;
561 });
562
563 add_filter('fluentform/editor_init_element_input_text', function ($item) {
564 if (isset($item['attributes']['data-mask'])) {
565 if (!isset($item['settings']['data-mask-reverse'])) {
566 $item['settings']['data-mask-reverse'] = 'no';
567 }
568 if (!isset($item['settings']['data-clear-if-not-match'])) {
569 $item['settings']['data-clear-if-not-match'] = 'no';
570 }
571 } else {
572 if (!isset($item['settings']['is_unique'])) {
573 $item['settings']['is_unique'] = 'no';
574 }
575 if (!isset($item['settings']['unique_validation_message'])) {
576 $item['settings']['unique_validation_message'] = __('This field value need to be unique.', 'fluentform');
577 }
578 }
579
580 if (!isset($item['settings']['prefix_label'])) {
581 $item['settings']['prefix_label'] = '';
582 }
583 if (!isset($item['settings']['suffix_label'])) {
584 $item['settings']['suffix_label'] = '';
585 }
586 return $item;
587 });
588
589 if ($inputs = \FluentForm\App\Modules\Form\FormFieldsParser::getInputs($form, ['element'])) {
590 foreach ($inputs as $input) {
591 add_filter('fluentform/editor_init_element_' . $input['element'], function ($field) {
592 Helper::resolveValidationRulesGlobalOption($field);
593 return $field;
594 });
595 }
596 }
597
598 add_filter('fluentform/editor_init_element_recaptcha', function ($item, $form) {
599 $item['attributes']['name'] = 'g-recaptcha-response';
600 return $item;
601 }, 10, 2);
602
603 add_filter('fluentform/editor_init_element_hcaptcha', function ($item, $form) {
604 $item['attributes']['name'] = 'h-captcha-response';
605 return $item;
606 }, 10, 2);
607
608 add_filter('fluentform/editor_init_element_turnstile', function ($item, $form) {
609 $item['attributes']['name'] = 'cf-turnstile-response';
610 return $item;
611 }, 10, 2);
612
613 add_filter('fluentform/editor_init_element_address', function ($item) {
614 // Initialize autocomplete provider settings
615 if (!isset($item['settings']['autocomplete_provider'])) {
616 // If google autocomplete setting is enabled, set provider to google
617 if (ArrayHelper::get($item, 'settings.enable_g_autocomplete') === 'yes') {
618 $item['settings']['autocomplete_provider'] = 'google';
619 } else {
620 $item['settings']['autocomplete_provider'] = 'none';
621 }
622 }
623 if (!isset($item['settings']['enable_auto_locate'])) {
624 $item['settings']['enable_auto_locate'] = 'on_click'; // on_load, on_click, no
625 }
626 if (!isset($item['settings']['save_coordinates'])) {
627 $item['settings']['save_coordinates'] = 'no';
628 }
629
630 foreach ($item['fields'] as &$addressField) {
631 if (
632 !isset($addressField['settings']['label_placement']) &&
633 !isset($addressField['settings']['label_placement_options'])
634 ) {
635 $addressField['settings']['label_placement'] = '';
636 $addressField['settings']['label_placement_options'] = [
637 [
638 'value' => '',
639 'label' => __('Default', 'fluentform'),
640 ],
641 [
642 'value' => 'top',
643 'label' => __('Top', 'fluentform'),
644 ],
645 [
646 'value' => 'right',
647 'label' => __('Right', 'fluentform'),
648 ],
649 [
650 'value' => 'bottom',
651 'label' => __('Bottom', 'fluentform'),
652 ],
653 [
654 'value' => 'left',
655 'label' => __('Left', 'fluentform'),
656 ],
657 [
658 'value' => 'hide_label',
659 'label' => __('Hidden', 'fluentform'),
660 ],
661 ];
662 }
663 }
664 return $item;
665 });
666
667 add_filter('fluentform/editor_init_element_gdpr_agreement', function ($item, $form) {
668 $isConversationalForm = Helper::isConversionForm($form->id);
669
670 if ($isConversationalForm) {
671 $item['settings']['tc_agree_text'] = __('I accept', 'fluentform');
672 }
673
674 return $item;
675 }, 10, 2);
676
677 add_filter('fluentform/editor_init_element_terms_and_condition', function ($item, $form) {
678 $isConversationalForm = Helper::isConversionForm($form->id);
679
680 if ($isConversationalForm) {
681 $item['settings']['hide_disagree'] = false;
682 }
683
684 return $item;
685 }, 10, 2);
686 }, 10);
687
688 $app->addAction('fluentform/addons_page_render_fluentform_pdf', function () use ($app) {
689 $url = '';
690 if (!defined('FLUENTFORM_PDF_VERSION')) {
691 $url = wp_nonce_url(
692 self_admin_url('update.php?action=install-plugin&plugin=fluentforms-pdf'),
693 'install-plugin_fluentforms-pdf'
694 );
695 }
696
697 $app->view->render('admin.addons.pdf_promo', [
698 'public_url' => fluentFormMix(),
699 'install_url' => $url,
700 'is_installed' => defined('FLUENTFORM_PDF_VERSION'),
701 ]);
702 });
703
704 $app->addAction('fluentform/installed_by', function ($by) {
705 if (is_string($by) && !get_option('_ff_ins_by')) {
706 update_option('_ff_ins_by', sanitize_text_field($by), 'no');
707 }
708 });
709
710 // from Frontend.php
711 if (defined('WP_ROCKET_VERSION')) {
712 add_filter('rocket_excluded_inline_js_content', function ($lines) {
713 $lines[] = 'fluent_form_ff_form_instance';
714 $lines[] = 'fluentFormVars';
715 $lines[] = 'fluentform_payment';
716
717 return $lines;
718 });
719 }
720
721 // from Common.php
722 add_action('save_post', function ($post_id) use ($app) {
723
724 if (!is_post_type_viewable(get_post_type($post_id))) {
725 return;
726 }
727
728 // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Nonce verified by WordPress save_post action
729 $post_content = isset($_REQUEST['post_content']) ? wp_kses_post(wp_unslash($_REQUEST['post_content'])) : false;
730 if (!$post_content || !is_string($post_content)) {
731 $post = get_post($post_id);
732 $post_content = $post->post_content;
733 }
734
735 $shortcodeIds = Helper::getShortCodeIds(
736 $post_content,
737 'fluentform',
738 'id'
739 );
740
741 $attributes = ArrayHelper::get($shortcodeIds, 'attributes', []);
742 ArrayHelper::forget($shortcodeIds, 'attributes');
743
744 $shortcodeModalIds = Helper::getShortCodeIds(
745 $post_content,
746 'fluentform_modal',
747 'form_id'
748 );
749
750 $gutenbergIds = Helper::getFormsIdsFromBlocks($post_content);
751
752 if ($shortcodeModalIds) {
753 $modalAttributes = ArrayHelper::get($shortcodeModalIds, 'attributes', []);
754 ArrayHelper::forget($shortcodeModalIds, 'attributes');
755
756 $shortcodeIds = array_merge($shortcodeIds, $shortcodeModalIds);
757
758 if ($modalAttributes) {
759 $attributes = array_merge($attributes, $modalAttributes);
760 }
761 }
762
763 if ($gutenbergIds) {
764 $blockAttributes = ArrayHelper::get($gutenbergIds, 'attributes', []);
765 ArrayHelper::forget($gutenbergIds, 'attributes');
766
767 $shortcodeIds = array_merge($shortcodeIds, $gutenbergIds);
768
769 if ($blockAttributes) {
770 $attributes = array_merge($attributes, $blockAttributes);
771 }
772 }
773
774 $shortcodeIds = array_unique($shortcodeIds);
775
776 if ($attributes) {
777 $data = [];
778
779 foreach ($attributes as $attribute) {
780 $data[$attribute['formId']]['themes'][] = $attribute['theme'];
781 }
782
783 $shortcodeIds['attributes'] = $data;
784 }
785
786 if ($shortcodeIds) {
787 update_post_meta($post_id, '_has_fluentform', $shortcodeIds);
788 } elseif (get_post_meta($post_id, '_has_fluentform', true)) {
789 update_post_meta($post_id, '_has_fluentform', []);
790 }
791 });
792
793 $fluentformComponent = new Component($app);
794 $fluentformComponent->addRendererActions();
795 $fluentformComponent->addFluentFormShortCode();
796 $fluentformComponent->addFluentFormDefaultValueParser();
797 $fluentformComponent->addFluentformSubmissionInsertedFilter();
798 $fluentformComponent->addIsRenderableFilter();
799 $fluentformComponent->registerInputSanitizers();
800
801 add_action('wp', function () use ($app) {
802 // @todo: We will remove the fluentform_pages check from April 2021
803 $fluentFormPages = $app->request->get('fluent_forms_pages') || $app->request->get('fluentform_pages');
804
805 if ($fluentFormPages) {
806 add_action('wp_enqueue_scripts', function () use ($app) {
807 wp_enqueue_script('jquery');
808 wp_enqueue_script(
809 'fluent_forms_global',
810 fluentFormMix('js/fluent_forms_global.js'),
811 ['jquery'],
812 FLUENTFORM_VERSION,
813 true
814 );
815 $globalVars = [
816 'ajaxurl' => Helper::getAjaxUrl(),
817 'global_search_active' => apply_filters('fluentform/global_search_active', 'yes'),
818 'rest' => Helper::getRestInfo(),
819 ];
820 if (Acl::hasAnyFormPermission()) {
821 $globalVars['fluent_forms_admin_nonce'] = wp_create_nonce('fluent_forms_admin_nonce');
822 }
823 wp_localize_script('fluent_forms_global', 'fluent_forms_global_var', $globalVars);
824 wp_enqueue_style('fluent-form-styles');
825 $form = wpFluent()->table('fluentform_forms')->find(intval($app->request->get('preview_id')));
826 $postId = get_the_ID() ? get_the_ID() : 0;
827
828 $loadPublicStyle = apply_filters_deprecated(
829 'fluentform_load_default_public',
830 [
831 true,
832 $form,
833 $postId,
834 ],
835 FLUENTFORM_FRAMEWORK_UPGRADE,
836 'fluentform/load_default_public',
837 'Use fluentform/load_default_public instead of fluentform_load_default_public.'
838 );
839
840 if (apply_filters('fluentform/load_default_public', $loadPublicStyle, $form, $postId)) {
841 wp_enqueue_style('fluentform-public-default');
842 }
843 wp_enqueue_script('fluent-form-submission');
844 wp_enqueue_style('fluent-form-preview', fluentFormMix('css/preview.css'), [], FLUENTFORM_VERSION);
845 if (!defined('FLUENTFORMPRO')) {
846 wp_enqueue_script(
847 'fluentform-preview_app',
848 fluentFormMix('js/form_preview_app.js'),
849 ['jquery'],
850 FLUENTFORM_VERSION,
851 true
852 );
853
854 wp_localize_script('fluentform-preview_app', 'fluent_preview_var', [
855 'i18n' => \FluentForm\App\Modules\Registerer\TranslationString::getPreviewI18n(),
856 ]);
857 }
858 });
859
860 (new \FluentForm\App\Modules\ProcessExteriorModule())->handleExteriorPages();
861 }
862 }, 1);
863
864 // Register api response log hooks
865 $app->addAction(
866 'fluentform/after_submission_api_response_success',
867 function ($form, $entryId, $data, $feed, $res, $msg = '') {
868 fluentform_after_submission_api_response_success($form, $entryId, $data, $feed, $res, $msg = '');
869 },
870 10,
871 6
872 );
873
874 $app->addAction(
875 'fluentform/after_submission_api_response_failed',
876 function ($form, $entryId, $data, $feed, $res, $msg = '') {
877 fluentform_after_submission_api_response_failed($form, $entryId, $data, $feed, $res, $msg = '');
878 },
879 10,
880 6
881 );
882
883 function fluentform_after_submission_api_response_success($form, $entryId, $data, $feed, $res, $msg = '')
884 {
885 try {
886 $isDev = 'production' != wpFluentForm()->getEnv();
887
888 $isDev = apply_filters_deprecated(
889 'fluentform_api_success_log',
890 [
891 $isDev,
892 $form,
893 $feed,
894 ],
895 FLUENTFORM_FRAMEWORK_UPGRADE,
896 'fluentform/api_success_log',
897 'Use fluentform/api_success_log instead of fluentform_api_success_log.'
898 );
899
900 if (!apply_filters('fluentform/api_success_log', $isDev, $form, $feed)) {
901 return;
902 }
903
904 wpFluent()->table('fluentform_submission_meta')->insert([
905 'response_id' => $entryId,
906 'form_id' => $form->id,
907 'meta_key' => 'api_log',
908 'value' => $msg,
909 'name' => $feed->formattedValue['name'],
910 'status' => 'success',
911 'created_at' => current_time('mysql'),
912 'updated_at' => current_time('mysql'),
913 ]);
914 } catch (Exception $e) {
915 if (defined('WP_DEBUG') && WP_DEBUG) {
916 // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log -- Debug logging only when WP_DEBUG is enabled, helps developers troubleshoot shortcode parsing issues
917 error_log($e->getMessage());
918 }
919 return '';
920 }
921 }
922
923 function fluentform_after_submission_api_response_failed($form, $entryId, $data, $feed, $res, $msg = '')
924 {
925 try {
926 $isDev = 'production' != wpFluentForm()->getEnv();
927
928 $isDev = apply_filters_deprecated(
929 'fluentform_api_failed_log',
930 [
931 $isDev,
932 $form,
933 $feed,
934 ],
935 FLUENTFORM_FRAMEWORK_UPGRADE,
936 'fluentform/api_failed_log',
937 'Use fluentform/api_failed_log instead of fluentform_api_failed_log.'
938 );
939
940 if (!apply_filters('fluentform/api_failed_log', $isDev, $form, $feed)) {
941 return;
942 }
943
944 wpFluent()->table('fluentform_submission_meta')->insert([
945 'response_id' => $entryId,
946 'form_id' => $form->id,
947 'meta_key' => 'api_log',
948 'value' => json_encode($res),
949 'name' => $feed->formattedValue['name'],
950 'status' => 'failed',
951 'created_at' => current_time('mysql'),
952 'updated_at' => current_time('mysql'),
953 ]);
954 } catch (Exception $e) {
955 // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log -- Intentional logging for debugging
956 error_log($e->getMessage());
957 }
958 }
959
960 $app->addAction('fluentform/before_form_render', function ($form, $atts) {
961 $theme = ArrayHelper::get($atts, 'theme');
962
963 $styles = $theme ? [$theme] : [];
964
965 do_action(
966 'fluentform/load_form_assets',
967 $form->id,
968 $styles
969 );
970 }, 10, 2);
971
972 add_action('fluentform/load_form_assets', function ($formId, $styles = []) {
973 $formAssetLoader = (new \FluentForm\App\Modules\Form\Settings\FormCssJs());
974
975 $formAssetLoader->addCustomCssJs($formId);
976
977 $notLoadedStyles = [];
978
979 foreach ($styles as $style) {
980 if (!did_action('fluent_form/loaded_styler_' . $formId . '_' . $style)) {
981 $notLoadedStyles[] = $style;
982 }
983 }
984
985 // check if already loaded
986 if ($notLoadedStyles) {
987 $formAssetLoader->addStylerCSS($formId, $notLoadedStyles);
988 }
989 }, 10, 2);
990
991 $app->addAction('fluentform/submission_inserted', function ($insertId, $formData, $form) use ($app) {
992 $notificationManager = new \FluentForm\App\Hooks\Handlers\GlobalNotificationHandler($app);
993 $notificationManager->globalNotify($insertId, $formData, $form);
994 }, 10, 3);
995
996 $app->addAction('fluentform/schedule_feed', function ($queueId) use ($app) {
997 $scheduler = $app['fluentFormAsyncRequest'];
998
999 $scheduler->process($queueId);
1000 });
1001
1002 $app->addAction('init', function () use ($app) {
1003 new \FluentForm\App\Services\Integrations\MailChimp\MailChimpIntegration($app);
1004 new \FluentForm\App\Modules\Form\TokenBasedSpamProtection($app);
1005 // Load payment module
1006 if (Helper::isPaymentCompatible()) {
1007 (new FluentForm\App\Modules\Payments\PaymentHandler())->init();
1008 }
1009 });
1010
1011 $app->addAction('fluentform/form_element_start', function ($form) use ($app) {
1012 $honeyPot = new \FluentForm\App\Modules\Form\HoneyPot($app);
1013 $honeyPot->renderHoneyPot($form);
1014
1015 $tokenBasedSpamProtection = new \FluentForm\App\Modules\Form\TokenBasedSpamProtection($app);
1016 $tokenBasedSpamProtection->renderTokenField($form);
1017
1018 $cleanTalk = new \FluentForm\App\Modules\Form\CleanTalkHandler();
1019 $cleanTalk->setCleanTalkScript();
1020 });
1021
1022 $app->addAction('fluentform/before_insert_submission', function ($insertData, $requestData, $form) use ($app) {
1023 $honeyPot = new \FluentForm\App\Modules\Form\HoneyPot($app);
1024 $honeyPot->verify($insertData, $requestData, $form->id);
1025
1026 $tokenBasedSpamProtection = new \FluentForm\App\Modules\Form\TokenBasedSpamProtection($app);
1027 $tokenBasedSpamProtection->verify($insertData, $requestData, $form->id);
1028 }, 9, 3);
1029
1030 // The token-based spam check (FINDING-25) enforces on conversational forms too, but its ~1h TTL
1031 // token cannot be refreshed by the conversational JS app — it bakes hidden inputs statically at
1032 // render, so behind a full-page cache the token expires and rejects every legitimate submission.
1033 // Disable ONLY the token for conversational forms, resolved from server-side form meta (never the
1034 // client-supplied isFFConversational flag, which was the original bypass). The honeypot still applies.
1035 $app->addFilter('fluentform/token_based_spam_protection_status', function ($status, $formId) {
1036 if ($status && \FluentForm\App\Helpers\Helper::isConversionForm($formId)) {
1037 return false;
1038 }
1039 return $status;
1040 }, 10, 2);
1041
1042 // Maybe update current user allowed form ids,
1043 // if current user has specific form permission and capable to create form
1044 $app->addAction('fluentform/inserted_new_form', function ($formId) {
1045 \FluentForm\App\Services\Manager\FormManagerService::maybeAddUserAllowedFormIds($formId);
1046 });
1047
1048 add_action('fluentform/log_data', function ($data) use ($app) {
1049 $dataLogger = new \FluentForm\App\Modules\Logger\DataLogger($app);
1050 $dataLogger->log($data);
1051 });
1052
1053 // Support for third party plugin who do_action this hook on previous way (before 5.0.0 way)
1054 // In Fluent Forms 5.0.0 'ff_log_data' add_action replaced with action named 'fluentform/log_data'.
1055 // @todo - notify them for updating do_action name 'fluentform/log_data'.
1056 // @todo - We will remove bellow add_action after 2 or more version release latter.
1057 add_action('ff_log_data', function ($data) use ($app) {
1058 $dataLogger = new \FluentForm\App\Modules\Logger\DataLogger($app);
1059 $dataLogger->log($data);
1060 });
1061
1062 // widgets
1063 add_action('widgets_init', function () {
1064 register_widget('FluentForm\App\Modules\Widgets\SidebarWidgets');
1065 });
1066
1067 add_action('wp', function () {
1068 global $post;
1069
1070 if (!is_a($post, 'WP_Post')) {
1071 return;
1072 }
1073
1074 $fluentFormIds = get_post_meta($post->ID, '_has_fluentform', true);
1075 $attributes = ArrayHelper::get($fluentFormIds, 'attributes', []);
1076
1077 if (isset($fluentFormIds['attributes'])) {
1078 unset($fluentFormIds['attributes']);
1079 }
1080
1081 if ($fluentFormIds && is_array($fluentFormIds)) {
1082 foreach ($fluentFormIds as $formId) {
1083 do_action(
1084 'fluentform/load_form_assets',
1085 $formId,
1086 array_unique(ArrayHelper::get($attributes, $formId . '.themes', []))
1087 );
1088 }
1089 }
1090 });
1091
1092 add_filter('cron_schedules', function ($schedules) {
1093 $schedules['ff_every_five_minutes'] = [
1094 'interval' => 300,
1095 'display' => 'Every 5 minutes (FluentForm)',
1096 ];
1097
1098 return $schedules;
1099 }, 10, 1);
1100
1101 add_action('fluentform_do_scheduled_tasks', 'fluentFormHandleScheduledTasks');
1102 add_action('fluentform_do_email_report_scheduled_tasks', 'fluentFormHandleScheduledEmailReport');
1103
1104 add_action('fluentform/integration_action_result', function ($feed, $status, $note = '') {
1105 if (!isset($feed['scheduled_action_id']) || !$status) {
1106 return;
1107 }
1108 if (!$note) {
1109 $note = $status;
1110 }
1111
1112 $note = is_scalar($note)
1113 ? sanitize_text_field(wp_unslash((string) $note))
1114 : sanitize_text_field((string) wp_json_encode($note));
1115
1116 if (strlen($note) > 255) {
1117 if (function_exists('mb_substr')) {
1118 $note = mb_substr($note, 0, 251) . '...';
1119 } else {
1120 $note = substr($note, 0, 251) . '...';
1121 }
1122 }
1123
1124 $actionId = intval($feed['scheduled_action_id']);
1125 wpFluent()->table('ff_scheduled_actions')
1126 ->where('id', $actionId)
1127 ->update([
1128 'status' => $status,
1129 'note' => $note,
1130 'updated_at' => current_time('mysql'),
1131 ]);
1132 }, 10, 3);
1133
1134
1135 // Support for third party plugin who do_action this hook on previous way (before 5.0.0 way)
1136 // In Fluent Forms 5.0.0 'ff_integration_action_result' add_action replaced in above action named 'fluentform/integration_action_result'.
1137 // @todo - notify them for updating do_action name 'fluentform/integration_action_result'.
1138 // @todo - We will remove bellow add_action after 2 or more version release latter.
1139 add_action('ff_integration_action_result', function ($feed, $status, $note = '') {
1140 if (!isset($feed['scheduled_action_id']) || !$status) {
1141 return;
1142 }
1143 if (!$note) {
1144 $note = $status;
1145 }
1146
1147 $note = is_scalar($note)
1148 ? sanitize_text_field(wp_unslash((string) $note))
1149 : sanitize_text_field((string) wp_json_encode($note));
1150
1151 if (strlen($note) > 255) {
1152 if (function_exists('mb_substr')) {
1153 $note = mb_substr($note, 0, 251) . '...';
1154 } else {
1155 $note = substr($note, 0, 251) . '...';
1156 }
1157 }
1158
1159 $actionId = intval($feed['scheduled_action_id']);
1160 wpFluent()->table('ff_scheduled_actions')
1161 ->where('id', $actionId)
1162 ->update([
1163 'status' => $status,
1164 'note' => $note,
1165 ]);
1166 }, 10, 3);
1167
1168 add_action('fluentform/global_notify_completed', function ($insertId, $form) use ($app) {
1169 $isTruncate = apply_filters_deprecated(
1170 'fluentform_truncate_password_values',
1171 [
1172 true,
1173 $form->id,
1174 ],
1175 FLUENTFORM_FRAMEWORK_UPGRADE,
1176 'fluentform/truncate_password_values',
1177 'Use fluentform/truncate_password_values instead of fluentform_truncate_password_values.'
1178 );
1179
1180 if (strpos($form->form_fields, '"element":"input_password"') && apply_filters('fluentform/truncate_password_values', $isTruncate, $form->id)) {
1181 // we have password
1182 (new \FluentForm\App\Services\Integrations\GlobalNotificationService())->cleanUpPassword($insertId, $form);
1183 }
1184 }, 10, 2);
1185
1186 /*
1187 * Elementor Block Init
1188 */
1189
1190 if (defined('ELEMENTOR_VERSION')) {
1191 new \FluentForm\App\Modules\Widgets\ElementorWidget($app);
1192 }
1193 /*
1194 * Oxygen Widget Init
1195 */
1196
1197 add_action('init', function () {
1198 if (class_exists('OxyEl')) {
1199 if (file_exists(FLUENTFORM_DIR_PATH . 'app/Modules/Widgets/OxygenWidget.php')) {
1200 new FluentForm\App\Modules\Widgets\OxygenWidget();
1201 }
1202 }
1203 });
1204
1205 (new FluentForm\App\Services\Integrations\Slack\SlackNotificationActions($app))->register();
1206
1207 /*
1208 * Smartcode parser shortcodes
1209 */
1210
1211 new \FluentForm\App\Services\FormBuilder\Components\CustomSubmitButton();
1212
1213 add_action('enqueue_block_editor_assets', function () {
1214
1215 wp_enqueue_script(
1216 'fluentform-gutenberg-block',
1217 fluentFormMix('js/fluent_gutenblock.js'),
1218 ['wp-element', 'wp-polyfill', 'wp-i18n', 'wp-blocks', 'wp-components','wp-server-side-render', 'wp-block-editor'],
1219 FLUENTFORM_VERSION,
1220 true
1221 );
1222 wp_enqueue_style(
1223 'fluentform-gutenberg-block',
1224 fluentFormMix('css/fluent_gutenblock.css'),
1225 ['wp-edit-blocks'],
1226 FLUENTFORM_VERSION
1227 );
1228
1229 $forms = wpFluent()->table('fluentform_forms')
1230 ->select(['id', 'title'])
1231 ->orderBy('id', 'DESC')
1232 ->get()
1233 ->toArray();
1234
1235 array_unshift($forms, (object) [
1236 'id' => '',
1237 'title' => __('-- Select a form --', 'fluentform'),
1238 ]);
1239
1240 $presets = [
1241 [
1242 'label' => __('Default (Form Styler)', 'fluentform'),
1243 'value' => '',
1244 ],
1245 [
1246 'label' => __('Inherit Theme Style', 'fluentform'),
1247 'value' => 'ffs_inherit_theme',
1248 ],
1249 ];
1250
1251 $presets = apply_filters('fluentform/block_editor_style_presets', $presets);
1252
1253 wp_localize_script('fluentform-gutenberg-block', 'fluentform_block_vars', [
1254 'logo' => fluentFormMix('img/fluent_icon.svg'),
1255 'forms' => $forms,
1256 'style_presets' => $presets,
1257 'theme_style' => apply_filters('fluentform/load_theme_style', false) ? 'ffs_inherit_theme' : '',
1258 'conversational_demo_img' => fluentFormMix('img/conversational-form-demo.png'),
1259 'rest' => Helper::getRestInfo(),
1260 ]);
1261
1262 wp_enqueue_style(
1263 'fluentform-gutenberg-block',
1264 fluentFormMix('css/fluent_gutenblock.css'),
1265 ['wp-edit-blocks'],
1266 FLUENTFORM_VERSION
1267 );
1268 $fluentFormPublicCss = fluentFormMix('css/fluent-forms-public.css');
1269 $fluentFormPublicDefaultCss = fluentFormMix('css/fluentform-public-default.css');
1270
1271 if (is_rtl()) {
1272 $fluentFormPublicCss = fluentFormMix('css/fluent-forms-public-rtl.css');
1273 $fluentFormPublicDefaultCss = fluentFormMix('css/fluentform-public-default-rtl.css');
1274 }
1275
1276 wp_enqueue_style(
1277 'fluent-form-styles',
1278 $fluentFormPublicCss,
1279 [],
1280 FLUENTFORM_VERSION
1281 );
1282
1283 // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Checking post ID in admin context
1284 $post_id = isset($_GET['post']) ? (int) $_GET['post'] : 0;
1285 $loadPublicStyle = apply_filters_deprecated(
1286 'fluentform_load_default_public',
1287 [
1288 true,
1289 (object) [],
1290 $post_id,
1291 ],
1292 FLUENTFORM_FRAMEWORK_UPGRADE,
1293 'fluentform/load_default_public',
1294 'Use fluentform/load_default_public instead of fluentform_load_default_public.'
1295 );
1296
1297 if (apply_filters('fluentform/load_default_public', $loadPublicStyle, (object) [], $post_id)) {
1298 wp_enqueue_style(
1299 'fluentform-public-default',
1300 $fluentFormPublicDefaultCss,
1301 [],
1302 FLUENTFORM_VERSION
1303 );
1304 }
1305 });
1306
1307
1308 if (function_exists('register_block_type')) {
1309 add_action('init', function () {
1310 // Use the dedicated GutenbergBlock class for block registration and rendering
1311 \FluentForm\App\Services\Blocks\GutenbergBlock::register();
1312 });
1313 }
1314
1315
1316 add_action('fluentform/before_updating_form', function ($form, $postData) {
1317 (new FluentForm\App\Services\Form\HistoryService())->init($form, $postData);
1318 }, 10, 2);
1319
1320
1321 // WordPress 6.3+ uses iframes for block editor preview
1322 // Official WordPress solution: Use enqueue_block_assets with proper context checking
1323 // See: https://make.wordpress.org/core/2023/07/18/miscellaneous-editor-changes-in-wordpress-6-3/
1324 add_action('enqueue_block_assets', function () {
1325 // enqueue_block_assets also fires on the front end, where wp_enqueue_scripts already loads these conditionally.
1326 if (!is_admin()) {
1327 return;
1328 }
1329
1330 $current_screen = function_exists('get_current_screen') ? get_current_screen() : null;
1331 if ($current_screen && !$current_screen->is_block_editor()) {
1332 return;
1333 }
1334
1335 // Enqueue Fluent Forms CSS for block editor iframe preview
1336 // These styles are necessary for the live form preview in the block editor
1337 wp_enqueue_style('fluent-forms-public', fluentFormMix('css/fluent-forms-public.css'), [], FLUENTFORM_VERSION);
1338 wp_enqueue_style('fluentform-public-default', fluentFormMix('css/fluentform-public-default.css'), [], FLUENTFORM_VERSION);
1339 });
1340
1341
1342
1343 // require the CLI
1344 if (defined('WP_CLI') && WP_CLI) {
1345 \WP_CLI::add_command('fluentform', '\FluentForm\App\Modules\CLI\Commands');
1346 }
1347