PluginProbe
aBlocks – Gutenberg Blocks, User Dashboard Builder, Popup Builder, Form Builder & Animation Builder / 2.11.1
aBlocks – Gutenberg Blocks, User Dashboard Builder, Popup Builder, Form Builder & Animation Builder v2.11.1
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 1.1.2 All 80 releases
ablocks / includes / classes / assets-generator.php

assets-generator.php in aBlocks – Gutenberg Blocks, User Dashboard Builder, Popup Builder, Form Builder & Animation Builder 2.11.1, at includes/classes/assets-generator.php

247 lines 9.0 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 namespace ABlocks\Classes;
3
4 use ABlocks\Classes\FileUpload;
5 use ABlocks\Classes\RegisterScripts;
6
7 class AssetsGenerator {
8 public static function write_frontend_css_in_uploads_folder( $file_name, $parse_blocks_content ) {
9 if ( empty( $file_name ) ) {
10 return;
11 }
12
13 $style_depends = [];
14 $scripts_depends = [];
15 $aBlocks = [];
16
17 self::recursive_block_parser( $parse_blocks_content, $aBlocks, $style_depends, $scripts_depends );
18
19 // Dedupe once, after the whole block tree has been walked.
20 $style_depends = array_unique( $style_depends );
21 $scripts_depends = array_unique( $scripts_depends );
22
23 $register_styles = RegisterScripts::get_register_styles();
24 $register_scripts = RegisterScripts::get_register_scripts();
25 $library_css = '';
26 $static_css = '';
27 $dynamic_css = '';
28 $static_js = '';
29 $library_js = '';
30
31 foreach ( $aBlocks as $aBlock ) {
32 if ( isset( $aBlock['static_js'] ) ) {
33 $static_js .= $aBlock['static_js'] . "\n";
34 }
35 if ( isset( $aBlock['dynamic_style'] ) ) {
36 $dynamic_css .= $aBlock['dynamic_style'] . "\n";
37 }
38
39 if ( isset( $aBlock['static_style'] ) ) {
40 $static_css .= self::minify_css( $aBlock['static_style'] ) . "\n";
41 }
42 }
43
44 // css
45 foreach ( $style_depends as $style_depend ) {
46 if ( isset( $register_styles[ $style_depend ]['path'] ) ) {
47 $library_css .= self::read_library_file( $register_styles[ $style_depend ]['path'] ) . "\n";
48 }
49 }
50
51 // js
52 foreach ( $scripts_depends as $script_depend ) {
53 if ( isset( $register_scripts[ $script_depend ]['path'] ) ) {
54 $library_js .= self::read_library_file( $register_scripts[ $script_depend ]['path'] ) . "\n";
55 }
56 }
57
58 // Merge per-instance rules that share an identical body into a single
59 // grouped selector (see CssDedupe). Always applied during generation —
60 // it produces byte-for-byte equivalent styling, just smaller. Filterable
61 // as a code-level escape hatch (no UI setting).
62 if ( (bool) apply_filters( 'ablocks/perf/dedupe_css', true ) ) {
63 $dynamic_css = CssDedupe::process( $dynamic_css );
64 }
65
66 $FileUpload = new FileUpload();
67 $destination_folder = $FileUpload->get_upload_dir();
68 self::copy_build_image_folder_to_uploads( $destination_folder );
69 $FileUpload->create_file( $file_name . '.min.css', $library_css . $static_css . $dynamic_css );
70 $FileUpload->create_file( $file_name . '.min.js', $library_js . $static_js );
71
72 return $aBlocks;
73 }
74
75 public static function recursive_block_parser( $parse_content, &$aBlocks, &$style_depends, &$scripts_depends, &$seen_refs = [] ) {
76 if ( count( $parse_content ) > 0 ) {
77 foreach ( $parse_content as $item ) {
78 if ( ! empty( $item['blockName'] ) ) {
79 // Handle reusable blocks or patterns using "ref"
80 if ( $item['blockName'] === 'core/block' && ! empty( $item['attrs']['ref'] ) ) {
81 $ref_post_id = (int) $item['attrs']['ref'];
82 // Guard against circular / repeated reusable-block references.
83 if ( in_array( $ref_post_id, $seen_refs, true ) ) {
84 continue;
85 }
86 $seen_refs[] = $ref_post_id;
87 $ref_post = get_post( $ref_post_id ); // Get the reusable block or pattern
88 if ( $ref_post ) {
89 $ref_content = parse_blocks( $ref_post->post_content ); // Parse the reusable block's content
90 self::recursive_block_parser( $ref_content, $aBlocks, $style_depends, $scripts_depends, $seen_refs ); // Recursively parse the referenced block/pattern
91 }
92 } elseif ( strpos( $item['blockName'], 'ablocks' ) !== false ) {
93 $block_name_class = str_replace( ' ', '', ucwords( str_replace( '-', ' ', explode( '/', $item['blockName'] )[1] ) ) );
94
95 $dynamic_class = '\\ABlocks\\Blocks\\' . $block_name_class . '\\Block';
96 if ( ! class_exists( $dynamic_class ) ) {
97 $dynamic_class = '\\ABlocksPro\\Blocks\\' . $block_name_class . '\\Block';
98 }
99
100 if ( class_exists( $dynamic_class ) ) {
101 $instance = new $dynamic_class( true );
102 $attributes = wp_parse_args( $item['attrs'], array_map( function( $attr ) {
103 return isset( $attr['default'] ) ? $attr['default'] : '';
104 }, $instance->get_attributes() ));
105
106 // Capture static CSS/JS
107 if ( ! isset( $aBlocks[ $item['blockName'] ] ) ) {
108 $aBlocks[ $item['blockName'] ] = [
109 'static_style' => $instance->get_static_css(),
110 'static_js' => $instance->get_static_js(),
111 ];
112 }
113 // 'ablocks-animate-style',
114 // if animation is used then added ablocks-animate-style dependency
115 if ( isset( $attributes['_animation']['animationType'] ) && ! empty( $attributes['_animation']['animationType'] ) && $attributes['_animation']['animationType'] !== 'none' ) {
116 $style_depends[] = 'ablocks-animate-style';
117 }
118 // Capture library scripts. Just accumulate here; the caller
119 // dedups once after the full tree is walked (avoids O(n^2)
120 // array_unique on every block).
121 $style_depends = array_merge( $style_depends, $instance->get_style_depends() );
122 $scripts_depends = array_merge( $scripts_depends, $instance->get_script_depends() );
123
124 // Capture dynamic CSS
125 if ( isset( $item['attrs']['ref'] ) || isset( $item['attrs']['block_id'] ) ) {
126 $block_id_or_ref = ! empty( $item['attrs']['block_id'] ) ? $item['attrs']['block_id'] : 'core_pattern_ref_' . $item['attrs']['ref'];
127 $aBlocks[ $block_id_or_ref ] = [
128 'block_name' => $item['blockName'],
129 'dynamic_style' => $instance->build_css( $attributes ),
130 ];
131 }
132 }//end if
133 }//end if
134
135 // Check for inner blocks and recursively process them
136 if ( is_array( $item['innerBlocks'] ) && count( $item['innerBlocks'] ) ) {
137 self::recursive_block_parser( $item['innerBlocks'], $aBlocks, $style_depends, $scripts_depends, $seen_refs );
138 }
139 }//end if
140 }//end foreach
141 }//end if
142 }
143
144 /**
145 * Read a static library asset file, cached per request so the same library
146 * file isn't re-read from disk when multiple pages are generated in one
147 * request (e.g. regenerate-all).
148 */
149 private static $library_file_cache = [];
150 private static function read_library_file( $path ) {
151 if ( ! isset( self::$library_file_cache[ $path ] ) ) {
152 // phpcs:ignore WordPress.WP.AlternativeFunctions.file_get_contents_file_get_contents
153 self::$library_file_cache[ $path ] = (string) file_get_contents( $path );
154 }
155 return self::$library_file_cache[ $path ];
156 }
157
158 public static function minify_css( $css_string ) {
159 // Remove comments (/* ... */) using regex
160 $css_string = preg_replace( '/\/\*[\s\S]*?\*\//', '', $css_string );
161
162 // Remove double spaces, tabs, and newlines
163 $css_string = preg_replace( '/\s+/', ' ', $css_string );
164
165 // Remove spaces around colons, semicolons, curly braces, and commas
166 $css_string = preg_replace( '/\s?([:,;{}])\s?/', '$1', $css_string );
167
168 return $css_string;
169 }
170
171 public static function copy_build_image_folder_to_uploads( $destination_folder ) {
172 global $wp_filesystem;
173 if ( empty( $wp_filesystem ) ) {
174 require_once ABSPATH . '/wp-admin/includes/file.php';
175 WP_Filesystem();
176 }
177
178 $source_folders = [
179 ABLOCKS_ASSETS_PATH . 'build/images/', // First folder
180 ABLOCKS_ASSETS_PATH . 'library/leaflet/', // Add more folders as needed
181 // Add more source folders here
182 ];
183
184 if ( ! file_exists( $destination_folder ) ) {
185 wp_mkdir_p( $destination_folder );
186 }
187
188 // Loop through each source folder and copy its contents
189 foreach ( $source_folders as $source_folder ) {
190 if ( file_exists( $source_folder ) ) {
191 self::recursive_copy( $source_folder, $destination_folder );
192 }
193 }
194 }
195
196 public static function recursive_copy( $source, $destination ) {
197 global $wp_filesystem;
198 if ( empty( $wp_filesystem ) ) {
199 require_once ABSPATH . '/wp-admin/includes/file.php';
200 WP_Filesystem();
201 }
202
203 $valid_extensions = [ 'jpg', 'jpeg', 'png', 'gif', 'bmp', 'webp' ];
204
205 // Ensure WP_Filesystem is initialized
206 if ( ! is_object( $GLOBALS['wp_filesystem'] ) ) {
207 request_filesystem_credentials( '', '', true );
208 }
209
210 // Initialize the WP_Filesystem object
211 $wp_file_system = $GLOBALS['wp_filesystem'];
212
213 // Open the source directory
214 $dir = opendir( $source );
215
216 // Create the destination directory using WP_Filesystem
217 if ( ! $wp_file_system->is_dir( $destination ) ) {
218 $wp_file_system->mkdir( $destination );
219 }
220
221 // phpcs:ignore WordPress.CodeAnalysis.AssignmentInCondition.FoundInWhileCondition
222 while ( false !== ( $file = readdir( $dir ) ) ) {
223 if ( ( $file !== '.' ) && ( $file !== '..' ) ) {
224 $source_file_path = $source . '/' . $file;
225 $destination_file_path = $destination . '/' . $file;
226
227 // If it's a directory, recursively copy its contents
228 if ( is_dir( $source_file_path ) ) {
229 self::recursive_copy( $source_file_path, $destination_file_path );
230 } else {
231 // Get file extension
232 $file_extension = pathinfo( $file, PATHINFO_EXTENSION );
233
234 // Check if the file has a valid image extension
235 if ( in_array( strtolower( $file_extension ), $valid_extensions, true ) ) {
236 // Copy only image files
237 $wp_file_system->copy( $source_file_path, $destination_file_path );
238 }
239 }
240 }
241 }
242
243 // Close the directory handle
244 closedir( $dir );
245 }
246 }
247