PluginProbe
Bit Form – Contact Form, Payment Forms, Multi Step Forms, Calculator & Custom Form Builder / V3.3.2
Bit Form – Contact Form, Payment Forms, Multi Step Forms, Calculator & Custom Form Builder vV3.3.2
V3.3.2 3.3.1 V-3.3.0 3.2.2 3.2.1 3.2.0 3.1.4 3.1.3 3.1.2 3.1.1 3.1.0 V3.0.3 V3.0.2 -3.0.1 V_3.0.0 1.1.1 1.1.8 1.2 1.3 1.4 1.4.18 1.5.2 1.9 2.0 2.10.0 All 139 releases
← All changes | includes/Core/Util/CacheCompat.php +263 -30 3.3.1 → V3.3.2 View file →
@@ -8,8 +8,13 @@
8 8 * delay JavaScript can reorder or withhold either one. Registers Bit Form's
9 9 * script patterns with each optimizer's exclusion filter, and stamps generic
10 10 * no-optimize attributes as a fallback for those that honor them.
11 11 *
12 + * Stylesheets need the same protection for a different reason: a form's styles
13 + * are atomic single-property classes generated per form, so a combiner that
14 + * reorders them against theme CSS, or an unused-CSS pass that drops the classes
15 + * it cannot see in the markup, leaves the form unstyled.
16 + *
12 17 * @since 3.2.2
13 18 */
14 19
15 20 namespace BitCode\BitForm\Core\Util;
@@ -38,8 +43,28 @@
38 43 'bitform-show-picker-bridge',
39 44 'bitforms_recaptcha',
40 45 ];
41 46
47 + /**
48 + * Frontend style handle prefixes. Covers the generated per-form sheets
49 + * (bitform-style-15, bitform-style-15-formid, bitform-style-custom-15), the
50 + * Pro data views (bitform-style-view-3), the page builder widgets and the
51 + * standalone, conversational and preview views.
52 + */
53 + private const STYLE_HANDLE_PREFIXES = [
54 + 'bf-inline-style',
55 + 'bitform-bricks-',
56 + 'bitform-conversational-',
57 + 'bitform-elementor-style',
58 + 'bitform-entry-edit-',
59 + 'bitform-preview-',
60 + 'bitform-standalone-',
61 + 'bitform-style',
62 + ];
63 +
64 + /** Attributes the optimizers that read markup instead of filters honor. */
65 + private const NO_OPTIMIZE_ATTRIBUTES = 'data-no-optimize="1" data-no-defer="1" data-no-minify="1" data-cfasync="false" data-jetpack-boost="ignore" nowprocket nitro-exclude ';
66 +
42 67 public static function register()
43 68 {
44 69 // WP Rocket
45 70 add_filter('rocket_delay_js_exclusions', [self::class, 'appendExclusionsArray']);
@@ -74,22 +99,58 @@
74 99
75 100 // W3 Total Cache (matches the tag and file path; this filter has no handle)
76 101 add_filter('w3tc_minify_js_do_tag_minification', [self::class, 'denyTagMinification'], 10, 3);
77 102
78 - // Hummingbird, at 20 so it runs after Hummingbird's own settings filters at 10
79 - add_filter('wphb_minify_resource', [self::class, 'denyForBitformHandle'], 20, 2);
80 - add_filter('wphb_combine_resource', [self::class, 'denyForBitformHandle'], 20, 2);
81 - add_filter('wphb_defer_resource', [self::class, 'denyForBitformHandle'], 20, 2);
82 - add_filter('wphb_inline_resource', [self::class, 'denyForBitformHandle'], 20, 2);
103 + // Hummingbird, at 20 so it runs after Hummingbird's own settings filters at 10.
104 + // These four carry styles as well as scripts, so they test both handle lists.
105 + add_filter('wphb_minify_resource', [self::class, 'denyForBitformAsset'], 20, 2);
106 + add_filter('wphb_combine_resource', [self::class, 'denyForBitformAsset'], 20, 2);
107 + add_filter('wphb_defer_resource', [self::class, 'denyForBitformAsset'], 20, 2);
108 + add_filter('wphb_inline_resource', [self::class, 'denyForBitformAsset'], 20, 2);
83 109
84 - // Jetpack Boost, Page Optimize and WordPress.com script concatenation
110 + // Jetpack Boost, Page Optimize and WordPress.com asset concatenation
85 111 add_filter('js_do_concat', [self::class, 'denyForBitformHandle'], 20, 2);
112 + add_filter('css_do_concat', [self::class, 'denyForBitformStyleHandle'], 20, 2);
86 113
114 + self::registerStyleFilters();
115 +
87 116 // Generic no-optimize attributes on our own script tags
88 117 add_filter('script_loader_tag', [self::class, 'addNoOptimizeAttributes'], 10, 2);
89 118 add_filter('wp_inline_script_attributes', [self::class, 'addInlineNoOptimizeAttributes'], 10, 2);
119 + add_filter('style_loader_tag', [self::class, 'addStyleNoOptimizeAttributes'], 10, 2);
90 120 }
91 121
122 + /** Stylesheet counterparts of the script exclusion filters above. */
123 + private static function registerStyleFilters()
124 + {
125 + // WP Rocket, including the Remove Unused CSS safelist
126 + add_filter('rocket_exclude_css', [self::class, 'appendStyleExclusionsArray']);
127 + add_filter('rocket_exclude_defer_css', [self::class, 'appendStyleExclusionsArray']);
128 + add_filter('rocket_rucss_safelist', [self::class, 'appendStyleExclusionsArray']);
129 +
130 + // LiteSpeed Cache, including the Unique CSS pass
131 + add_filter('litespeed_optimize_css_excludes', [self::class, 'appendStyleExclusionsArray']);
132 + add_filter('litespeed_optm_css_defer_exc', [self::class, 'appendStyleExclusionsArray']);
133 + add_filter('litespeed_optm_ucss_exc', [self::class, 'appendStyleExclusionsArray']);
134 +
135 + // Perfmatters Used CSS
136 + add_filter('perfmatters_used_css_excluded_stylesheets', [self::class, 'appendStyleExclusionsArray']);
137 +
138 + // Autoptimize (comma-separated string)
139 + add_filter('autoptimize_filter_css_exclude', [self::class, 'appendStyleExclusionsString']);
140 +
141 + // SiteGround Optimizer (style handles)
142 + add_filter('sgo_css_minify_exclude', [self::class, 'appendStyleHandles']);
143 + add_filter('sgo_css_combine_exclude', [self::class, 'appendStyleHandles']);
144 +
145 + // FlyingPress
146 + add_filter('flying_press_exclude_from_minify:css', [self::class, 'appendStyleExclusionsArray']);
147 + add_filter('flying_press_exclude_from_used_css', [self::class, 'appendStyleExclusionsArray']);
148 +
149 + // W3 Total Cache (matches the tag and file path; this filter has no handle)
150 + add_filter('w3tc_minify_css_do_tag_minification', [self::class, 'denyStyleTagMinification'], 10, 3);
151 + }
152 +
92 153 /** Register the cache purge that runs after a form changes. */
93 154 public static function registerPurgeHooks()
94 155 {
95 156 add_action('bitform_admin_form_changed', [self::class, 'schedulePurge']);
@@ -445,11 +506,26 @@
445 506 return is_array($filtered) ? $filtered : $patterns;
446 507 }
447 508
448 509 /**
449 - * Append patterns to an array-based optimizer filter. Typed loosely because
450 - * optimizers pass mixed shapes through these filters.
510 + * Substrings optimizers match against a stylesheet's URL or tag.
451 511 *
512 + * @return array
513 + */
514 + public static function styleExclusionPatterns()
515 + {
516 + $patterns = [
517 + 'bitform', // handles + generated file names (bitform-15-formid.css)
518 + 'bitforms/form-styles', // uploads path of the generated stylesheets
519 + ];
520 + $filtered = apply_filters('bitform_cache_style_exclusion_patterns', $patterns);
521 + return is_array($filtered) ? $filtered : $patterns;
522 + }
523 +
524 + /**
525 + * Append script patterns to an array-based optimizer filter. Typed loosely
526 + * because optimizers pass mixed shapes through these filters.
527 + *
452 528 * @param mixed $exclusions
453 529 *
454 530 * @return mixed
455 531 */
@@ -454,28 +530,74 @@
454 530 * @return mixed
455 531 */
456 532 public static function appendExclusionsArray($exclusions)
457 533 {
534 + return self::mergePatternsIntoArray($exclusions, self::exclusionPatterns());
535 + }
536 +
537 + /**
538 + * Append style patterns to an array-based optimizer filter.
539 + *
540 + * @param mixed $exclusions
541 + *
542 + * @return mixed
543 + */
544 + public static function appendStyleExclusionsArray($exclusions)
545 + {
546 + return self::mergePatternsIntoArray($exclusions, self::styleExclusionPatterns());
547 + }
548 +
549 + /**
550 + * Append script patterns to a comma-separated string filter (Autoptimize).
551 + *
552 + * @param mixed $exclusions
553 + *
554 + * @return mixed
555 + */
556 + public static function appendExclusionsString($exclusions)
557 + {
558 + return self::mergePatternsIntoString($exclusions, self::exclusionPatterns());
559 + }
560 +
561 + /**
562 + * Append style patterns to a comma-separated string filter (Autoptimize).
563 + *
564 + * @param mixed $exclusions
565 + *
566 + * @return mixed
567 + */
568 + public static function appendStyleExclusionsString($exclusions)
569 + {
570 + return self::mergePatternsIntoString($exclusions, self::styleExclusionPatterns());
571 + }
572 +
573 + /**
574 + * @param mixed $exclusions
575 + * @param array $patterns
576 + *
577 + * @return mixed
578 + */
579 + private static function mergePatternsIntoArray($exclusions, $patterns)
580 + {
458 581 if (!is_array($exclusions)) {
459 582 return $exclusions;
460 583 }
461 - return array_values(array_unique(array_merge($exclusions, self::exclusionPatterns())));
584 + return array_values(array_unique(array_merge($exclusions, $patterns)));
462 585 }
463 586
464 587 /**
465 - * Append exclusion patterns to a comma-separated string filter (Autoptimize).
466 - *
467 588 * @param mixed $exclusions
589 + * @param array $patterns
468 590 *
469 591 * @return mixed
470 592 */
471 - public static function appendExclusionsString($exclusions)
593 + private static function mergePatternsIntoString($exclusions, $patterns)
472 594 {
473 595 if (!is_string($exclusions)) {
474 596 return $exclusions;
475 597 }
476 598 $parts = array_filter(array_map('trim', explode(',', $exclusions)));
477 - $parts = array_unique(array_merge($parts, self::exclusionPatterns()));
599 + $parts = array_unique(array_merge($parts, $patterns));
478 600 return implode(',', $parts);
479 601 }
480 602
481 603 /**
@@ -490,16 +612,39 @@
490 612 * @return mixed
491 613 */
492 614 public static function appendHandles($handles)
493 615 {
616 + return self::mergeRegisteredHandles($handles, self::HANDLE_PREFIXES, wp_scripts());
617 + }
618 +
619 + /**
620 + * Append style handles to a handle-based filter (SiteGround).
621 + *
622 + * @param mixed $handles
623 + *
624 + * @return mixed
625 + */
626 + public static function appendStyleHandles($handles)
627 + {
628 + return self::mergeRegisteredHandles($handles, self::STYLE_HANDLE_PREFIXES, wp_styles());
629 + }
630 +
631 + /**
632 + * @param mixed $handles
633 + * @param array $prefixes
634 + * @param mixed $registry a WP_Scripts or WP_Styles instance
635 + *
636 + * @return mixed
637 + */
638 + private static function mergeRegisteredHandles($handles, $prefixes, $registry)
639 + {
494 640 if (!is_array($handles)) {
495 641 return $handles;
496 642 }
497 - $bitformHandles = self::HANDLE_PREFIXES;
498 - $wpScripts = wp_scripts();
499 - if (!empty($wpScripts->registered)) {
500 - foreach (array_keys($wpScripts->registered) as $registeredHandle) {
501 - if (self::isBitformHandle($registeredHandle)) {
643 + $bitformHandles = $prefixes;
644 + if (is_object($registry) && !empty($registry->registered)) {
645 + foreach (array_keys($registry->registered) as $registeredHandle) {
646 + if (self::hasPrefix($registeredHandle, $prefixes)) {
502 647 $bitformHandles[] = $registeredHandle;
503 648 }
504 649 }
505 650 }
@@ -514,12 +659,35 @@
514 659 * @return bool
515 660 */
516 661 private static function isBitformHandle($handle)
517 662 {
663 + return self::hasPrefix($handle, self::HANDLE_PREFIXES);
664 + }
665 +
666 + /**
667 + * Whether a style handle belongs to a Bit Form stylesheet.
668 + *
669 + * @param mixed $handle
670 + *
671 + * @return bool
672 + */
673 + private static function isBitformStyleHandle($handle)
674 + {
675 + return self::hasPrefix($handle, self::STYLE_HANDLE_PREFIXES);
676 + }
677 +
678 + /**
679 + * @param mixed $handle
680 + * @param array $prefixes
681 + *
682 + * @return bool
683 + */
684 + private static function hasPrefix($handle, $prefixes)
685 + {
518 686 if (!is_string($handle) || '' === $handle) {
519 687 return false;
520 688 }
521 - foreach (self::HANDLE_PREFIXES as $prefix) {
689 + foreach ($prefixes as $prefix) {
522 690 if (0 === strpos($handle, $prefix)) {
523 691 return true;
524 692 }
525 693 }
@@ -526,20 +694,21 @@
526 694 return false;
527 695 }
528 696
529 697 /**
530 - * Whether a tag or file path carries one of the exclusion patterns.
698 + * Whether a tag or file path carries one of the given exclusion patterns.
531 699 *
532 700 * @param mixed $value
701 + * @param array $patterns
533 702 *
534 703 * @return bool
535 704 */
536 - private static function matchesExclusionPattern($value)
705 + private static function matchesAnyPattern($value, $patterns)
537 706 {
538 707 if (!is_string($value) || '' === $value) {
539 708 return false;
540 709 }
541 - foreach (self::exclusionPatterns() as $pattern) {
710 + foreach ($patterns as $pattern) {
542 711 if (is_string($pattern) && '' !== $pattern && false !== strpos($value, $pattern)) {
543 712 return true;
544 713 }
545 714 }
@@ -546,10 +715,10 @@
546 715 return false;
547 716 }
548 717
549 718 /**
550 - * Return false for Bit Form handles on boolean, handle-keyed optimizer
551 - * filters (Hummingbird's minify/combine/defer/inline, js_do_concat).
719 + * Return false for Bit Form script handles on boolean, handle-keyed optimizer
720 + * filters (js_do_concat).
552 721 *
553 722 * @param mixed $value
554 723 * @param mixed $handle
555 724 *
@@ -560,8 +729,35 @@
560 729 return self::isBitformHandle($handle) ? false : $value;
561 730 }
562 731
563 732 /**
733 + * Same, for style handles (css_do_concat).
734 + *
735 + * @param mixed $value
736 + * @param mixed $handle
737 + *
738 + * @return mixed
739 + */
740 + public static function denyForBitformStyleHandle($value, $handle = '')
741 + {
742 + return self::isBitformStyleHandle($handle) ? false : $value;
743 + }
744 +
745 + /**
746 + * Same, for filters that carry scripts and styles through one hook
747 + * (Hummingbird's minify/combine/defer/inline).
748 + *
749 + * @param mixed $value
750 + * @param mixed $handle
751 + *
752 + * @return mixed
753 + */
754 + public static function denyForBitformAsset($value, $handle = '')
755 + {
756 + return self::isBitformHandle($handle) || self::isBitformStyleHandle($handle) ? false : $value;
757 + }
758 +
759 + /**
564 760 * Deny W3 Total Cache tag minification for Bit Form scripts.
565 761 *
566 762 * @param mixed $doMinification
567 763 * @param mixed $scriptTag
@@ -570,9 +766,10 @@
570 766 * @return mixed
571 767 */
572 768 public static function denyTagMinification($doMinification, $scriptTag = '', $file = '')
573 769 {
574 - if (self::matchesExclusionPattern($scriptTag) || self::matchesExclusionPattern($file)) {
770 + if (self::matchesAnyPattern($scriptTag, self::exclusionPatterns())
771 + || self::matchesAnyPattern($file, self::exclusionPatterns())) {
575 772 return false;
576 773 }
577 774 return $doMinification;
578 775 }
@@ -577,8 +774,26 @@
577 774 return $doMinification;
578 775 }
579 776
580 777 /**
778 + * Deny W3 Total Cache tag minification for Bit Form stylesheets.
779 + *
780 + * @param mixed $doMinification
781 + * @param mixed $styleTag
782 + * @param mixed $file
783 + *
784 + * @return mixed
785 + */
786 + public static function denyStyleTagMinification($doMinification, $styleTag = '', $file = '')
787 + {
788 + if (self::matchesAnyPattern($styleTag, self::styleExclusionPatterns())
789 + || self::matchesAnyPattern($file, self::styleExclusionPatterns())) {
790 + return false;
791 + }
792 + return $doMinification;
793 + }
794 +
795 + /**
581 796 * Stamp exclusion attributes on Bit Form <script src> tags. Honored by
582 797 * Cloudflare Rocket Loader, WP Rocket, LiteSpeed, FlyingPress, Breeze,
583 798 * NitroPack (nitro-exclude) and Jetpack Boost (data-jetpack-boost).
584 799 *
@@ -594,13 +809,31 @@
594 809 }
595 810 if (false !== strpos($tag, 'data-no-optimize')) {
596 811 return $tag;
597 812 }
598 - return str_replace(
599 - '<script ',
600 - '<script data-no-optimize="1" data-no-defer="1" data-no-minify="1" data-cfasync="false" data-jetpack-boost="ignore" nowprocket nitro-exclude ',
601 - $tag
602 - );
813 + return str_replace('<script ', '<script ' . self::NO_OPTIMIZE_ATTRIBUTES, $tag);
814 + }
815 +
816 + /**
817 + * Stamp the same attributes on Bit Form stylesheet tags. Covers both the
818 + * <link> a registered sheet prints and the <style> an inline-only handle
819 + * prints, since optimizers read either one.
820 + *
821 + * @param mixed $tag
822 + * @param mixed $handle
823 + *
824 + * @return mixed
825 + */
826 + public static function addStyleNoOptimizeAttributes($tag, $handle)
827 + {
828 + if (!is_string($tag) || !self::isBitformStyleHandle($handle)) {
829 + return $tag;
830 + }
831 + if (false !== strpos($tag, 'data-no-optimize')) {
832 + return $tag;
833 + }
834 + $tag = str_replace('<link ', '<link ' . self::NO_OPTIMIZE_ATTRIBUTES, $tag);
835 + return str_replace('<style ', '<style ' . self::NO_OPTIMIZE_ATTRIBUTES, $tag);
603 836 }
604 837
605 838 /**
606 839 * Same attributes for wp_add_inline_script fragments, which never pass