PluginProbe ʕ •ᴥ•ʔ
WooCommerce / 10.9.1
WooCommerce v10.9.1
10.9.3 10.9.2 10.9.1 10.9.0 10.9.0-rc.1 10.9.0-beta.2 10.9.0-beta.1 10.8.1 10.8.0 10.8.0-rc.1 10.8.0-beta.2 10.8.0-beta.1 7.8.0-beta.1 7.8.0-beta.2 7.8.0-rc.1 7.8.0-rc.2 7.8.1 7.8.2 7.8.3 7.8.4 7.9.0 7.9.0-beta.1 7.9.0-beta.2 7.9.0-rc.2 7.9.0-rc.3 7.9.1 7.9.2 8.0.0 8.0.0-beta.1 8.0.0-beta.2 8.0.0-rc.1 8.0.0-rc.2 8.0.1 8.0.2 8.0.3 8.0.4 8.0.5 8.1.0 8.1.0-beta.1 8.1.0-rc.1 8.1.0-rc.2 8.1.1 8.1.2 8.1.3 8.1.4 8.2.0 8.2.0-beta.1 8.2.0-rc.1 8.2.0-rc.2 8.2.1 8.2.2 8.2.3 8.2.4 8.2.5 8.3.0 8.3.0-beta.1 8.3.0-rc.1 8.3.0-rc.2 8.3.1 8.3.2 8.3.3 8.3.4 8.4.0 8.4.0-beta.1 8.4.0-rc.1 8.4.1 8.4.2 8.4.3 8.5.0 8.5.0-beta.1 8.5.0-rc.1 8.5.1 8.5.2 8.5.3 8.5.4 8.5.5 8.6.0 8.6.0-beta.1 8.6.0-rc.1 8.6.1 8.6.2 8.6.3 8.6.4 8.7.0 8.7.0-beta.1 8.7.0-beta.2 8.7.0-rc.1 8.7.1 8.7.2 8.7.3 8.8.0 8.8.0-beta.1 8.8.0-rc.1 8.8.1 8.8.2 8.8.3 8.8.4 8.8.5 8.8.6 8.8.7 8.9.0 8.9.0-beta.1 8.9.0-rc.1 8.9.1 8.9.2 8.9.3 8.9.4 8.9.5 9.0.0 9.0.0-beta.1 9.0.0-beta.2 9.0.0-rc.1 9.0.1 9.0.2 9.0.3 9.0.4 9.1.0 9.1.0-beta.1 9.1.0-rc.1 9.1.1 9.1.2 9.1.3 9.1.4 9.1.5 9.1.6 9.2.0 9.2.0-beta.1 9.2.0-rc.1 9.2.1 9.2.2 9.2.3 9.2.4 9.2.5 9.3.0 9.3.0-beta.1 9.3.0-rc.1 9.3.1 9.3.2 9.3.3 9.3.4 9.3.5 9.3.6 9.4.0 9.4.0-beta.1 9.4.0-beta.2 9.4.0-rc.1 9.4.0-rc.2 9.4.0-rc.3 9.4.0-rc.4 9.4.1 9.4.2 9.4.3 9.4.4 9.4.5 9.5.0 9.5.0-beta.1 9.5.0-beta.2 9.5.0-rc.1 9.5.1 9.5.2 9.5.3 9.5.4 9.6.0 9.6.0-beta.1 9.6.0-beta.2 9.6.0-rc.1 9.6.1 9.6.2 9.6.3 9.6.4 9.7.0 9.7.0-beta.1 9.7.0-rc.1 9.7.1 9.7.2 9.7.3 9.8.0 9.8.0-beta.1 9.8.0-rc.1 9.8.1 9.8.2 9.8.3 9.8.4 9.8.5 9.8.6 9.8.7 9.9.0 9.9.0-beta.1 9.9.0-rc.1 9.9.1 9.9.2 9.9.3 9.9.4 9.9.5 9.9.6 9.9.7 3.7.3 7.1.2 3.8.0 7.2.0 3.8.0-beta.1 7.2.0-beta.1 3.8.0-rc.1 7.2.0-beta.2 3.8.0-rc.2 7.2.0-rc.1 3.8.1 7.2.0-rc.2 3.8.2 7.2.1 3.8.3 7.2.2 3.9.0 7.2.3 3.9.0-beta.1 7.2.4 3.9.0-beta.2 7.3.0 3.9.0-rc.1 7.3.0-beta.1 3.9.0-rc.2 7.3.0-beta.2 3.9.0-rc.3 7.3.0-rc.1 3.9.0-rc.4 7.3.0-rc.2 3.9.1 7.3.1 3.9.2 7.4.0 3.9.3 7.4.0-beta.1 3.9.4 7.4.0-beta.2 3.9.5 7.4.0-rc.1 4.0.0 7.4.0-rc.2 4.0.0-beta.1 7.4.1 4.0.0-rc.1 7.4.2 4.0.0-rc.2 7.5.0 4.0.1 7.5.0-beta.1 4.0.2 7.5.0-beta.2 4.0.3 7.5.0-rc.1 4.0.4 7.5.1 4.1.0 7.5.2 4.1.0-beta.1 7.6.0 4.1.0-beta.2 7.6.0-beta.1 4.1.0-rc.1 7.6.0-beta.2 4.1.0-rc.2 7.6.0-rc.1 4.1.1 7.6.0-rc.2 4.1.2 7.6.0-rc.3 4.1.3 7.6.1 4.1.4 7.6.2 4.2.0 7.7.0 4.2.0-RC.1 7.7.0-beta.1 4.2.0-RC.2 7.7.0-beta.2 4.2.0-beta.1 7.7.0-rc.1 4.2.1 7.7.1 4.2.2 7.7.2 4.2.3 7.7.3 4.2.4 7.8.0 4.2.5 4.3.0 4.3.0-beta.1 4.3.0-rc.1 4.3.0-rc.2 4.3.0-rc.3 4.3.1 4.3.2 4.3.3 4.3.4 4.3.5 4.3.6 4.4.0 4.4.0-beta.1 4.4.0-rc.1 4.4.1 4.4.2 4.4.3 4.4.4 4.5.0 4.5.0-beta.1 4.5.0-rc.1 4.5.0-rc.3 4.5.1 4.5.2 4.5.3 4.5.4 4.5.5 4.6.0 4.6.0-beta.1 4.6.0-rc.1 4.6.1 4.6.2 4.6.3 4.6.4 4.6.5 4.7.0 4.7.0-beta.1 4.7.0-beta.2 4.7.0-rc.1 4.7.1 4.7.1-beta.1 4.7.2 4.7.3 4.7.4 4.8.0 4.8.0-beta.1 4.8.0-rc.1 4.8.0-rc.2 4.8.1 4.8.2 4.8.3 4.9.0 4.9.0-beta.1 4.9.0-rc.1 4.9.0-rc.2 4.9.1 4.9.2 4.9.3 4.9.4 4.9.5 5.0.0 5.0.0-beta.1 5.0.0-beta.2 5.0.0-rc.1 5.0.0-rc.2 5.0.0-rc.3 5.0.1 5.0.2 5.0.3 5.1.0 5.1.0-beta.1 5.1.0-rc.1 trunk 5.1.1 10.0.0 5.1.2 10.0.0-rc.1 5.1.3 10.0.0-rc.2 5.2.0 10.0.1 5.2.0-beta.1 10.0.2 5.2.0-rc.1 10.0.3 5.2.0-rc.2 10.0.4 5.2.1 10.0.5 5.2.2 10.0.6 5.2.3 10.1.0 5.2.4 10.1.0-rc.1 5.2.5 10.1.0-rc.2 5.3.0 10.1.0-rc.3 5.3.0-beta.1 10.1.0-rc.4 5.3.0-rc.1 10.1.1 5.3.0-rc.2 10.1.2 5.3.1 10.1.3 5.3.2 10.1.4 5.3.3 10.2.0 5.4.0 10.2.0-beta.1 5.4.0-beta.1 10.2.0-beta.2 5.4.0-rc.1 10.2.0-rc.1 5.4.1 10.2.1 5.4.2 10.2.2 5.4.3 10.2.3 5.4.4 10.2.4 5.4.5 10.3.0 5.5.0 10.3.0-beta.1 5.5.0-beta.1 10.3.0-beta.2 5.5.0-rc.1 10.3.0-rc.1 5.5.0-rc.2 10.3.0-rc.2 5.5.1 10.3.1 5.5.2 10.3.2 5.5.3 10.3.3 5.5.4 10.3.4 5.5.5 10.3.5 5.6.0 10.3.6 5.6.0-beta.1 10.3.7 5.6.0-rc.1 10.3.8 5.6.0-rc.2 10.4.0 5.6.1 10.4.0-beta.1 5.6.2 10.4.0-beta.2 5.6.3 10.4.0-rc.1 5.7.0 10.4.1 5.7.0-beta.1 10.4.2 5.7.0-rc.1 10.4.3 5.7.1 10.4.4 5.7.2 10.5.0 5.7.3 10.5.0-beta.1 5.8.0 10.5.0-beta.2 5.8.0-beta.1 10.5.0-rc.1 5.8.0-beta.2 10.5.0-rc.2 5.8.0-rc.1 10.5.0-rc.3 5.8.1 10.5.1 5.8.2 10.5.2 5.9.0 10.5.3 5.9.0-beta.1 10.6.0 5.9.0-rc.1 10.6.0-beta.1 5.9.0-rc.2 10.6.0-beta.2 5.9.1 10.6.0-rc.1 5.9.2 10.6.1 6.0.0 10.6.2 6.0.0-beta.1 10.7.0 6.0.0-rc.1 10.7.0-beta.1 6.0.1 10.7.0-beta.2 6.0.2 10.7.0-rc.1 6.1.0 3.0.0 6.1.0-beta.1 3.0.1 6.1.0-rc.1 3.0.2 6.1.0-rc.2 3.0.3 6.1.1 3.0.4 6.1.2 3.0.5 6.1.3 3.0.6 6.2.0 3.0.7 6.2.0-beta.1 3.0.8 6.2.0-rc.1 3.0.9 6.2.0-rc.2 3.1.0 6.2.1 3.1.1 6.2.2 3.1.2 6.2.3 3.2.0 6.3.0 3.2.1 6.3.0-beta.1 3.2.2 6.3.0-rc.1 3.2.3 6.3.0-rc.2 3.2.4 6.3.1 3.2.5 6.3.2 3.2.6 6.4.0 3.3.0 6.4.0-beta.1 3.3.1 6.4.0-rc.1 3.3.2 6.4.1 3.3.2-rc.1 6.4.2 3.3.3 6.5.0 3.3.4 6.5.0-beta.1 3.3.5 6.5.0-rc.1 3.3.6 6.5.0-rc.2 3.4.0 6.5.1 3.4.0-beta.1 6.5.2 3.4.0-rc.2 6.6.0 3.4.1 6.6.0-beta.1 3.4.2 6.6.0-rc.1 3.4.3 6.6.0-rc.2 3.4.4 6.6.1 3.4.5 6.6.2 3.4.6 6.7.0 3.4.7 6.7.0-beta.1 3.4.8 6.7.0-beta.2 3.5.0 6.7.0-rc.1 3.5.0-beta.1 6.7.1 3.5.0-rc.1 6.8.0 3.5.0-rc.2 6.8.0-beta.1 3.5.1 6.8.0-beta.2 3.5.10 6.8.0-rc.1 3.5.2 6.8.1 3.5.3 6.8.2 3.5.4 6.8.3 3.5.5 6.9.0 3.5.6 6.9.0-beta.1 3.5.7 6.9.0-beta.2 3.5.8 6.9.0-rc.1 3.5.9 6.9.1 3.6.0 6.9.2 3.6.0-beta.1 6.9.3 3.6.0-rc.1 6.9.4 3.6.0-rc.2 6.9.5 3.6.0-rc.3 7.0.0 3.6.1 7.0.0-beta.1 3.6.2 7.0.0-beta.2 3.6.3 7.0.0-beta.3 3.6.4 7.0.0-rc.1 3.6.5 7.0.0-rc.2 3.6.6 7.0.1 3.6.7 7.0.2 3.7.0 7.1.0 3.7.0-beta.1 7.1.0-beta.1 3.7.0-rc.1 7.1.0-beta.2 3.7.0-rc.2 7.1.0-rc.1 3.7.1 7.1.0-rc.2 3.7.2 7.1.1
woocommerce / src / Blocks / AssetsController.php
woocommerce / src / Blocks Last commit date
AI 1 year ago AIContent 1 year ago Assets 4 weeks ago BlockTypes 2 weeks ago Domain 2 months ago Images 1 year ago Integrations 2 years ago Patterns 6 months ago Payments 5 months ago Registry 2 years ago SharedStores 2 months ago Shipping 7 months ago Templates 2 months ago Utils 4 weeks ago Assets.php 2 years ago AssetsController.php 4 weeks ago BlockPatterns.php 7 months ago BlockTemplatesController.php 7 months ago BlockTemplatesRegistry.php 10 months ago BlockTypesController.php 4 weeks ago DependencyDetection.php 5 months ago InboxNotifications.php 2 years ago Installer.php 2 months ago Library.php 2 years ago Options.php 2 years ago Package.php 1 year ago QueryFilters.php 7 months ago TemplateOptions.php 1 year ago
AssetsController.php
511 lines
1 <?php
2 declare( strict_types = 1 );
3
4 namespace Automattic\WooCommerce\Blocks;
5
6 use Automattic\Jetpack\Constants;
7 use Automattic\WooCommerce\Blocks\Assets\Api as AssetApi;
8
9 /**
10 * AssetsController class.
11 *
12 * @since 5.0.0
13 * @internal
14 */
15 final class AssetsController {
16
17 /**
18 * Asset API interface for various asset registration.
19 *
20 * @var AssetApi
21 */
22 private $api;
23
24 /**
25 * Constructor.
26 *
27 * @param AssetApi $asset_api Asset API interface for various asset registration.
28 */
29 public function __construct( AssetApi $asset_api ) {
30 $this->api = $asset_api;
31 $this->init();
32 }
33
34 /**
35 * Initialize class features.
36 */
37 protected function init() { // phpcs:ignore WooCommerce.Functions.InternalInjectionMethod.MissingPublic
38 add_action( 'init', array( $this, 'register_assets' ) );
39 add_action( 'init', array( $this, 'register_script_modules' ) );
40 add_action( 'enqueue_block_editor_assets', array( $this, 'register_and_enqueue_site_editor_assets' ) );
41 add_filter( 'wp_resource_hints', array( $this, 'add_resource_hints' ), 10, 2 );
42 add_action( 'body_class', array( $this, 'add_theme_body_class' ), 1 );
43 add_action( 'admin_body_class', array( $this, 'add_theme_body_class' ), 1 );
44 add_action( 'admin_enqueue_scripts', array( $this, 'update_block_style_dependencies' ), 20 );
45 add_action( 'wp_enqueue_scripts', array( $this, 'update_block_settings_dependencies' ), 100 );
46 add_action( 'admin_enqueue_scripts', array( $this, 'update_block_settings_dependencies' ), 100 );
47 add_action( 'admin_enqueue_scripts', array( $this, 'enqueue_wc_entities' ), 100 );
48 add_filter( 'js_do_concat', array( $this, 'skip_boost_minification_for_cart_checkout' ), 10, 2 );
49 }
50
51 /**
52 * Register script modules.
53 */
54 public function register_script_modules() {
55 // Right now we only have one script modules build for supported interactivity API powered block front-ends.
56 // We generate a combined asset file for that via DependencyExtractionWebpackPlugin to make registration more
57 // efficient.
58 $asset_data = $this->api->get_asset_data(
59 $this->api->get_block_asset_build_path( 'interactivity-blocks-frontend-assets', 'php' )
60 );
61
62 foreach ( $asset_data as $handle => $data ) {
63 $handle_without_js = str_replace( '.js', '', $handle );
64 wp_register_script_module( $handle_without_js, plugins_url( $this->api->get_block_asset_build_path( $handle_without_js ), dirname( __DIR__ ) ), $data['dependencies'], $data['version'] );
65 }
66 }
67
68 /**
69 * Register block scripts & styles.
70 */
71 public function register_assets() {
72 $this->register_style( 'wc-blocks-packages-style', plugins_url( $this->api->get_block_asset_build_path( 'packages-style', 'css' ), dirname( __DIR__ ) ), array(), 'all', true );
73 $this->register_style( 'wc-blocks-style', plugins_url( $this->api->get_block_asset_build_path( 'wc-blocks', 'css' ), dirname( __DIR__ ) ), array(), 'all', true );
74 $this->register_style( 'wc-blocks-editor-style', plugins_url( $this->api->get_block_asset_build_path( 'wc-blocks-editor-style', 'css' ), dirname( __DIR__ ) ), array( 'wp-edit-blocks' ), 'all', true );
75
76 $this->api->register_script( 'wc-types', $this->api->get_block_asset_build_path( 'wc-types' ), array(), false );
77 $this->api->register_script( 'wc-entities', 'assets/client/blocks/wc-entities.js', array(), false );
78 $this->api->register_script( 'wc-blocks-middleware', 'assets/client/blocks/wc-blocks-middleware.js', array(), false );
79 $this->api->register_script( 'wc-blocks-data-store', 'assets/client/blocks/wc-blocks-data.js', array( 'wc-blocks-middleware' ) );
80 $this->api->register_script( 'wc-blocks-vendors', $this->api->get_block_asset_build_path( 'wc-blocks-vendors' ), array(), false );
81 $this->api->register_script( 'wc-blocks-registry', 'assets/client/blocks/wc-blocks-registry.js', array(), false );
82 $this->api->register_script( 'wc-blocks', $this->api->get_block_asset_build_path( 'wc-blocks' ), array( 'wc-blocks-vendors' ), false );
83 $this->api->register_script( 'wc-blocks-shared-context', 'assets/client/blocks/wc-blocks-shared-context.js' );
84 $this->api->register_script( 'wc-blocks-shared-hocs', 'assets/client/blocks/wc-blocks-shared-hocs.js', array(), false );
85
86 // The price package is shared externally so has no blocks prefix.
87 $this->api->register_script( 'wc-price-format', 'assets/client/blocks/price-format.js', array(), false );
88
89 // Vendor scripts for blocks frontends (not including cart and checkout).
90 $this->api->register_script( 'wc-blocks-frontend-vendors', $this->api->get_block_asset_build_path( 'wc-blocks-frontend-vendors-frontend' ), array(), true );
91
92 // Cart and checkout frontend scripts.
93 $this->api->register_script( 'wc-cart-checkout-vendors', $this->api->get_block_asset_build_path( 'wc-cart-checkout-vendors-frontend' ), array(), true );
94 $this->api->register_script( 'wc-cart-checkout-base', $this->api->get_block_asset_build_path( 'wc-cart-checkout-base-frontend' ), array(), true );
95 $this->api->register_script( 'wc-blocks-checkout', 'assets/client/blocks/blocks-checkout.js' );
96 $this->api->register_script( 'wc-blocks-checkout-events', 'assets/client/blocks/blocks-checkout-events.js' );
97 $this->api->register_script( 'wc-blocks-components', 'assets/client/blocks/blocks-components.js' );
98 $this->api->register_script( 'wc-schema-parser', 'assets/client/blocks/wc-schema-parser.js', array(), false );
99
100 // Sanitize.
101 $this->api->register_script(
102 'wc-sanitize',
103 'assets/client/admin/sanitize/index.js',
104 array()
105 );
106
107 // Customer Effort Score.
108 $this->api->register_script(
109 'wc-customer-effort-score',
110 'assets/client/admin/customer-effort-score/index.js',
111 array( 'wp-data', 'wp-data-controls', 'wc-store-data' )
112 );
113 $this->api->register_style(
114 'wc-customer-effort-score',
115 'assets/client/admin/customer-effort-score/style.css',
116 );
117
118 wp_add_inline_script(
119 'wc-blocks-middleware',
120 "
121 var wcBlocksMiddlewareConfig = {
122 storeApiNonce: '" . esc_js( wp_create_nonce( 'wc_store_api' ) ) . "',
123 wcStoreApiNonceTimestamp: '" . esc_js( time() ) . "'
124 };
125 ",
126 'before'
127 );
128 }
129
130 /**
131 * Register and enqueue assets for exclusive usage within the Site Editor.
132 */
133 public function register_and_enqueue_site_editor_assets() {
134 // Customer Effort Score.
135 wp_enqueue_script( 'wc-customer-effort-score' );
136 wp_enqueue_style( 'wc-customer-effort-score' );
137 }
138
139 /**
140 * Defines resource hints to help speed up the loading of some critical blocks.
141 *
142 * These will not impact page loading times negatively because they are loaded once the current page is idle.
143 *
144 * @param array $urls URLs to print for resource hints. Each URL is an array of resource attributes, or a URL string.
145 * @param string $relation_type The relation type the URLs are printed. Possible values: preconnect, dns-prefetch, prefetch, prerender.
146 * @return array URLs to print for resource hints.
147 */
148 public function add_resource_hints( $urls, $relation_type ) {
149 if ( ! in_array( $relation_type, array( 'prefetch', 'prerender' ), true ) || is_admin() ) {
150 return $urls;
151 }
152
153 // We only need to prefetch when the cart has contents.
154 $cart = wc()->cart;
155
156 if ( ! $cart instanceof \WC_Cart || 0 === $cart->get_cart_contents_count() ) {
157 return $urls;
158 }
159
160 if ( 'prefetch' === $relation_type ) {
161 $urls = array_merge(
162 $urls,
163 $this->get_prefetch_resource_hints()
164 );
165 }
166
167 if ( 'prerender' === $relation_type ) {
168 $urls = array_merge(
169 $urls,
170 $this->get_prerender_resource_hints()
171 );
172 }
173
174 return $urls;
175 }
176
177 /**
178 * Get resource hints during prefetch requests.
179 *
180 * @return array Array of URLs.
181 */
182 private function get_prefetch_resource_hints() {
183 $urls = array();
184
185 // Core page IDs.
186 $cart_page_id = wc_get_page_id( 'cart' );
187 $checkout_page_id = wc_get_page_id( 'checkout' );
188
189 // Checks a specific page (by ID) to see if it contains the named block.
190 $has_block_cart = $cart_page_id && has_block( 'woocommerce/cart', $cart_page_id );
191 $has_block_checkout = $checkout_page_id && has_block( 'woocommerce/checkout', $checkout_page_id );
192
193 // Checks the current page to see if it contains the named block.
194 $is_block_cart = has_block( 'woocommerce/cart' );
195 $is_block_checkout = has_block( 'woocommerce/checkout' );
196
197 if ( $has_block_cart && ! $is_block_cart ) {
198 $urls = array_merge( $urls, $this->get_block_asset_resource_hints( 'cart-frontend' ) );
199 }
200
201 if ( $has_block_checkout && ! $is_block_checkout ) {
202 $urls = array_merge( $urls, $this->get_block_asset_resource_hints( 'checkout-frontend' ) );
203 }
204
205 return $urls;
206 }
207
208 /**
209 * Get resource hints during prerender requests.
210 *
211 * @return array Array of URLs.
212 */
213 private function get_prerender_resource_hints() {
214 $urls = array();
215 $is_block_cart = has_block( 'woocommerce/cart' );
216
217 if ( ! $is_block_cart ) {
218 return $urls;
219 }
220
221 $checkout_page_id = wc_get_page_id( 'checkout' );
222 $checkout_page_url = $checkout_page_id ? get_permalink( $checkout_page_id ) : '';
223
224 if ( $checkout_page_url ) {
225 $urls[] = $checkout_page_url;
226 }
227
228 return $urls;
229 }
230
231 /**
232 * Get the block asset resource hints in the cache or null if not found.
233 *
234 * @return array|null Array of resource hints.
235 */
236 private function get_block_asset_resource_hints_cache() {
237 if ( wp_is_development_mode( 'plugin' ) ) {
238 return null;
239 }
240
241 $cache = get_transient( 'woocommerce_block_asset_resource_hints' );
242
243 $current_version = array(
244 'woocommerce' => Constants::get_constant( 'WC_VERSION' ),
245 'wordpress' => get_bloginfo( 'version' ),
246 'site_url' => site_url(),
247 );
248
249 if ( isset( $cache['version'] ) && $cache['version'] === $current_version ) {
250 return $cache['files'];
251 }
252
253 return null;
254 }
255
256 /**
257 * Set the block asset resource hints in the cache.
258 *
259 * @param string $filename File name.
260 * @param array $data Array of resource hints.
261 */
262 private function set_block_asset_resource_hints_cache( $filename, $data ) {
263 $cache = $this->get_block_asset_resource_hints_cache();
264 $updated = array(
265 'files' => $cache ?? array(),
266 'version' => array(
267 'woocommerce' => Constants::get_constant( 'WC_VERSION' ),
268 'wordpress' => get_bloginfo( 'version' ),
269 'site_url' => site_url(),
270 ),
271 );
272
273 $updated['files'][ $filename ] = $data;
274 set_transient( 'woocommerce_block_asset_resource_hints', $updated, WEEK_IN_SECONDS );
275 }
276
277 /**
278 * Get resource hint for a block by name.
279 *
280 * @param string $filename Block filename.
281 * @return array
282 */
283 private function get_block_asset_resource_hints( $filename = '' ) {
284 if ( ! $filename ) {
285 return array();
286 }
287
288 $cached = $this->get_block_asset_resource_hints_cache();
289
290 if ( isset( $cached[ $filename ] ) ) {
291 return $cached[ $filename ];
292 }
293
294 $script_data = $this->api->get_script_data(
295 $this->api->get_block_asset_build_path( $filename )
296 );
297 $resources = array_merge(
298 array( esc_url( add_query_arg( 'ver', $script_data['version'], $script_data['src'] ) ) ),
299 $this->get_script_dependency_src_array( $script_data['dependencies'] )
300 );
301
302 $data = array_map(
303 function ( $src ) {
304 return array(
305 'href' => $src,
306 'as' => 'script',
307 );
308 },
309 array_unique( array_filter( $resources ) )
310 );
311
312 $this->set_block_asset_resource_hints_cache( $filename, $data );
313
314 return $data;
315 }
316
317 /**
318 * Get the src of all script dependencies (handles).
319 *
320 * @param array $dependencies Array of dependency handles.
321 * @return string[] Array of src strings.
322 */
323 private function get_script_dependency_src_array( array $dependencies ) {
324 $wp_scripts = wp_scripts();
325
326 $found_dependencies = array();
327 $this->gather_script_dependency_handles( $dependencies, $wp_scripts, $found_dependencies );
328
329 $src = array();
330 foreach ( $found_dependencies as $handle => $unused ) {
331 $src[] = esc_url( add_query_arg( 'ver', $wp_scripts->registered[ $handle ]->ver, $this->get_absolute_url( $wp_scripts->registered[ $handle ]->src ) ) );
332 }
333 return $src;
334 }
335
336 /**
337 * Recursively gather all unique script dependency handles from a starting list.
338 *
339 * Traverses the dependency graph for each input handle, collecting any found handles
340 * and their nested dependencies in the provided array. Used internally to build a
341 * complete, deduplicated set of handles for further processing (e.g., mapping to src URLs).
342 *
343 * @param array $dependencies Array of initial script handles to process.
344 * @param \WP_Scripts $wp_scripts WP_Scripts instance containing all registered scripts.
345 * @param array $found_dependencies Reference to array in which discovered handles are stored.
346 *
347 * @return void
348 */
349 private function gather_script_dependency_handles( array $dependencies, \WP_Scripts $wp_scripts, &$found_dependencies = array() ) {
350 foreach ( $dependencies as $handle ) {
351 if ( isset( $wp_scripts->registered[ $handle ] ) && ! isset( $found_dependencies[ $handle ] ) ) {
352 $found_dependencies[ $handle ] = true;
353 if ( ! empty( $wp_scripts->registered[ $handle ]->deps ) ) {
354 $this->gather_script_dependency_handles( $wp_scripts->registered[ $handle ]->deps, $wp_scripts, $found_dependencies );
355 }
356 }
357 }
358 }
359
360 /**
361 * Returns an absolute url to relative links for WordPress core scripts.
362 *
363 * @param string $src Original src that can be relative.
364 * @return string Correct full path string.
365 */
366 private function get_absolute_url( $src ) {
367 $wp_scripts = wp_scripts();
368 if ( ! preg_match( '|^(https?:)?//|', $src ) && ! ( $wp_scripts->content_url && 0 === strpos( $src, $wp_scripts->content_url ) ) ) {
369 $src = $wp_scripts->base_url . $src;
370 }
371 return $src;
372 }
373
374 /**
375 * Skip Jetpack Boost minification on older versions of Jetpack Boost where it causes issues.
376 *
377 * @param mixed $do_concat Whether to concatenate the script or not.
378 * @param mixed $handle The script handle.
379 * @return mixed
380 */
381 public function skip_boost_minification_for_cart_checkout( $do_concat, $handle ) {
382 $boost_is_outdated = defined( 'JETPACK_BOOST_VERSION' ) && version_compare( JETPACK_BOOST_VERSION, '3.4.2', '<' );
383 $scripts_to_ignore = array(
384 'wc-cart-checkout-vendors',
385 'wc-cart-checkout-base',
386 );
387
388 return $boost_is_outdated && in_array( $handle, $scripts_to_ignore, true ) ? false : $do_concat;
389 }
390
391 /**
392 * Add body classes to the frontend and within admin.
393 *
394 * @param string|array $classes Array or string of CSS classnames.
395 * @return string|array Modified classnames.
396 */
397 public function add_theme_body_class( $classes ) {
398 $class = 'theme-' . get_template();
399
400 if ( is_array( $classes ) ) {
401 $classes[] = $class;
402 } else {
403 $classes .= ' ' . $class . ' ';
404 }
405
406 return $classes;
407 }
408
409 /**
410 * Get the file modified time as a cache buster if we're in dev mode.
411 *
412 * @param string $file Local path to the file.
413 * @return string The cache buster value to use for the given file.
414 */
415 protected function get_file_version( $file ) {
416 if ( defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG && file_exists( \Automattic\WooCommerce\Blocks\Package::get_path() . $file ) ) {
417 return filemtime( \Automattic\WooCommerce\Blocks\Package::get_path() . $file );
418 }
419 return $this->api->wc_version;
420 }
421
422 /**
423 * Registers a style according to `wp_register_style`.
424 *
425 * @param string $handle Name of the stylesheet. Should be unique.
426 * @param string $src Full URL of the stylesheet, or path of the stylesheet relative to the WordPress root directory.
427 * @param array $deps Optional. An array of registered stylesheet handles this stylesheet depends on. Default empty array.
428 * @param string $media Optional. The media for which this stylesheet has been defined. Default 'all'. Accepts media types like
429 * 'all', 'print' and 'screen', or media queries like '(orientation: portrait)' and '(max-width: 640px)'.
430 * @param boolean $rtl Optional. Whether or not to register RTL styles.
431 */
432 protected function register_style( $handle, $src, $deps = array(), $media = 'all', $rtl = false ) {
433 $filename = str_replace( plugins_url( '/', dirname( __DIR__ ) ), '', $src );
434 $ver = self::get_file_version( $filename );
435
436 wp_register_style( $handle, $src, $deps, $ver, $media );
437
438 if ( $rtl ) {
439 wp_style_add_data( $handle, 'rtl', 'replace' );
440 }
441 }
442
443 /**
444 * Update block style dependencies after they have been registered.
445 */
446 public function update_block_style_dependencies() {
447 $wp_styles = wp_styles();
448 $style = $wp_styles->query( 'wc-blocks-style', 'registered' );
449
450 if ( ! $style ) {
451 return;
452 }
453
454 // In WC < 5.5, `woocommerce-general` is not registered in block editor
455 // screens, so we don't add it as a dependency if it's not registered.
456 // In WC >= 5.5, `woocommerce-general` is registered on `admin_enqueue_scripts`,
457 // so we need to check if it's registered here instead of on `init`.
458 if (
459 wp_style_is( 'woocommerce-general', 'registered' ) &&
460 ! in_array( 'woocommerce-general', $style->deps, true )
461 ) {
462 $style->deps[] = 'woocommerce-general';
463 }
464 }
465
466 /**
467 * Fix scripts with wc-settings dependency.
468 *
469 * The wc-settings script only works correctly when enqueued in the footer. This is to give blocks etc time to
470 * register their settings data before it's printed.
471 *
472 * This code will look at registered scripts, and if they have a wc-settings dependency, force them to print in the
473 * footer instead of the header.
474 *
475 * This only supports packages known to require wc-settings!
476 *
477 * @see https://github.com/woocommerce/woocommerce-gutenberg-products-block/issues/5052
478 */
479 public function update_block_settings_dependencies() {
480 $wp_scripts = wp_scripts();
481 $known_packages = array( 'wc-settings', 'wc-blocks-checkout', 'wc-price-format' );
482
483 foreach ( $wp_scripts->registered as $handle => $script ) {
484 // scripts that are loaded in the footer has extra->group = 1.
485 if ( array_intersect( $known_packages, $script->deps ) && ! isset( $script->extra['group'] ) ) {
486 // Append the script to footer.
487 $wp_scripts->add_data( $handle, 'group', 1 );
488 // Show a warning.
489 $error_handle = 'wc-settings-dep-in-header';
490 $used_deps = implode( ', ', array_intersect( $known_packages, $script->deps ) );
491 $error_message = "Scripts that have a dependency on [$used_deps] must be loaded in the footer, {$handle} was registered to load in the header, but has been switched to load in the footer instead. See https://github.com/woocommerce/woocommerce-gutenberg-products-block/pull/5059";
492 // phpcs:ignore WordPress.WP.EnqueuedResourceParameters.NotInFooter,WordPress.WP.EnqueuedResourceParameters.MissingVersion
493 wp_register_script( $error_handle, '' );
494 wp_enqueue_script( $error_handle );
495 wp_add_inline_script(
496 $error_handle,
497 sprintf( 'console.warn( "%s" );', $error_message )
498 );
499
500 }
501 }
502 }
503
504 /**
505 * Enqueue the wc-entities script.
506 */
507 public function enqueue_wc_entities() {
508 wp_enqueue_script( 'wc-entities' );
509 }
510 }
511