/var/www/html_us/wp-content/plugins/woocommerce/src/Blocks/Assets/Api.php


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
<?php
namespace Automattic\WooCommerce\Blocks\Assets;

use 
Automattic\WooCommerce\Blocks\Domain\Package;
use 
Exception;
use 
Automattic\Jetpack\Constants;
/**
 * The Api class provides an interface to various asset registration helpers.
 *
 * Contains asset api methods
 *
 * @since 2.5.0
 */
class Api {

    
/**
     * Stores the prefixed WC version. Used because the WC Blocks version has not been updated since the monorepo merge.
     *
     * @var string
     */
    
public $wc_version;

    
/**
     * Stores inline scripts already enqueued.
     *
     * @var array
     */
    
private $inline_scripts = [];

    
/**
     * Determines if caching is enabled for script data.
     *
     * @var boolean
     */
    
private $disable_cache false;

    
/**
     * Stores loaded script data for the current request
     *
     * @var array|null
     */
    
private $script_data null;

    
/**
     * Tracks whether script_data was modified during the current request.
     *
     * @var boolean
     */
    
private $script_data_modified false;

    
/**
     * Stores the hash for the script data, made up of the site url, plugin version and package path.
     *
     * @var string
     */
    
private $script_data_hash;

    
/**
     * Stores the transient key used to cache the script data. This will change if the site is accessed via HTTPS or HTTP.
     *
     * @var string
     */
    
private $script_data_transient_key 'woocommerce_blocks_asset_api_script_data';

    
/**
     * Reference to the Package instance
     *
     * @var Package
     */
    
private $package;

    
/**
     * Constructor for class
     *
     * @param Package $package An instance of Package.
     */
    
public function __constructPackage $package ) {
        
// Use wc- prefix here to prevent collisions when WC Core version catches up to a version previously used by the WC Blocks feature plugin.
        
$this->wc_version    'wc-' Constants::get_constant'WC_VERSION' );
        
$this->package       $package;
        
$this->disable_cache = ( defined'SCRIPT_DEBUG' ) && SCRIPT_DEBUG ) || wp_get_environment_type() !== 'production';

        
// If the site is accessed via HTTPS, change the transient key. This is to prevent the script URLs being cached
        // with the first scheme they are accessed on after cache expiry.
        
if ( is_ssl() ) {
            
$this->script_data_transient_key .= '_ssl';
        }
        if ( ! 
$this->disable_cache ) {
            
$this->script_data_hash $this->get_script_data_hash();
        }
        
add_action'shutdown', array( $this'update_script_data_cache' ), 20 );
    }

    
/**
     * Get the file modified time as a cache buster if we're in dev mode.
     *
     * @param string $file Local path to the file (relative to the plugin
     *                     directory).
     * @return string The cache buster value to use for the given file.
     */
    
protected function get_file_version$file ) {
        if ( 
defined'SCRIPT_DEBUG' ) && SCRIPT_DEBUG && file_exists$this->package->get_path() . $file ) ) {
            return 
filemtime$this->package->get_pathtrim$file'/' ) ) );
        }
        return 
$this->wc_version;
    }

    
/**
     * Retrieve the url to an asset for this plugin.
     *
     * @param string $relative_path An optional relative path appended to the
     *                              returned url.
     *
     * @return string
     */
    
protected function get_asset_url$relative_path '' ) {
        return 
$this->package->get_url$relative_path );
    }

    
/**
     * Get the path to a block's metadata
     *
     * @param string $block_name The block to get metadata for.
     * @param string $path Optional. The path to the metadata file inside the 'assets/client/blocks' folder.
     *
     * @return string|boolean False if metadata file is not found for the block.
     */
    
public function get_block_metadata_path$block_name$path '' ) {
        
$path_to_metadata_from_plugin_root $this->package->get_path'assets/client/blocks/' $path $block_name '/block.json' );
        if ( ! 
file_exists$path_to_metadata_from_plugin_root ) ) {
            return 
false;
        }
        return 
$path_to_metadata_from_plugin_root;
    }

    
