PluginProbe
Fluent Forms – Customizable Contact Forms, Survey, Quiz, & Conversational Form Builder / 6.2.12
Fluent Forms – Customizable Contact Forms, Survey, Quiz, & Conversational Form Builder v6.2.12
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.12, at app/Hooks/actions.php

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