PluginProbe
ShopBuilder – WooCommerce Builder For Elementor / 3.2.6
ShopBuilder – WooCommerce Builder For Elementor v3.2.6
3.4.2 3.4.1 3.4.0 2.0.1 2.0.2 2.0.3 2.1.0 2.1.1 2.1.10 2.1.11 2.1.12 2.1.13 2.1.14 2.1.15 2.1.2 2.1.3 2.1.4 2.1.5 2.1.6 2.1.7 2.1.8 2.1.9 2.2.0 2.2.1 2.2.2 All 63 releases
shopbuilder / app / Models / AssetBundler.php

AssetBundler.php in ShopBuilder – WooCommerce Builder For Elementor 3.2.6, at app/Models/AssetBundler.php

226 lines 5.3 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * AssetBundler class.
4 *
5 * Dynamically merges and minifies CSS/JS files into a single versioned file stored in uploads.
6 *
7 * @package RadiusTheme\SB
8 * @since 1.0.0
9 */
10
11 namespace RadiusTheme\SB\Models;
12
13 use MatthiasMullie\Minify\JS;
14 use MatthiasMullie\Minify\CSS;
15
16 // Do not allow directly accessing this file.
17 if ( ! defined( 'ABSPATH' ) ) {
18 exit( 'This script cannot be accessed directly.' );
19 }
20
21 /**
22 * AssetBundler class.
23 */
24 class AssetBundler {
25 /**
26 * Handle for this bundle (used in filename/versioning).
27 *
28 * @var string
29 */
30 protected $handle;
31
32 /**
33 * List of source file paths to bundle.
34 *
35 * @var array
36 */
37 protected $source_files = [];
38
39 /**
40 * Directory where a minified bundle will be saved.
41 *
42 * @var string
43 */
44 protected $upload_dir;
45
46 /**
47 * Generated filename of the minified JS file.
48 *
49 * @var string
50 */
51 protected $filename;
52
53 /**
54 * File type (JS or CSS).
55 *
56 * @var string
57 */
58 protected $type;
59
60 /**
61 * AssetBundler constructor.
62 *
63 * @param string $handle Unique identifier for the bundle.
64 * @param array $files List of absolute file paths to include in the bundle.
65 * @param string $type File type (JS or CSS).
66 *
67 * @return void
68 */
69 public function __construct( string $handle, array $files, string $type = 'js' ) {
70 $this->handle = sanitize_key( $handle );
71 $this->source_files = $files;
72 $this->type = in_array( $type, [ 'js', 'css' ], true ) ? $type : 'js';
73
74 $upload = wp_upload_dir();
75 $this->upload_dir = trailingslashit( $upload['basedir'] ) . "shopbuilder_uploads/cache/$this->type/";
76
77 $this->maybe_create_cache_dir();
78 }
79
80 /**
81 * Creates the cache directory if it doesn't exist.
82 *
83 * @return void
84 */
85 protected function maybe_create_cache_dir() {
86 if ( ! file_exists( $this->upload_dir ) ) {
87 wp_mkdir_p( $this->upload_dir );
88 }
89 }
90
91 /**
92 * Generates the full path to the cached JS file based on handle and file hash.
93 *
94 * @return string
95 */
96 protected function get_cache_file_path() {
97 $this->filename = $this->generate_filename();
98
99 return $this->upload_dir . $this->filename;
100 }
101
102 /**
103 * Checks if the cached version of the JS file already exists.
104 *
105 * @return bool
106 */
107 protected function is_cached() {
108 return file_exists( $this->get_cache_file_path() );
109 }
110
111 /**
112 * Builds the minified JS bundle if not cached and returns the URL.
113 *
114 * @return string
115 */
116 public function build() {
117 $cache_path = $this->get_cache_file_path();
118
119 if ( ! $this->is_cached() ) {
120 $minifier = ( 'css' === $this->type ) ? new CSS() : new JS();
121
122 foreach ( $this->source_files as $file ) {
123 $this->safely_add_file_to_minifier( $file, $minifier );
124 }
125
126 $minifier->minify( $cache_path );
127 }
128
129 return $this->get_url();
130 }
131
132 /**
133 * Returns the URL to the cached JS bundle.
134 *
135 * @return string
136 */
137 public function get_url() {
138 $upload = wp_upload_dir();
139
140 return trailingslashit( $upload['baseurl'] ) . "shopbuilder_uploads/cache/$this->type/" . $this->filename;
141 }
142
143 /**
144 * Clears all cached files related to this bundle handle.
145 *
146 * @return void
147 */
148 public function clear_cache() {
149 foreach ( glob( $this->upload_dir . "$this->handle-*.min.$this->type" ) as $file ) {
150 if ( file_exists( $file ) ) {
151 wp_delete_file( $file );
152 }
153 }
154 }
155
156 /**
157 * Generates the filename for the minified JS file.
158 *
159 * @return string
160 */
161 protected function generate_filename() {
162 $hash = md5( $this->handle . wp_json_encode( $this->source_files ) );
163
164 return "$this->handle-$hash.min.$this->type";
165 }
166
167 /**
168 * Rewrites relative font URLs in CSS to absolute plugin URLs.
169 *
170 * @param string $css The CSS content.
171 * @param string $base_path The base URL for resolving relative paths.
172 * @return string Modified CSS content with absolute font URLs.
173 */
174 protected function fix_font_urls( string $css, string $base_path ) {
175 $base_path = trailingslashit( $base_path );
176
177 return preg_replace_callback(
178 '/url\((["\']?)(?!https?:\/\/|\/)([^)]+?\.(?:eot|woff2?|ttf|svg|otf))(\?[^)]+)?\1\)/i',
179 function ( $matches ) use ( $base_path ) {
180 $relative_path = $matches[2];
181 $query = isset( $matches[3] ) ? $matches[3] : '';
182 $absolute_url = $base_path . ltrim( $relative_path, './\\' );
183 return 'url("' . esc_url( $absolute_url . $query ) . '")';
184 },
185 $css
186 );
187 }
188
189 /**
190 * Safely add file contents or path to the minifier.
191 *
192 * @param string $file File path.
193 * @param object $minifier Minifier instance.
194 *
195 * @return void
196 */
197 private function safely_add_file_to_minifier( $file, $minifier ) {
198 if ( ! is_string( $file ) ) {
199 return;
200 }
201
202 if ( ! is_readable( $file ) ) {
203 error_log( "[ShopBuilder Minify] Skipping unreadable file: $file" ); // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log
204
205 return;
206 }
207
208 if ( 'css' === $this->type ) {
209 $content = @file_get_contents( $file ); // phpcs:ignore WordPress.PHP.NoSilencedErrors.Discouraged, WordPress.WP.AlternativeFunctions.file_get_contents_file_get_contents
210
211 if ( false === $content ) {
212 error_log( "[ShopBuilder Minify] Failed to read file: $file" ); // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log
213
214 return;
215 }
216
217 $base_url = dirname( plugins_url( '', $file ), 2 );
218 $processed = $this->fix_font_urls( $content, $base_url );
219
220 $minifier->add( $processed );
221 } else {
222 $minifier->add( $file );
223 }
224 }
225 }
226