| @@ -1,11 +1,12 @@ | ||
| 1 | 1 | <?php |
| 2 | 2 | |
| 3 | -defined('ABSPATH') or die; | |
| 3 | +defined('ABSPATH') || die; | |
| 4 | 4 | |
| 5 | 5 | use FluentForm\App\Modules\Component\Component; |
| 6 | 6 | use FluentForm\App\Modules\Acl\Acl; |
| 7 | 7 | use FluentForm\App\Helpers\Helper; |
| 8 | +use FluentForm\App\Services\FormBuilder\LegacyDateConfigDecoder; | |
| 8 | 9 | use FluentForm\Framework\Helpers\ArrayHelper; |
| 9 | 10 | |
| 10 | 11 | /** |
| 11 | 12 | * All registered action's handlers should be in app\Hooks\Handlers, |
| @@ -10,14 +11,16 @@ | ||
| 10 | 11 | /** |
| 11 | 12 | * All registered action's handlers should be in app\Hooks\Handlers, |
| 12 | 13 | * addAction is similar to add_action and addCustomAction is just a |
| 13 | 14 | * 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 | + * using the plugin slug to make it unique in all WordPress plugins, | |
| 15 | 16 | * ex: $app->addCustomAction('foo', ['FooHandler', 'handleFoo']) is |
| 16 | 17 | * equivalent to add_action('slug-foo', ['FooHandler', 'handleFoo']). |
| 17 | 18 | */ |
| 18 | 19 | |
| 19 | 20 | /** |
| 21 | + * Application instance. | |
| 22 | + * | |
| 20 | 23 | * @var $app FluentForm\Framework\Foundation\Application |
| 21 | 24 | */ |
| 22 | 25 | |
| 23 | 26 | // From MenuProvider.php |
| @@ -69,8 +72,23 @@ | ||
| 69 | 72 | (new \FluentForm\App\Modules\Renderer\GlobalSettings\Settings($app))->render(); |
| 70 | 73 | } |
| 71 | 74 | ); |
| 72 | 75 | |
| 76 | +/** | |
| 77 | + * Pro 6.2.13+ supplies the REST API used by Free's Vue license screen. Older | |
| 78 | + * Pro versions keep rendering their PHP page through this component action. | |
| 79 | + */ | |
| 80 | +$app->addAction( | |
| 81 | + 'fluentform/global_settings_component_license_page', | |
| 82 | + function () use ($app) { | |
| 83 | + if (!defined('FLUENTFORMPRO_VERSION') || version_compare(FLUENTFORMPRO_VERSION, '6.2.13', '<')) { | |
| 84 | + return; | |
| 85 | + } | |
| 86 | + | |
| 87 | + (new \FluentForm\App\Modules\Renderer\GlobalSettings\Settings($app))->render('license'); | |
| 88 | + } | |
| 89 | +); | |
| 90 | + | |
| 73 | 91 | // Register DefaultStyleApplicator on init so it works for REST API requests too |
| 74 | 92 | add_action('init', function () { |
| 75 | 93 | new \FluentForm\App\Modules\Form\DefaultStyleApplicator(); |
| 76 | 94 | }, 9); |
| @@ -150,9 +168,9 @@ | ||
| 150 | 168 | 'fluent_forms_docs', |
| 151 | 169 | 'fluent_forms_all_entries', |
| 152 | 170 | 'msformentries', |
| 153 | 171 | 'fluent_forms_payment_entries', |
| 154 | - 'fluent_forms_reports' | |
| 172 | + 'fluent_forms_reports', | |
| 155 | 173 | ]; |
| 156 | 174 | |
| 157 | 175 | $page = wpFluentForm('request')->get('page'); |
| 158 | 176 | |
| @@ -159,8 +177,10 @@ | ||
| 159 | 177 | if ($page && in_array($page, $disablePages)) { |
| 160 | 178 | remove_all_actions('admin_notices'); |
| 161 | 179 | \FluentForm\App\Modules\Registerer\ReviewQuery::register(); |
| 162 | 180 | \FluentForm\App\Modules\Registerer\MigrationNotice::register(); |
| 181 | + \FluentForm\App\Modules\Registerer\StripeKeyNotice::register(); | |
| 182 | + \FluentForm\App\Modules\Registerer\CaptchaKeyNotice::register(); | |
| 163 | 183 | } |
| 164 | 184 | }); |
| 165 | 185 | |
| 166 | 186 | add_action('wp_print_scripts', function () { |
| @@ -171,9 +191,9 @@ | ||
| 171 | 191 | |
| 172 | 192 | $isSkip = apply_filters_deprecated( |
| 173 | 193 | 'fluentform_skip_no_conflict', |
| 174 | 194 | [ |
| 175 | - $isSkip | |
| 195 | + $isSkip, | |
| 176 | 196 | ], |
| 177 | 197 | FLUENTFORM_FRAMEWORK_UPGRADE, |
| 178 | 198 | 'fluentform/skip_no_conflict', |
| 179 | 199 | 'Use fluentform/skip_no_conflict instead of fluentform_skip_no_conflict.' |
| @@ -228,8 +248,20 @@ | ||
| 228 | 248 | } |
| 229 | 249 | return $field; |
| 230 | 250 | }); |
| 231 | 251 | |
| 252 | + add_filter('fluentform/editor_init_element_step_start', function ($item) { | |
| 253 | + if (!isset($item['settings']['progress_layout'])) { | |
| 254 | + $item['settings']['progress_layout'] = 'top'; | |
| 255 | + } | |
| 256 | + | |
| 257 | + if (!isset($item['settings']['tabs_show_progress_bar'])) { | |
| 258 | + $item['settings']['tabs_show_progress_bar'] = 'no'; | |
| 259 | + } | |
| 260 | + | |
| 261 | + return $item; | |
| 262 | + }); | |
| 263 | + | |
| 232 | 264 | $upgradableCheckInputs = [ |
| 233 | 265 | 'input_radio', |
| 234 | 266 | 'select', |
| 235 | 267 | 'select_country', |
| @@ -266,8 +298,50 @@ | ||
| 266 | 298 | if (!isset($element['settings']['dynamic_default_value'])) { |
| 267 | 299 | $element['settings']['dynamic_default_value'] = ''; |
| 268 | 300 | } |
| 269 | 301 | |
| 302 | + // The editor only renders a rule the field already carries, so forms | |
| 303 | + // built before selection limits existed need the keys backfilled. | |
| 304 | + $isMultiSelect = 'select' == $upgradeElement | |
| 305 | + && \FluentForm\Framework\Helpers\ArrayHelper::get($element, 'attributes.multiple'); | |
| 306 | + | |
| 307 | + if ('input_checkbox' == $upgradeElement || $isMultiSelect) { | |
| 308 | + $rules = \FluentForm\Framework\Helpers\ArrayHelper::get($element, 'settings.validation_rules', []); | |
| 309 | + | |
| 310 | + foreach (['max_selection', 'min_selection'] as $selectionRule) { | |
| 311 | + if (isset($rules[$selectionRule])) { | |
| 312 | + continue; | |
| 313 | + } | |
| 314 | + | |
| 315 | + $globalMessage = \FluentForm\App\Helpers\Helper::getGlobalDefaultMessage($selectionRule); | |
| 316 | + | |
| 317 | + // Carry the legacy ceiling across, or the editor would show | |
| 318 | + // "no limit" on a form that has one and drop it on save. | |
| 319 | + $value = ''; | |
| 320 | + if ('max_selection' === $selectionRule && $isMultiSelect) { | |
| 321 | + $value = \FluentForm\Framework\Helpers\ArrayHelper::get($element, 'settings.max_selection', ''); | |
| 322 | + } | |
| 323 | + | |
| 324 | + $rules[$selectionRule] = [ | |
| 325 | + 'value' => $value, | |
| 326 | + 'message' => $globalMessage, | |
| 327 | + 'global_message' => $globalMessage, | |
| 328 | + 'global' => true, | |
| 329 | + ]; | |
| 330 | + } | |
| 331 | + | |
| 332 | + // Key order is the panel's layout order. Rebuilt rather than | |
| 333 | + // appended, so forms saved by an earlier build get it too. | |
| 334 | + $ordered = []; | |
| 335 | + foreach (['required', 'max_selection', 'min_selection'] as $key) { | |
| 336 | + if (isset($rules[$key])) { | |
| 337 | + $ordered[$key] = $rules[$key]; | |
| 338 | + } | |
| 339 | + } | |
| 340 | + | |
| 341 | + $element['settings']['validation_rules'] = $ordered + $rules; | |
| 342 | + } | |
| 343 | + | |
| 270 | 344 | if ('select_country' != $upgradeElement && !isset($element['settings']['randomize_options'])) { |
| 271 | 345 | $element['settings']['randomize_options'] = 'no'; |
| 272 | 346 | } |
| 273 | 347 | |
| @@ -296,9 +370,11 @@ | ||
| 296 | 370 | if ('select_country' != $upgradeElement && !isset($element['settings']['values_visible'])) { |
| 297 | 371 | $element['settings']['values_visible'] = false; |
| 298 | 372 | } |
| 299 | 373 | |
| 300 | - | |
| 374 | + if ('select' == $upgradeElement && !isset($element['settings']['enable_option_groups'])) { | |
| 375 | + $element['settings']['enable_option_groups'] = 'no'; | |
| 376 | + } | |
| 301 | 377 | |
| 302 | 378 | return $element; |
| 303 | 379 | }); |
| 304 | 380 | } |
| @@ -314,18 +390,41 @@ | ||
| 314 | 390 | } |
| 315 | 391 | if (!isset($element['settings']['file_location_type'])) { |
| 316 | 392 | $element['settings']['file_location_type'] = 'follow_global_settings'; |
| 317 | 393 | } |
| 394 | + if ('input_image' === $element['element']) { | |
| 395 | + if (!isset($element['settings']['enable_crop'])) { | |
| 396 | + $element['settings']['enable_crop'] = 'no'; | |
| 397 | + } | |
| 398 | + if (!isset($element['settings']['crop_mode'])) { | |
| 399 | + $element['settings']['crop_mode'] = ( | |
| 400 | + isset($element['settings']['enforce_image_dimensions']) && | |
| 401 | + 'yes' === $element['settings']['enforce_image_dimensions'] | |
| 402 | + ) ? 'dimensions' : 'ratio'; | |
| 403 | + } | |
| 404 | + if (!isset($element['settings']['crop_ratio'])) { | |
| 405 | + $element['settings']['crop_ratio'] = 'free'; | |
| 406 | + } | |
| 407 | + if (!isset($element['settings']['enforce_image_dimensions'])) { | |
| 408 | + $element['settings']['enforce_image_dimensions'] = 'no'; | |
| 409 | + } | |
| 410 | + if (!isset($element['settings']['crop_width'])) { | |
| 411 | + $element['settings']['crop_width'] = ''; | |
| 412 | + } | |
| 413 | + if (!isset($element['settings']['crop_height'])) { | |
| 414 | + $element['settings']['crop_height'] = ''; | |
| 415 | + } | |
| 416 | + } | |
| 318 | 417 | return $element; |
| 319 | 418 | }); |
| 320 | 419 | } |
| 321 | - | |
| 420 | + | |
| 322 | 421 | $prefixSuffixInputs = [ |
| 323 | 422 | 'textarea', |
| 324 | 423 | 'input_url', |
| 325 | 424 | 'input_password', |
| 326 | 425 | ]; |
| 327 | - | |
| 426 | + | |
| 328 | 427 | foreach ($prefixSuffixInputs as $inputType) { |
| 329 | 428 | add_filter('fluentform/editor_init_element_' . $inputType, function ($item) { |
| 330 | 429 | if (!isset($item['settings']['prefix_label'])) { |
| 331 | 430 | $item['settings']['prefix_label'] = ''; |
| @@ -335,9 +434,9 @@ | ||
| 335 | 434 | } |
| 336 | 435 | return $item; |
| 337 | 436 | }); |
| 338 | 437 | } |
| 339 | - | |
| 438 | + | |
| 340 | 439 | add_filter('fluentform/editor_init_element_gdpr_agreement', function ($element) { |
| 341 | 440 | if (!isset($element['settings']['required_field_message'])) { |
| 342 | 441 | $element['settings']['required_field_message'] = ''; |
| 343 | 442 | } |
| @@ -361,12 +460,40 @@ | ||
| 361 | 460 | add_filter('fluentform/editor_init_element_input_date', function ($item) { |
| 362 | 461 | if (!isset($item['settings']['date_config'])) { |
| 363 | 462 | $item['settings']['date_config'] = ''; |
| 364 | 463 | } |
| 464 | + // Show the executable form of any legacy 6.2.7-6.2.12 tokens; only a trusted author's verbatim save persists it (restricted saves keep the stored value). | |
| 465 | + $decoded = LegacyDateConfigDecoder::decode((string) $item['settings']['date_config']); | |
| 466 | + if (null !== $decoded) { | |
| 467 | + $item['settings']['date_config'] = $decoded; | |
| 468 | + } | |
| 365 | 469 | return $item; |
| 366 | 470 | }); |
| 367 | 471 | |
| 472 | + add_filter('fluentform/editor_init_element_ratings', function ($item) { | |
| 473 | + if (!isset($item['settings']['icon_source'])) { | |
| 474 | + $item['settings']['icon_source'] = 'preset'; | |
| 475 | + } | |
| 368 | 476 | |
| 477 | + if (!isset($item['settings']['icon_type'])) { | |
| 478 | + $item['settings']['icon_type'] = \FluentForm\App\Services\FormBuilder\RatingIcon::DEFAULT_ICON; | |
| 479 | + } | |
| 480 | + | |
| 481 | + if (!isset($item['settings']['custom_icon_svg'])) { | |
| 482 | + $item['settings']['custom_icon_svg'] = ''; | |
| 483 | + } | |
| 484 | + | |
| 485 | + if (!isset($item['settings']['inactive_color'])) { | |
| 486 | + $item['settings']['inactive_color'] = \FluentForm\App\Services\FormBuilder\RatingIcon::DEFAULT_INACTIVE_COLOR; | |
| 487 | + } | |
| 488 | + | |
| 489 | + if (!isset($item['settings']['active_color'])) { | |
| 490 | + $item['settings']['active_color'] = \FluentForm\App\Services\FormBuilder\RatingIcon::DEFAULT_ACTIVE_COLOR; | |
| 491 | + } | |
| 492 | + | |
| 493 | + return $item; | |
| 494 | + }); | |
| 495 | + | |
| 369 | 496 | add_filter('fluentform/editor_init_element_container', function ($item) { |
| 370 | 497 | if (!isset($item['settings']['conditional_logics'])) { |
| 371 | 498 | $item['settings']['conditional_logics'] = []; |
| 372 | 499 | } |
| @@ -415,8 +542,17 @@ | ||
| 415 | 542 | |
| 416 | 543 | return $item; |
| 417 | 544 | }); |
| 418 | 545 | |
| 546 | + foreach (['input_text', 'input_email', 'textarea', 'input_number', 'select', 'input_url', 'input_password', 'input_date', 'input_name', 'address', 'phone'] as $autocompleteElement) { | |
| 547 | + add_filter('fluentform/editor_init_element_' . $autocompleteElement, function ($item) { | |
| 548 | + if (!isset($item['attributes']['autocomplete'])) { | |
| 549 | + $item['attributes']['autocomplete'] = ''; | |
| 550 | + } | |
| 551 | + return $item; | |
| 552 | + }); | |
| 553 | + } | |
| 554 | + | |
| 419 | 555 | add_filter('fluentform/editor_init_element_input_mask', function ($item) { |
| 420 | 556 | if (!isset($item['settings']['mobile_keyboard_type'])) { |
| 421 | 557 | $item['settings']['mobile_keyboard_type'] = ''; |
| 422 | 558 | } |
| @@ -438,9 +574,8 @@ | ||
| 438 | 574 | } |
| 439 | 575 | return $item; |
| 440 | 576 | }); |
| 441 | 577 | |
| 442 | - | |
| 443 | 578 | add_filter('fluentform/editor_init_element_input_text', function ($item) { |
| 444 | 579 | if (isset($item['attributes']['data-mask'])) { |
| 445 | 580 | if (!isset($item['settings']['data-mask-reverse'])) { |
| 446 | 581 | $item['settings']['data-mask-reverse'] = 'no'; |
| @@ -467,9 +602,9 @@ | ||
| 467 | 602 | }); |
| 468 | 603 | |
| 469 | 604 | if ($inputs = \FluentForm\App\Modules\Form\FormFieldsParser::getInputs($form, ['element'])) { |
| 470 | 605 | foreach ($inputs as $input) { |
| 471 | - add_filter('fluentform/editor_init_element_'. $input['element'], function ($field) { | |
| 606 | + add_filter('fluentform/editor_init_element_' . $input['element'], function ($field) { | |
| 472 | 607 | Helper::resolveValidationRulesGlobalOption($field); |
| 473 | 608 | return $field; |
| 474 | 609 | }); |
| 475 | 610 | } |
| @@ -545,19 +680,19 @@ | ||
| 545 | 680 | }); |
| 546 | 681 | |
| 547 | 682 | add_filter('fluentform/editor_init_element_gdpr_agreement', function ($item, $form) { |
| 548 | 683 | $isConversationalForm = Helper::isConversionForm($form->id); |
| 549 | - | |
| 684 | + | |
| 550 | 685 | if ($isConversationalForm) { |
| 551 | 686 | $item['settings']['tc_agree_text'] = __('I accept', 'fluentform'); |
| 552 | 687 | } |
| 553 | - | |
| 688 | + | |
| 554 | 689 | return $item; |
| 555 | 690 | }, 10, 2); |
| 556 | 691 | |
| 557 | 692 | add_filter('fluentform/editor_init_element_terms_and_condition', function ($item, $form) { |
| 558 | 693 | $isConversationalForm = Helper::isConversionForm($form->id); |
| 559 | - | |
| 694 | + | |
| 560 | 695 | if ($isConversationalForm) { |
| 561 | 696 | $item['settings']['hide_disagree'] = false; |
| 562 | 697 | } |
| 563 | 698 | |
| @@ -606,11 +741,9 @@ | ||
| 606 | 741 | } |
| 607 | 742 | |
| 608 | 743 | // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Nonce verified by WordPress save_post action |
| 609 | 744 | $post_content = isset($_REQUEST['post_content']) ? wp_kses_post(wp_unslash($_REQUEST['post_content'])) : false; |
| 610 | - if ($post_content && is_string($post_content)) { | |
| 611 | - // Already sanitized above | |
| 612 | - } else { | |
| 745 | + if (!$post_content || !is_string($post_content)) { | |
| 613 | 746 | $post = get_post($post_id); |
| 614 | 747 | $post_content = $post->post_content; |
| 615 | 748 | } |
| 616 | 749 | |
| @@ -696,9 +829,9 @@ | ||
| 696 | 829 | ); |
| 697 | 830 | $globalVars = [ |
| 698 | 831 | 'ajaxurl' => Helper::getAjaxUrl(), |
| 699 | 832 | 'global_search_active' => apply_filters('fluentform/global_search_active', 'yes'), |
| 700 | - 'rest' => Helper::getRestInfo() | |
| 833 | + 'rest' => Helper::getRestInfo(), | |
| 701 | 834 | ]; |
| 702 | 835 | if (Acl::hasAnyFormPermission()) { |
| 703 | 836 | $globalVars['fluent_forms_admin_nonce'] = wp_create_nonce('fluent_forms_admin_nonce'); |
| 704 | 837 | } |
| @@ -704,9 +837,9 @@ | ||
| 704 | 837 | } |
| 705 | 838 | wp_localize_script('fluent_forms_global', 'fluent_forms_global_var', $globalVars); |
| 706 | 839 | wp_enqueue_style('fluent-form-styles'); |
| 707 | 840 | $form = wpFluent()->table('fluentform_forms')->find(intval($app->request->get('preview_id'))); |
| 708 | - $postId = get_the_ID() ?: 0; | |
| 841 | + $postId = get_the_ID() ? get_the_ID() : 0; | |
| 709 | 842 | |
| 710 | 843 | $loadPublicStyle = apply_filters_deprecated( |
| 711 | 844 | 'fluentform_load_default_public', |
| 712 | 845 | [ |
| @@ -711,9 +844,9 @@ | ||
| 711 | 844 | 'fluentform_load_default_public', |
| 712 | 845 | [ |
| 713 | 846 | true, |
| 714 | 847 | $form, |
| 715 | - $postId | |
| 848 | + $postId, | |
| 716 | 849 | ], |
| 717 | 850 | FLUENTFORM_FRAMEWORK_UPGRADE, |
| 718 | 851 | 'fluentform/load_default_public', |
| 719 | 852 | 'Use fluentform/load_default_public instead of fluentform_load_default_public.' |
| @@ -733,9 +866,9 @@ | ||
| 733 | 866 | true |
| 734 | 867 | ); |
| 735 | 868 | |
| 736 | 869 | wp_localize_script('fluentform-preview_app', 'fluent_preview_var', [ |
| 737 | - 'i18n' => \FluentForm\App\Modules\Registerer\TranslationString::getPreviewI18n() | |
| 870 | + 'i18n' => \FluentForm\App\Modules\Registerer\TranslationString::getPreviewI18n(), | |
| 738 | 871 | ]); |
| 739 | 872 | } |
| 740 | 873 | }); |
| 741 | 874 | |
| @@ -771,9 +904,9 @@ | ||
| 771 | 904 | 'fluentform_api_success_log', |
| 772 | 905 | [ |
| 773 | 906 | $isDev, |
| 774 | 907 | $form, |
| 775 | - $feed | |
| 908 | + $feed, | |
| 776 | 909 | ], |
| 777 | 910 | FLUENTFORM_FRAMEWORK_UPGRADE, |
| 778 | 911 | 'fluentform/api_success_log', |
| 779 | 912 | 'Use fluentform/api_success_log instead of fluentform_api_success_log.' |
| @@ -811,9 +944,9 @@ | ||
| 811 | 944 | 'fluentform_api_failed_log', |
| 812 | 945 | [ |
| 813 | 946 | $isDev, |
| 814 | 947 | $form, |
| 815 | - $feed | |
| 948 | + $feed, | |
| 816 | 949 | ], |
| 817 | 950 | FLUENTFORM_FRAMEWORK_UPGRADE, |
| 818 | 951 | 'fluentform/api_failed_log', |
| 819 | 952 | 'Use fluentform/api_failed_log instead of fluentform_api_failed_log.' |
| @@ -908,11 +1041,23 @@ | ||
| 908 | 1041 | $tokenBasedSpamProtection = new \FluentForm\App\Modules\Form\TokenBasedSpamProtection($app); |
| 909 | 1042 | $tokenBasedSpamProtection->verify($insertData, $requestData, $form->id); |
| 910 | 1043 | }, 9, 3); |
| 911 | 1044 | |
| 1045 | +// The token-based spam check (FINDING-25) enforces on conversational forms too, but its ~1h TTL | |
| 1046 | +// token cannot be refreshed by the conversational JS app — it bakes hidden inputs statically at | |
| 1047 | +// render, so behind a full-page cache the token expires and rejects every legitimate submission. | |
| 1048 | +// Disable ONLY the token for conversational forms, resolved from server-side form meta (never the | |
| 1049 | +// client-supplied isFFConversational flag, which was the original bypass). The honeypot still applies. | |
| 1050 | +$app->addFilter('fluentform/token_based_spam_protection_status', function ($status, $formId) { | |
| 1051 | + if ($status && \FluentForm\App\Helpers\Helper::isConversionForm($formId)) { | |
| 1052 | + return false; | |
| 1053 | + } | |
| 1054 | + return $status; | |
| 1055 | +}, 10, 2); | |
| 1056 | + | |
| 912 | 1057 | // Maybe update current user allowed form ids, |
| 913 | 1058 | // if current user has specific form permission and capable to create form |
| 914 | -$app->addAction('fluentform/inserted_new_form', function ($formId){ | |
| 1059 | +$app->addAction('fluentform/inserted_new_form', function ($formId) { | |
| 915 | 1060 | \FluentForm\App\Services\Manager\FormManagerService::maybeAddUserAllowedFormIds($formId); |
| 916 | 1061 | }); |
| 917 | 1062 | |
| 918 | 1063 | add_action('fluentform/log_data', function ($data) use ($app) { |
| @@ -978,8 +1123,12 @@ | ||
| 978 | 1123 | if (!$note) { |
| 979 | 1124 | $note = $status; |
| 980 | 1125 | } |
| 981 | 1126 | |
| 1127 | + $note = is_scalar($note) | |
| 1128 | + ? sanitize_text_field(wp_unslash((string) $note)) | |
| 1129 | + : sanitize_text_field((string) wp_json_encode($note)); | |
| 1130 | + | |
| 982 | 1131 | if (strlen($note) > 255) { |
| 983 | 1132 | if (function_exists('mb_substr')) { |
| 984 | 1133 | $note = mb_substr($note, 0, 251) . '...'; |
| 985 | 1134 | } else { |
| @@ -1009,8 +1158,12 @@ | ||
| 1009 | 1158 | if (!$note) { |
| 1010 | 1159 | $note = $status; |
| 1011 | 1160 | } |
| 1012 | 1161 | |
| 1162 | + $note = is_scalar($note) | |
| 1163 | + ? sanitize_text_field(wp_unslash((string) $note)) | |
| 1164 | + : sanitize_text_field((string) wp_json_encode($note)); | |
| 1165 | + | |
| 1013 | 1166 | if (strlen($note) > 255) { |
| 1014 | 1167 | if (function_exists('mb_substr')) { |
| 1015 | 1168 | $note = mb_substr($note, 0, 251) . '...'; |
| 1016 | 1169 | } else { |
| @@ -1031,9 +1184,9 @@ | ||
| 1031 | 1184 | $isTruncate = apply_filters_deprecated( |
| 1032 | 1185 | 'fluentform_truncate_password_values', |
| 1033 | 1186 | [ |
| 1034 | 1187 | true, |
| 1035 | - $form->id | |
| 1188 | + $form->id, | |
| 1036 | 1189 | ], |
| 1037 | 1190 | FLUENTFORM_FRAMEWORK_UPGRADE, |
| 1038 | 1191 | 'fluentform/truncate_password_values', |
| 1039 | 1192 | 'Use fluentform/truncate_password_values instead of fluentform_truncate_password_values.' |
| @@ -1087,9 +1240,8 @@ | ||
| 1087 | 1240 | ['wp-edit-blocks'], |
| 1088 | 1241 | FLUENTFORM_VERSION |
| 1089 | 1242 | ); |
| 1090 | 1243 | |
| 1091 | - | |
| 1092 | 1244 | $forms = wpFluent()->table('fluentform_forms') |
| 1093 | 1245 | ->select(['id', 'title']) |
| 1094 | 1246 | ->orderBy('id', 'DESC') |
| 1095 | 1247 | ->get() |
| @@ -1106,9 +1258,9 @@ | ||
| 1106 | 1258 | 'value' => '', |
| 1107 | 1259 | ], |
| 1108 | 1260 | [ |
| 1109 | 1261 | 'label' => __('Inherit Theme Style', 'fluentform'), |
| 1110 | - 'value' => 'ffs_inherit_theme' | |
| 1262 | + 'value' => 'ffs_inherit_theme', | |
| 1111 | 1263 | ], |
| 1112 | 1264 | ]; |
| 1113 | 1265 | |
| 1114 | 1266 | $presets = apply_filters('fluentform/block_editor_style_presets', $presets); |
| @@ -1118,9 +1270,9 @@ | ||
| 1118 | 1270 | 'forms' => $forms, |
| 1119 | 1271 | 'style_presets' => $presets, |
| 1120 | 1272 | 'theme_style' => apply_filters('fluentform/load_theme_style', false) ? 'ffs_inherit_theme' : '', |
| 1121 | 1273 | 'conversational_demo_img' => fluentFormMix('img/conversational-form-demo.png'), |
| 1122 | - 'rest' => Helper::getRestInfo() | |
| 1274 | + 'rest' => Helper::getRestInfo(), | |
| 1123 | 1275 | ]); |
| 1124 | 1276 | |
| 1125 | 1277 | wp_enqueue_style( |
| 1126 | 1278 | 'fluentform-gutenberg-block', |
| @@ -1143,15 +1295,15 @@ | ||
| 1143 | 1295 | FLUENTFORM_VERSION |
| 1144 | 1296 | ); |
| 1145 | 1297 | |
| 1146 | 1298 | // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Checking post ID in admin context |
| 1147 | - $post_id = isset($_GET['post']) ? (int)$_GET['post'] : 0; | |
| 1299 | + $post_id = isset($_GET['post']) ? (int) $_GET['post'] : 0; | |
| 1148 | 1300 | $loadPublicStyle = apply_filters_deprecated( |
| 1149 | 1301 | 'fluentform_load_default_public', |
| 1150 | 1302 | [ |
| 1151 | 1303 | true, |
| 1152 | - (object)[], | |
| 1153 | - $post_id | |
| 1304 | + (object) [], | |
| 1305 | + $post_id, | |
| 1154 | 1306 | ], |
| 1155 | 1307 | FLUENTFORM_FRAMEWORK_UPGRADE, |
| 1156 | 1308 | 'fluentform/load_default_public', |
| 1157 | 1309 | 'Use fluentform/load_default_public instead of fluentform_load_default_public.' |
| @@ -1156,9 +1308,9 @@ | ||
| 1156 | 1308 | 'fluentform/load_default_public', |
| 1157 | 1309 | 'Use fluentform/load_default_public instead of fluentform_load_default_public.' |
| 1158 | 1310 | ); |
| 1159 | 1311 | |
| 1160 | - if (apply_filters('fluentform/load_default_public', $loadPublicStyle, (object)[], $post_id)) { | |
| 1312 | + if (apply_filters('fluentform/load_default_public', $loadPublicStyle, (object) [], $post_id)) { | |
| 1161 | 1313 | wp_enqueue_style( |
| 1162 | 1314 | 'fluentform-public-default', |
| 1163 | 1315 | $fluentFormPublicDefaultCss, |
| 1164 | 1316 | [], |
| @@ -1175,29 +1327,25 @@ | ||
| 1175 | 1327 | }); |
| 1176 | 1328 | } |
| 1177 | 1329 | |
| 1178 | 1330 | |
| 1179 | -add_action('fluentform/before_updating_form',function ($form, $postData){ | |
| 1331 | +add_action('fluentform/before_updating_form', function ($form, $postData) { | |
| 1180 | 1332 | (new FluentForm\App\Services\Form\HistoryService())->init($form, $postData); |
| 1181 | -},10,2); | |
| 1333 | +}, 10, 2); | |
| 1182 | 1334 | |
| 1183 | 1335 | |
| 1184 | 1336 | // WordPress 6.3+ uses iframes for block editor preview |
| 1185 | 1337 | // Official WordPress solution: Use enqueue_block_assets with proper context checking |
| 1186 | 1338 | // See: https://make.wordpress.org/core/2023/07/18/miscellaneous-editor-changes-in-wordpress-6-3/ |
| 1187 | -add_action('enqueue_block_assets', function() { | |
| 1188 | - // Check if we're in the block editor context (not frontend) | |
| 1189 | - // This works for both the editor UI and the iframe preview in WordPress 6.3+ | |
| 1190 | - if (!is_admin() && !wp_is_block_theme()) { | |
| 1339 | +add_action('enqueue_block_assets', function () { | |
| 1340 | + // enqueue_block_assets also fires on the front end, where wp_enqueue_scripts already loads these conditionally. | |
| 1341 | + if (!is_admin()) { | |
| 1191 | 1342 | return; |
| 1192 | 1343 | } |
| 1193 | 1344 | |
| 1194 | - // Additional check: Only load if we're actually in a block editor screen | |
| 1195 | - if (is_admin()) { | |
| 1196 | - $current_screen = function_exists('get_current_screen') ? get_current_screen() : null; | |
| 1197 | - if ($current_screen && !$current_screen->is_block_editor()) { | |
| 1198 | - return; | |
| 1199 | - } | |
| 1345 | + $current_screen = function_exists('get_current_screen') ? get_current_screen() : null; | |
| 1346 | + if ($current_screen && !$current_screen->is_block_editor()) { | |
| 1347 | + return; | |
| 1200 | 1348 | } |
| 1201 | 1349 | |
| 1202 | 1350 | // Enqueue Fluent Forms CSS for block editor iframe preview |
| 1203 | 1351 | // These styles are necessary for the live form preview in the block editor |
| @@ -1202,9 +1350,8 @@ | ||
| 1202 | 1350 | // Enqueue Fluent Forms CSS for block editor iframe preview |
| 1203 | 1351 | // These styles are necessary for the live form preview in the block editor |
| 1204 | 1352 | wp_enqueue_style('fluent-forms-public', fluentFormMix('css/fluent-forms-public.css'), [], FLUENTFORM_VERSION); |
| 1205 | 1353 | wp_enqueue_style('fluentform-public-default', fluentFormMix('css/fluentform-public-default.css'), [], FLUENTFORM_VERSION); |
| 1206 | - | |
| 1207 | 1354 | }); |
| 1208 | 1355 | |
| 1209 | 1356 | |
| 1210 | 1357 | |