/**
     * Generates a hash containing the site url, plugin version and package path.
     *
     * Moving the plugin, changing the version, or changing the site url will result in a new hash and the cache will be invalidated.
     *
     * @return string The generated hash.
     */
    
private function get_script_data_hash() {
        return 
md5get_option'siteurl''' ) . $this->wc_version $this->package->get_path() );
    }

    
/**
     * Initialize and load cached script data from the transient cache.
     *
     * @return array
     */
    
private function get_cached_script_data() {
        if ( 
$this->disable_cache ) {
            return [];
        }

        
$transient_value json_decode( (string) get_transient$this->script_data_transient_key ), true );

        if (
            
json_last_error() !== JSON_ERROR_NONE ||
            empty( 
$transient_value ) ||
            empty( 
$transient_value['script_data'] ) ||
            empty( 
$transient_value['version'] ) ||
            
$transient_value['version'] !== $this->wc_version ||
            empty( 
$transient_value['hash'] ) ||
            
$transient_value['hash'] !== $this->script_data_hash
        
) {
            return [];
        }

        return (array) ( 
$transient_value['script_data'] ?? [] );
    }

    
/**
     * Store all cached script data in the transient cache.
     */
    
public function update_script_data_cache() {
        if ( 
is_null$this->script_data ) || $this->disable_cache ) {
            return;
        }
        if ( ! 
$this->script_data_modified ) {
            return;
        }
        
set_transient(
            
$this->script_data_transient_key,
            
wp_json_encode(
                array(
                    
'script_data' => $this->script_data,
                    
'version'     => $this->wc_version,
                    
'hash'        => $this->script_data_hash,
                )
            ),
            
DAY_IN_SECONDS 30
        
);
    }

    
/**
     * Get src, version and dependencies given a script relative src.
     *
     * @param string $relative_src Relative src to the script.
     * @param array  $dependencies Optional. An array of registered script handles this script depends on. Default empty array.
     *
     * @return array src, version and dependencies of the script.
     */
    
public function get_script_data$relative_src$dependencies = [] ) {
        if ( ! 
$relative_src ) {
            return array(
                
'src'          => '',
                
'version'      => '1',
                
'dependencies' => $dependencies,
            );
        }

        if ( 
is_null$this->script_data ) ) {
            
$this->script_data $this->get_cached_script_data();
        }

        if ( empty( 
$this->script_data$relative_src ] ) ) {
            
$asset_path $this->package->get_pathstr_replace'.js''.asset.php'$relative_src ) );
            
// The following require is safe because we are checking if the file exists and it is not a user input.
            // nosemgrep audit.php.lang.security.file.inclusion-arg.
            
$asset file_exists$asset_path ) ? require $asset_path : [];

            
$this->script_data$relative_src ] = array(
                
'src'          => $this->get_asset_url$relative_src ),
                
'version'      => ! empty( $asset['version'] ) ? $asset['version'] : $this->get_file_version$relative_src ),
                
'dependencies' => ! empty( $asset['dependencies'] ) ? $asset['dependencies'] : [],
            );
            
$this->script_data_modified         true;
        }

        
// Return asset details as well as the requested dependencies array.
        
return [
            
'src'          => $this->script_data$relative_src ]['src'],
            
'version'      => $this->script_data$relative_src ]['version'],
            
'dependencies' => array_merge$this->script_data$relative_src ]['dependencies'], $dependencies ),
        ];
    }

    
/**
     * Registers a script according to `wp_register_script`, adding the correct prefix, and additionally loading translations.
     *
     * When creating script assets, the following rules should be followed:
     *   1. All asset handles should have a `wc-` prefix.
     *   2. If the asset handle is for a Block (in editor context) use the `-block` suffix.
     *   3. If the asset handle is for a Block (in frontend context) use the `-block-frontend` suffix.
     *   4. If the asset is for any other script being consumed or enqueued by the blocks plugin, use the `wc-blocks-` prefix.
     *
     * @since 2.5.0
     * @throws Exception If the registered script has a dependency on itself.
     *
     * @param string $handle        Unique name of the script.
     * @param string $relative_src  Relative url for the script to the path from plugin root.
     * @param array  $dependencies  Optional. An array of registered script handles this script depends on. Default empty array.
     * @param bool   $has_i18n      Optional. Whether to add a script translation call to this file. Default: true.
     */
    
