PluginProbe
aBlocks – Gutenberg Blocks, User Dashboard Builder, Popup Builder, Form Builder & Animation Builder / 2.14.0
aBlocks – Gutenberg Blocks, User Dashboard Builder, Popup Builder, Form Builder & Animation Builder v2.14.0
2.14.0 2.13.0 2.13.1 2.12.0 2.11.1 2.11.0 2.10.0 2.9.0 2.7.4 2.7.5 2.7.6 2.7.7 2.8.0 2.8.1 2.9.1 trunk 1.0 1.0-beta1 1.0-beta2 1.0-beta3 1.0.1 1.0.2 1.0.3 1.1.0 1.1.1 All 81 releases
← All changes | includes/classes/assets-generator.php +92 -30 2.9.1 → 2.14.0 View file →
@@ -4,24 +4,25 @@
4 4 use ABlocks\Classes\FileUpload;
5 5 use ABlocks\Classes\RegisterScripts;
6 6
7 7 class AssetsGenerator {
8 - public static function write_frontend_css_in_uploads_folder( $post_id ) {
9 - $post = get_post( $post_id );
10 - $post_type = get_post_type( $post_id );
11 - $parse_blocks_content = '';
12 -
13 - if ( empty( $post->post_content ) || $post_type === 'wp_template_part' || $post_type === 'wp_template' ) {
14 - $parse_blocks_content = parse_blocks( $post->post_content );
15 - } else {
16 - $parse_blocks_content = parse_blocks( $post->post_content );
8 + public static function write_frontend_css_in_uploads_folder( $file_name, $parse_blocks_content ) {
9 + if ( empty( $file_name ) ) {
10 + return;
17 11 }
18 12
19 13 $style_depends = [];
20 14 $scripts_depends = [];
21 15 $aBlocks = [];
22 - self::recursive_block_parser( $parse_blocks_content, $aBlocks, $style_depends, $scripts_depends );
16 + $seen_refs = [];
17 + $global_classes = [];
23 18
19 + self::recursive_block_parser( $parse_blocks_content, $aBlocks, $style_depends, $scripts_depends, $seen_refs, $global_classes );
20 +
21 + // Dedupe once, after the whole block tree has been walked.
22 + $style_depends = array_unique( $style_depends );
23 + $scripts_depends = array_unique( $scripts_depends );
24 +
24 25 $register_styles = RegisterScripts::get_register_styles();
25 26 $register_scripts = RegisterScripts::get_register_scripts();
26 27 $library_css = '';
27 28 $static_css = '';
@@ -44,10 +45,9 @@
44 45
45 46 // css
46 47 foreach ( $style_depends as $style_depend ) {
47 48 if ( isset( $register_styles[ $style_depend ]['path'] ) ) {
48 - // phpcs:ignore WordPress.WP.AlternativeFunctions.file_get_contents_file_get_contents
49 - $library_css .= file_get_contents( $register_styles[ $style_depend ]['path'] ) . "\n";
49 + $library_css .= self::read_library_file( $register_styles[ $style_depend ]['path'] ) . "\n";
50 50 }
51 51 }
52 52
53 53 // js
@@ -52,35 +52,64 @@
52 52
53 53 // js
54 54 foreach ( $scripts_depends as $script_depend ) {
55 55 if ( isset( $register_scripts[ $script_depend ]['path'] ) ) {
56 - // phpcs:ignore WordPress.WP.AlternativeFunctions.file_get_contents_file_get_contents
57 - $library_js .= file_get_contents( $register_scripts[ $script_depend ]['path'] ) . "\n";
56 + $library_js .= self::read_library_file( $register_scripts[ $script_depend ]['path'] ) . "\n";
58 57 }
59 58 }
60 59
60 + // Merge per-instance rules that share an identical body into a single
61 + // grouped selector (see CssDedupe). Always applied during generation —
62 + // it produces byte-for-byte equivalent styling, just smaller. Filterable
63 + // as a code-level escape hatch (no UI setting).
64 + if ( (bool) apply_filters( 'ablocks/perf/dedupe_css', true ) ) {
65 + $dynamic_css = CssDedupe::process( $dynamic_css );
66 + }
67 +
68 + // Global classes, narrowed to the ones this page uses. They sit between
69 + // the blocks' static CSS and their per-instance rules so a block's own
70 + // styles still win over a class it carries.
71 + $global_css = GlobalClasses::compiled_css_for(
72 + array_values( array_unique( $global_classes ) )
73 + );
74 +
61 75 $FileUpload = new FileUpload();
62 76 $destination_folder = $FileUpload->get_upload_dir();
63 77 self::copy_build_image_folder_to_uploads( $destination_folder );
64 - $FileUpload->create_file( $post_id . '.min.css', $library_css . $static_css . $dynamic_css );
65 - $FileUpload->create_file( $post_id . '.min.js', $library_js . $static_js );
78 + $FileUpload->create_file( $file_name . '.min.css', $library_css . $static_css . $global_css . $dynamic_css );
79 + $FileUpload->create_file( $file_name . '.min.js', $library_js . $static_js );
66 80
67 81 return $aBlocks;
68 82 }
69 83
70 - public static function recursive_block_parser( $parse_content, &$aBlocks, &$style_depends, &$scripts_depends ) {
84 + public static function recursive_block_parser( $parse_content, &$aBlocks, &$style_depends, &$scripts_depends, &$seen_refs = [], &$global_classes = [] ) {
71 85 if ( count( $parse_content ) > 0 ) {
72 86 foreach ( $parse_content as $item ) {
73 87 if ( ! empty( $item['blockName'] ) ) {
74 88 // Handle reusable blocks or patterns using "ref"
75 89 if ( $item['blockName'] === 'core/block' && ! empty( $item['attrs']['ref'] ) ) {
76 - $ref_post_id = $item['attrs']['ref'];
90 + $ref_post_id = (int) $item['attrs']['ref'];
91 + // Guard against circular / repeated reusable-block references.
92 + if ( in_array( $ref_post_id, $seen_refs, true ) ) {
93 + continue;
94 + }
95 + $seen_refs[] = $ref_post_id;
77 96 $ref_post = get_post( $ref_post_id ); // Get the reusable block or pattern
78 97 if ( $ref_post ) {
79 98 $ref_content = parse_blocks( $ref_post->post_content ); // Parse the reusable block's content
80 - self::recursive_block_parser( $ref_content, $aBlocks, $style_depends, $scripts_depends ); // Recursively parse the referenced block/pattern
99 + self::recursive_block_parser( $ref_content, $aBlocks, $style_depends, $scripts_depends, $seen_refs, $global_classes ); // Recursively parse the referenced block/pattern
81 100 }
82 101 } elseif ( strpos( $item['blockName'], 'ablocks' ) !== false ) {
102 + // Which global classes this page actually needs. Collected
103 + // from the walk rather than from a stored per-post index:
104 + // the walk is happening anyway, and an index would be one
105 + // more thing to keep in sync with the content.
106 + if ( ! empty( $item['attrs']['globalClasses'] ) && is_array( $item['attrs']['globalClasses'] ) ) {
107 + foreach ( $item['attrs']['globalClasses'] as $global_class_id ) {
108 + $global_classes[] = (string) $global_class_id;
109 + }
110 + }
111 +
83 112 $block_name_class = str_replace( ' ', '', ucwords( str_replace( '-', ' ', explode( '/', $item['blockName'] )[1] ) ) );
84 113
85 114 $dynamic_class = '\\ABlocks\\Blocks\\' . $block_name_class . '\\Block';
86 115 if ( ! class_exists( $dynamic_class ) ) {
@@ -99,20 +128,40 @@
99 128 'static_style' => $instance->get_static_css(),
100 129 'static_js' => $instance->get_static_js(),
101 130 ];
102 131 }
132 + // 'ablocks-animate-style',
133 + // if animation is used then added ablocks-animate-style dependency
134 + if ( isset( $attributes['_animation']['animationType'] ) && ! empty( $attributes['_animation']['animationType'] ) && $attributes['_animation']['animationType'] !== 'none' ) {
135 + $style_depends[] = 'ablocks-animate-style';
136 + }
137 + // Capture library scripts. Just accumulate here; the caller
138 + // dedups once after the full tree is walked (avoids O(n^2)
139 + // array_unique on every block).
140 + $style_depends = array_merge( $style_depends, $instance->get_style_depends() );
141 + $scripts_depends = array_merge( $scripts_depends, $instance->get_script_depends() );
103 142
104 - // Capture library scripts
105 - $style_depends = array_unique( array_merge( $style_depends, $instance->get_style_depends() ) );
106 - $scripts_depends = array_unique( array_merge( $scripts_depends, $instance->get_script_depends() ) );
107 -
108 - // Capture dynamic CSS
143 + // Capture dynamic CSS.
144 + //
145 + // A block can be reached twice in one walk: on an FSE theme
146 + // `pre_render_block` collects EVERY block — parents and their
147 + // children alike — and this parser also recurses into
148 + // `innerBlocks`, so a nested block is seen once as a child and
149 + // once as a collected top-level entry. Compiling it a second
150 + // time is not idempotent for blocks whose CSS is emitted
151 + // through a per-request dedupe (the atomic blocks' hashed
152 + // `ablocks-s-*` rules): the repeat build returns an empty
153 + // string because the rule was already emitted, and writing
154 + // that over the first result stripped every nested atomic
155 + // block's styles from the page. Keep the first result.
109 156 if ( isset( $item['attrs']['ref'] ) || isset( $item['attrs']['block_id'] ) ) {
110 157 $block_id_or_ref = ! empty( $item['attrs']['block_id'] ) ? $item['attrs']['block_id'] : 'core_pattern_ref_' . $item['attrs']['ref'];
111 - $aBlocks[ $block_id_or_ref ] = [
112 - 'block_name' => $item['blockName'],
113 - 'dynamic_style' => $instance->build_css( $attributes ),
114 - ];
158 + if ( ! isset( $aBlocks[ $block_id_or_ref ]['dynamic_style'] ) ) {
159 + $aBlocks[ $block_id_or_ref ] = [
160 + 'block_name' => $item['blockName'],
161 + 'dynamic_style' => $instance->build_css( $attributes ),
162 + ];
163 + }
115 164 }
116 165 }//end if
117 166 }//end if
118 167
@@ -117,9 +166,9 @@
117 166 }//end if
118 167
119 168 // Check for inner blocks and recursively process them
120 169 if ( is_array( $item['innerBlocks'] ) && count( $item['innerBlocks'] ) ) {
121 - self::recursive_block_parser( $item['innerBlocks'], $aBlocks, $style_depends, $scripts_depends );
170 + self::recursive_block_parser( $item['innerBlocks'], $aBlocks, $style_depends, $scripts_depends, $seen_refs, $global_classes );
122 171 }
123 172 }//end if
124 173 }//end foreach
125 174 }//end if
@@ -124,8 +173,22 @@
124 173 }//end foreach
125 174 }//end if
126 175 }
127 176
177 + /**
178 + * Read a static library asset file, cached per request so the same library
179 + * file isn't re-read from disk when multiple pages are generated in one
180 + * request (e.g. regenerate-all).
181 + */
182 + private static $library_file_cache = [];
183 + private static function read_library_file( $path ) {
184 + if ( ! isset( self::$library_file_cache[ $path ] ) ) {
185 + // phpcs:ignore WordPress.WP.AlternativeFunctions.file_get_contents_file_get_contents
186 + self::$library_file_cache[ $path ] = (string) file_get_contents( $path );
187 + }
188 + return self::$library_file_cache[ $path ];
189 + }
190 +
128 191 public static function minify_css( $css_string ) {
129 192 // Remove comments (/* ... */) using regex
130 193 $css_string = preg_replace( '/\/\*[\s\S]*?\*\//', '', $css_string );
131 194
@@ -212,6 +275,5 @@
212 275
213 276 // Close the directory handle
214 277 closedir( $dir );
215 278 }
216 -
217 279 }