public function register_script$handle$relative_src$dependencies = [], $has_i18n true ) {
        
$script_data $this->get_script_data$relative_src$dependencies );

        if ( 
in_array$handle$script_data['dependencies'], true ) ) {
            if ( 
wp_get_environment_type() === 'development' ) {
                
$dependencies array_diff$script_data['dependencies'], [ $handle ] );
                    
add_action(
                        
'admin_notices',
                        function() use ( 
$handle ) {
                                echo 
'<div class="error"><p>';
                                
/* translators: %s file handle name. */
                                
printfesc_html__'Script with handle %s had a dependency on itself which has been removed. This is an indicator that your JS code has a circular dependency that can cause bugs.''woocommerce' ), esc_html$handle ) );
                                echo 
'</p></div>';
                        }
                    );
            } else {
                throw new 
Exceptionsprintf'Script with handle %s had a dependency on itself. This is an indicator that your JS code has a circular dependency that can cause bugs.'$handle ) );
            }
        }

        
/**
         * Filters the list of script dependencies.
         *
         * @since 3.0.0
         *
         * @param array $dependencies The list of script dependencies.
         * @param string $handle The script's handle.
         * @return array
         */
        
$script_dependencies apply_filters'woocommerce_blocks_register_script_dependencies'$script_data['dependencies'], $handle );

        
wp_register_script$handle$script_data['src'], $script_dependencies$script_data['version'], true );

        if ( 
$has_i18n && function_exists'wp_set_script_translations' ) ) {
            
wp_set_script_translations$handle'woocommerce'$this->package->get_path'languages' ) );
            
wp_set_script_translations$handle'woocommerce'$this->package->get_path'i18n/languages' ) );
        }
    }

    
/**
     * Registers a style according to `wp_register_style`.
     *
     * @since 2.5.0
     * @since 2.6.0 Change src to be relative source.
     *
     * @param string  $handle       Name of the stylesheet. Should be unique.
     * @param string  $relative_src Relative source of the stylesheet to the plugin path.
     * @param array   $deps         Optional. An array of registered stylesheet handles this stylesheet depends on. Default empty array.
     * @param string  $media        Optional. The media for which this stylesheet has been defined. Default 'all'. Accepts media types like
     *                              'all', 'print' and 'screen', or media queries like '(orientation: portrait)' and '(max-width: 640px)'.
     * @param boolean $rtl   Optional. Whether or not to register RTL styles.
     */
    
public function register_style$handle$relative_src$deps = [], $media 'all'$rtl false ) {
        
$filename str_replaceplugins_url'/'dirname__DIR__ ) ), ''$relative_src );
        
$src      $this->get_asset_url$relative_src );
        
$ver      $this->get_file_version$filename );
        
wp_register_style$handle$src$deps$ver$media );

        if ( 
$rtl ) {
            
wp_style_add_data$handle'rtl''replace' );
        }
    }

    
/**
     * Returns the appropriate asset path for current builds.
     *
     * @param   string $filename  Filename for asset path (without extension).
     * @param   string $type      File type (.css or .js).
     * @return  string             The generated path.
     */
    
public function get_block_asset_build_path$filename$type 'js' ) {
        return 
"assets/client/blocks/$filename.$type";
    }

    
/**
     * Adds an inline script, once.
     *
     * @param string $handle Script handle.
     * @param string $script Script contents.
     */
    
public function add_inline_script$handle$script ) {
        if ( ! empty( 
$this->inline_scripts$handle ] ) && in_array$script$this->inline_scripts$handle ], true ) ) {
            return;
        }

        
wp_add_inline_script$handle$script );

        if ( isset( 
$this->inline_scripts$handle ] ) ) {
            
$this->inline_scripts$handle ][] = $script;
        } else {
            
$this->inline_scripts$handle ] = array( $script );
        }
    }
}