Commit 9899f3b6f1 for woocommerce

commit 9899f3b6f1f8f3752f7dc557331b4f1c917bdcb5
Author: Sam Seay <samueljseay@gmail.com>
Date:   Thu Dec 11 17:16:32 2025 +1300

    Refactor BlocksSharedState to a class with static methods to fix duplicate state registration (#62168)

diff --git a/plugins/woocommerce/changelog/62168-wooplug-5663-mini-cart-register_cart_interactivity-logic-runs-multiple b/plugins/woocommerce/changelog/62168-wooplug-5663-mini-cart-register_cart_interactivity-logic-runs-multiple
new file mode 100644
index 0000000000..d9e73511ef
--- /dev/null
+++ b/plugins/woocommerce/changelog/62168-wooplug-5663-mini-cart-register_cart_interactivity-logic-runs-multiple
@@ -0,0 +1,4 @@
+Significance: minor
+Type: fix
+
+Migrate BlocksSharedState to a class with static methods to fix a bug where state was duplicated between block instances.
\ No newline at end of file
diff --git a/plugins/woocommerce/phpstan-baseline.neon b/plugins/woocommerce/phpstan-baseline.neon
index 40c1b79a54..e1dbb1f5fa 100644
--- a/plugins/woocommerce/phpstan-baseline.neon
+++ b/plugins/woocommerce/phpstan-baseline.neon
@@ -73287,24 +73287,6 @@ parameters:
 			count: 1
 			path: src/Blocks/BlockTypes/MiniCart.php

-		-
-			message: '#^Method Automattic\\WooCommerce\\Blocks\\BlockTypes\\MiniCart\:\:initialize_shared_config\(\) has no return type specified\.$#'
-			identifier: missingType.return
-			count: 1
-			path: src/Blocks/BlockTypes/MiniCart.php
-
-		-
-			message: '#^Method Automattic\\WooCommerce\\Blocks\\BlockTypes\\MiniCart\:\:placeholder_image\(\) has no return type specified\.$#'
-			identifier: missingType.return
-			count: 1
-			path: src/Blocks/BlockTypes/MiniCart.php
-
-		-
-			message: '#^Method Automattic\\WooCommerce\\Blocks\\BlockTypes\\MiniCart\:\:prevent_cache\(\) has no return type specified\.$#'
-			identifier: missingType.return
-			count: 1
-			path: src/Blocks/BlockTypes/MiniCart.php
-
 		-
 			message: '#^Method Automattic\\WooCommerce\\Blocks\\BlockTypes\\MiniCart\:\:print_lazy_load_scripts\(\) has no return type specified\.$#'
 			identifier: missingType.return
@@ -73449,12 +73431,6 @@ parameters:
 			count: 2
 			path: src/Blocks/BlockTypes/MiniCart.php

-		-
-			message: '#^Property WooCommerce\:\:\$cart \(WC_Cart\) in isset\(\) is not nullable\.$#'
-			identifier: isset.property
-			count: 1
-			path: src/Blocks/BlockTypes/MiniCart.php
-
 		-
 			message: '#^Result of && is always false\.$#'
 			identifier: booleanAnd.alwaysFalse
@@ -74091,24 +74067,6 @@ parameters:
 			count: 1
 			path: src/Blocks/BlockTypes/ProductButton.php

-		-
-			message: '#^Method Automattic\\WooCommerce\\Blocks\\BlockTypes\\ProductButton\:\:initialize_shared_config\(\) has no return type specified\.$#'
-			identifier: missingType.return
-			count: 1
-			path: src/Blocks/BlockTypes/ProductButton.php
-
-		-
-			message: '#^Method Automattic\\WooCommerce\\Blocks\\BlockTypes\\ProductButton\:\:placeholder_image\(\) has no return type specified\.$#'
-			identifier: missingType.return
-			count: 1
-			path: src/Blocks/BlockTypes/ProductButton.php
-
-		-
-			message: '#^Method Automattic\\WooCommerce\\Blocks\\BlockTypes\\ProductButton\:\:prevent_cache\(\) has no return type specified\.$#'
-			identifier: missingType.return
-			count: 1
-			path: src/Blocks/BlockTypes/ProductButton.php
-
 		-
 			message: '#^Parameter \#3 \$block of method Automattic\\WooCommerce\\Blocks\\BlockTypes\\AbstractBlock\:\:enqueue_assets\(\) expects WP_Block, Automattic\\WooCommerce\\Blocks\\BlockTypes\\WP_Block given\.$#'
 			identifier: argument.type
@@ -74130,7 +74088,7 @@ parameters:
 		-
 			message: '#^Property WooCommerce\:\:\$cart \(WC_Cart\) in isset\(\) is not nullable\.$#'
 			identifier: isset.property
-			count: 2
+			count: 1
 			path: src/Blocks/BlockTypes/ProductButton.php

 		-
@@ -75315,24 +75273,6 @@ parameters:
 			count: 1
 			path: src/Blocks/BlockTypes/ProductFilters.php

-		-
-			message: '#^Method Automattic\\WooCommerce\\Blocks\\BlockTypes\\ProductFilters\:\:initialize_shared_config\(\) has no return type specified\.$#'
-			identifier: missingType.return
-			count: 1
-			path: src/Blocks/BlockTypes/ProductFilters.php
-
-		-
-			message: '#^Method Automattic\\WooCommerce\\Blocks\\BlockTypes\\ProductFilters\:\:placeholder_image\(\) has no return type specified\.$#'
-			identifier: missingType.return
-			count: 1
-			path: src/Blocks/BlockTypes/ProductFilters.php
-
-		-
-			message: '#^Method Automattic\\WooCommerce\\Blocks\\BlockTypes\\ProductFilters\:\:prevent_cache\(\) has no return type specified\.$#'
-			identifier: missingType.return
-			count: 1
-			path: src/Blocks/BlockTypes/ProductFilters.php
-
 		-
 			message: '#^Method Automattic\\WooCommerce\\Blocks\\BlockTypes\\ProductFilters\:\:render\(\) should return string but returns string\|false\.$#'
 			identifier: return.type
@@ -75369,12 +75309,6 @@ parameters:
 			count: 1
 			path: src/Blocks/BlockTypes/ProductFilters.php

-		-
-			message: '#^Property WooCommerce\:\:\$cart \(WC_Cart\) in isset\(\) is not nullable\.$#'
-			identifier: isset.property
-			count: 1
-			path: src/Blocks/BlockTypes/ProductFilters.php
-
 		-
 			message: '#^Access to property \$context on an unknown class Automattic\\WooCommerce\\Blocks\\BlockTypes\\WP_Block\.$#'
 			identifier: class.notFound
@@ -75597,24 +75531,6 @@ parameters:
 			count: 1
 			path: src/Blocks/BlockTypes/ProductPrice.php

-		-
-			message: '#^Method Automattic\\WooCommerce\\Blocks\\BlockTypes\\ProductPrice\:\:initialize_shared_config\(\) has no return type specified\.$#'
-			identifier: missingType.return
-			count: 1
-			path: src/Blocks/BlockTypes/ProductPrice.php
-
-		-
-			message: '#^Method Automattic\\WooCommerce\\Blocks\\BlockTypes\\ProductPrice\:\:placeholder_image\(\) has no return type specified\.$#'
-			identifier: missingType.return
-			count: 1
-			path: src/Blocks/BlockTypes/ProductPrice.php
-
-		-
-			message: '#^Method Automattic\\WooCommerce\\Blocks\\BlockTypes\\ProductPrice\:\:prevent_cache\(\) has no return type specified\.$#'
-			identifier: missingType.return
-			count: 1
-			path: src/Blocks/BlockTypes/ProductPrice.php
-
 		-
 			message: '#^Method Automattic\\WooCommerce\\Blocks\\BlockTypes\\ProductPrice\:\:register_block_type_assets\(\) has no return type specified\.$#'
 			identifier: missingType.return
@@ -75633,12 +75549,6 @@ parameters:
 			count: 1
 			path: src/Blocks/BlockTypes/ProductPrice.php

-		-
-			message: '#^Property WooCommerce\:\:\$cart \(WC_Cart\) in isset\(\) is not nullable\.$#'
-			identifier: isset.property
-			count: 1
-			path: src/Blocks/BlockTypes/ProductPrice.php
-
 		-
 			message: '#^Access to property \$context on an unknown class Automattic\\WooCommerce\\Blocks\\BlockTypes\\WP_Block\.$#'
 			identifier: class.notFound
@@ -76047,24 +75957,6 @@ parameters:
 			count: 1
 			path: src/Blocks/BlockTypes/ProductStockIndicator.php

-		-
-			message: '#^Method Automattic\\WooCommerce\\Blocks\\BlockTypes\\ProductStockIndicator\:\:initialize_shared_config\(\) has no return type specified\.$#'
-			identifier: missingType.return
-			count: 1
-			path: src/Blocks/BlockTypes/ProductStockIndicator.php
-
-		-
-			message: '#^Method Automattic\\WooCommerce\\Blocks\\BlockTypes\\ProductStockIndicator\:\:placeholder_image\(\) has no return type specified\.$#'
-			identifier: missingType.return
-			count: 1
-			path: src/Blocks/BlockTypes/ProductStockIndicator.php
-
-		-
-			message: '#^Method Automattic\\WooCommerce\\Blocks\\BlockTypes\\ProductStockIndicator\:\:prevent_cache\(\) has no return type specified\.$#'
-			identifier: missingType.return
-			count: 1
-			path: src/Blocks/BlockTypes/ProductStockIndicator.php
-
 		-
 			message: '#^Method Automattic\\WooCommerce\\Blocks\\BlockTypes\\ProductStockIndicator\:\:register_block_type_assets\(\) has no return type specified\.$#'
 			identifier: missingType.return
@@ -76077,12 +75969,6 @@ parameters:
 			count: 1
 			path: src/Blocks/BlockTypes/ProductStockIndicator.php

-		-
-			message: '#^Property WooCommerce\:\:\$cart \(WC_Cart\) in isset\(\) is not nullable\.$#'
-			identifier: isset.property
-			count: 1
-			path: src/Blocks/BlockTypes/ProductStockIndicator.php
-
 		-
 			message: '#^Variable \$content in empty\(\) always exists and is always falsy\.$#'
 			identifier: empty.variable
@@ -78471,24 +78357,6 @@ parameters:
 			count: 1
 			path: src/Blocks/Templates/SingleProductTemplate.php

-		-
-			message: '#^Method Automattic\\WooCommerce\\Blocks\\Templates\\SingleProductTemplate\:\:initialize_shared_config\(\) has no return type specified\.$#'
-			identifier: missingType.return
-			count: 1
-			path: src/Blocks/Templates/SingleProductTemplate.php
-
-		-
-			message: '#^Method Automattic\\WooCommerce\\Blocks\\Templates\\SingleProductTemplate\:\:placeholder_image\(\) has no return type specified\.$#'
-			identifier: missingType.return
-			count: 1
-			path: src/Blocks/Templates/SingleProductTemplate.php
-
-		-
-			message: '#^Method Automattic\\WooCommerce\\Blocks\\Templates\\SingleProductTemplate\:\:prevent_cache\(\) has no return type specified\.$#'
-			identifier: missingType.return
-			count: 1
-			path: src/Blocks/Templates/SingleProductTemplate.php
-
 		-
 			message: '#^Method Automattic\\WooCommerce\\Blocks\\Templates\\SingleProductTemplate\:\:render_block_template\(\) has no return type specified\.$#'
 			identifier: missingType.return
@@ -78501,12 +78369,6 @@ parameters:
 			count: 2
 			path: src/Blocks/Templates/SingleProductTemplate.php

-		-
-			message: '#^Property WooCommerce\:\:\$cart \(WC_Cart\) in isset\(\) is not nullable\.$#'
-			identifier: isset.property
-			count: 1
-			path: src/Blocks/Templates/SingleProductTemplate.php
-
 		-
 			message: '#^Binary operation "\+" between mixed and 1 results in an error\.$#'
 			identifier: binaryOp.invalid
@@ -78813,6 +78675,12 @@ parameters:
 			count: 1
 			path: src/Blocks/Utils/BlockTemplateUtils.php

+		-
+			message: '#^Property WooCommerce\:\:\$cart \(WC_Cart\) in isset\(\) is not nullable\.$#'
+			identifier: isset.property
+			count: 1
+			path: src/Blocks/Utils/BlocksSharedState.php
+
 		-
 			message: '#^Cannot access offset ''value'' on mixed\.$#'
 			identifier: offsetAccess.nonOffsetAccessible
diff --git a/plugins/woocommerce/src/Blocks/BlockTypes/MiniCart.php b/plugins/woocommerce/src/Blocks/BlockTypes/MiniCart.php
index 4de9e491d4..afff696358 100644
--- a/plugins/woocommerce/src/Blocks/BlockTypes/MiniCart.php
+++ b/plugins/woocommerce/src/Blocks/BlockTypes/MiniCart.php
@@ -24,7 +24,6 @@ use Automattic\Block_Delimiter;
  */
 class MiniCart extends AbstractBlock {
 	use BlockHooksTrait;
-	use BlocksSharedState;

 	/**
 	 * Block name.
@@ -501,9 +500,10 @@ class MiniCart extends AbstractBlock {
 			wp_enqueue_script( $handle );
 		}

-		$this->register_cart_interactivity( 'I acknowledge that using private APIs means my theme or plugin will inevitably break in the next version of WooCommerce' );
-		$this->initialize_shared_config( 'I acknowledge that using private APIs means my theme or plugin will inevitably break in the next version of WooCommerce' );
-		$this->placeholder_image( 'I acknowledge that using private APIs means my theme or plugin will inevitably break in the next version of WooCommerce' );
+		$consent = 'I acknowledge that using private APIs means my theme or plugin will inevitably break in the next version of WooCommerce';
+		BlocksSharedState::load_cart_state( $consent );
+		BlocksSharedState::load_store_config( $consent );
+		BlocksSharedState::load_placeholder_image( $consent );

 		$cart = $this->get_cart_instance();

diff --git a/plugins/woocommerce/src/Blocks/BlockTypes/ProductButton.php b/plugins/woocommerce/src/Blocks/BlockTypes/ProductButton.php
index 15aea16f24..66d518b9c1 100644
--- a/plugins/woocommerce/src/Blocks/BlockTypes/ProductButton.php
+++ b/plugins/woocommerce/src/Blocks/BlockTypes/ProductButton.php
@@ -14,7 +14,6 @@ use Automattic\WooCommerce\Enums\ProductType;
  */
 class ProductButton extends AbstractBlock {
 	use EnableBlockJsonAssetsTrait;
-	use BlocksSharedState;

 	/**
 	 * Block name.
@@ -99,7 +98,7 @@ class ProductButton extends AbstractBlock {
 			return '';
 		}

-		$this->register_cart_interactivity( 'I acknowledge that using private APIs means my theme or plugin will inevitably break in the next version of WooCommerce' );
+		BlocksSharedState::load_cart_state( 'I acknowledge that using private APIs means my theme or plugin will inevitably break in the next version of WooCommerce' );

 		$number_of_items_in_cart  = $this->get_cart_item_quantities_by_product_id( $product->get_id() );
 		$is_product_purchasable   = $this->is_product_purchasable( $product );
diff --git a/plugins/woocommerce/src/Blocks/BlockTypes/ProductFilters.php b/plugins/woocommerce/src/Blocks/BlockTypes/ProductFilters.php
index 9fa813db28..36d1d6380b 100644
--- a/plugins/woocommerce/src/Blocks/BlockTypes/ProductFilters.php
+++ b/plugins/woocommerce/src/Blocks/BlockTypes/ProductFilters.php
@@ -11,7 +11,6 @@ use Automattic\WooCommerce\Internal\ProductFilters\Params;
  * ProductFilters class.
  */
 class ProductFilters extends AbstractBlock {
-	use BlocksSharedState;

 	/**
 	 * Block name.
@@ -40,7 +39,7 @@ class ProductFilters extends AbstractBlock {
 		global $pagenow;
 		parent::enqueue_data( $attributes );

-		$this->initialize_shared_config( 'I acknowledge that using private APIs means my theme or plugin will inevitably break in the next version of WooCommerce' );
+		BlocksSharedState::load_store_config( 'I acknowledge that using private APIs means my theme or plugin will inevitably break in the next version of WooCommerce' );

 		wp_interactivity_config(
 			$this->get_full_block_name(),
diff --git a/plugins/woocommerce/src/Blocks/BlockTypes/ProductPrice.php b/plugins/woocommerce/src/Blocks/BlockTypes/ProductPrice.php
index 35b62f4c17..5306deccb3 100644
--- a/plugins/woocommerce/src/Blocks/BlockTypes/ProductPrice.php
+++ b/plugins/woocommerce/src/Blocks/BlockTypes/ProductPrice.php
@@ -1,7 +1,6 @@
 <?php
 namespace Automattic\WooCommerce\Blocks\BlockTypes;

-use Automattic\WooCommerce\Blocks\Utils\BlocksSharedState;
 use Automattic\WooCommerce\Blocks\Utils\StyleAttributesUtils;
 use Automattic\WooCommerce\Enums\ProductType;

@@ -11,7 +10,6 @@ use Automattic\WooCommerce\Enums\ProductType;
 class ProductPrice extends AbstractBlock {

 	use EnableBlockJsonAssetsTrait;
-	use BlocksSharedState;


 	/**
diff --git a/plugins/woocommerce/src/Blocks/BlockTypes/ProductStockIndicator.php b/plugins/woocommerce/src/Blocks/BlockTypes/ProductStockIndicator.php
index ff2ff9fcec..57b58c663e 100644
--- a/plugins/woocommerce/src/Blocks/BlockTypes/ProductStockIndicator.php
+++ b/plugins/woocommerce/src/Blocks/BlockTypes/ProductStockIndicator.php
@@ -3,7 +3,6 @@ namespace Automattic\WooCommerce\Blocks\BlockTypes;

 use Automattic\WooCommerce\Blocks\Utils\StyleAttributesUtils;
 use Automattic\WooCommerce\Blocks\Utils\ProductAvailabilityUtils;
-use Automattic\WooCommerce\Blocks\Utils\BlocksSharedState;
 use Automattic\WooCommerce\Enums\ProductType;

 /**
@@ -12,7 +11,6 @@ use Automattic\WooCommerce\Enums\ProductType;
 class ProductStockIndicator extends AbstractBlock {

 	use EnableBlockJsonAssetsTrait;
-	use BlocksSharedState;

 	/**
 	 * Block name.
diff --git a/plugins/woocommerce/src/Blocks/Templates/SingleProductTemplate.php b/plugins/woocommerce/src/Blocks/Templates/SingleProductTemplate.php
index 2556aaf91e..be76b1dea2 100644
--- a/plugins/woocommerce/src/Blocks/Templates/SingleProductTemplate.php
+++ b/plugins/woocommerce/src/Blocks/Templates/SingleProductTemplate.php
@@ -2,9 +2,7 @@
 namespace Automattic\WooCommerce\Blocks\Templates;

 use Automattic\WooCommerce\Blocks\Templates\SingleProductTemplateCompatibility;
-use Automattic\WooCommerce\Blocks\Utils\BlocksSharedState;
 use Automattic\WooCommerce\Blocks\Utils\BlockTemplateUtils;
-use Automattic\WooCommerce\Blocks\Utils\ProductDataUtils;

 /**
  * SingleProductTemplate class.
@@ -12,7 +10,6 @@ use Automattic\WooCommerce\Blocks\Utils\ProductDataUtils;
  * @internal
  */
 class SingleProductTemplate extends AbstractTemplate {
-	use BlocksSharedState;

 	/**
 	 * The slug of the template.
diff --git a/plugins/woocommerce/src/Blocks/Utils/BlocksSharedState.php b/plugins/woocommerce/src/Blocks/Utils/BlocksSharedState.php
index a9e068ea2c..fd8d96b5a9 100644
--- a/plugins/woocommerce/src/Blocks/Utils/BlocksSharedState.php
+++ b/plugins/woocommerce/src/Blocks/Utils/BlocksSharedState.php
@@ -7,63 +7,61 @@ namespace Automattic\WooCommerce\Blocks\Utils;
 use InvalidArgumentException;
 use Automattic\WooCommerce\Blocks\Package;
 use Automattic\WooCommerce\Blocks\Domain\Services\Hydration;
-use Automattic\WooCommerce\StoreApi\StoreApi;
-use Automattic\WooCommerce\StoreApi\SchemaController;
-use Automattic\WooCommerce\StoreApi\Utilities\CartController;
-use Automattic\WooCommerce\StoreApi\Schemas\V1\CartSchema;

 /**
  * Manages the registration of interactivity config and state that is commonly shared by WooCommerce blocks.
- * Initialization only happens on the first call to initialize_shared_config.
- * Intended to be used as a singleton.
+ * Initialization only happens on the first call to load_store_config.
+ *
+ * This is a private API and may change in future versions.
  */
-trait BlocksSharedState {
+class BlocksSharedState {

 	/**
 	 * The consent statement for using private APIs of this class.
 	 *
 	 * @var string
 	 */
-	private static $consent_statement = 'I acknowledge that using private APIs means my theme or plugin will inevitably break in the next version of WooCommerce';
+	private static string $consent_statement = 'I acknowledge that using private APIs means my theme or plugin will inevitably break in the next version of WooCommerce';

 	/**
 	 * The namespace for the config.
 	 *
 	 * @var string
 	 */
-	private static $settings_namespace = 'woocommerce';
+	private static string $settings_namespace = 'woocommerce';

 	/**
 	 * Whether the core config has been registered.
 	 *
-	 * @var boolean
+	 * @var bool
 	 */
-	private static $core_config_registered = false;
+	private static bool $core_config_registered = false;

 	/**
 	 * Cart state.
 	 *
-	 * @var mixed
+	 * @var array|null
 	 */
-	private static $blocks_shared_cart_state;
+	private static ?array $blocks_shared_cart_state = null;

 	/**
-	 * Prevent caching on certain pages
+	 * Prevent caching on certain pages.
+	 *
+	 * @return void
 	 */
-	private static function prevent_cache() {
+	private static function prevent_cache(): void {
 		\WC_Cache_Helper::set_nocache_constants();
 		nocache_headers();
 	}

-
 	/**
 	 * Check that the consent statement was passed.
 	 *
-	 * @param string $consent_statement - The consent statement string.
+	 * @param string $consent_statement The consent statement string.
 	 * @return true
-	 * @throws \InvalidArgumentException - If the statement does not match the class consent statement string.
+	 * @throws InvalidArgumentException If the statement does not match.
 	 */
-	private static function check_consent( $consent_statement ) {
+	private static function check_consent( string $consent_statement ): bool {
 		if ( $consent_statement !== self::$consent_statement ) {
 			throw new InvalidArgumentException( 'This method cannot be called without consenting the API may change.' );
 		}
@@ -72,11 +70,13 @@ trait BlocksSharedState {
 	}

 	/**
-	 * Initialize the shared core config.
+	 * Load store config (currency, locale, core data) into interactivity config.
 	 *
-	 * @param string $consent_statement - The consent statement string.
+	 * @param string $consent_statement The consent statement string.
+	 * @return void
+	 * @throws InvalidArgumentException If consent statement doesn't match.
 	 */
-	public function initialize_shared_config( $consent_statement ) {
+	public static function load_store_config( string $consent_statement ): void {
 		self::check_consent( $consent_statement );

 		if ( self::$core_config_registered ) {
@@ -91,12 +91,13 @@ trait BlocksSharedState {
 	}

 	/**
-	 * Initialize interactivity state for cart that is needed by multiple blocks.
+	 * Load cart state into interactivity state.
 	 *
-	 * @param string $consent_statement - The consent statement string.
+	 * @param string $consent_statement The consent statement string.
 	 * @return void
+	 * @throws InvalidArgumentException If consent statement doesn't match.
 	 */
-	public function register_cart_interactivity( $consent_statement ) {
+	public static function load_cart_state( string $consent_statement ): void {
 		self::check_consent( $consent_statement );

 		if ( null === self::$blocks_shared_cart_state ) {
@@ -130,10 +131,10 @@ trait BlocksSharedState {
 	 *
 	 * @return array
 	 */
-	private static function get_core_data() {
-		return [
+	private static function get_core_data(): array {
+		return array(
 			'isBlockTheme' => wp_is_block_theme(),
-		];
+		);
 	}

 	/**
@@ -141,11 +142,11 @@ trait BlocksSharedState {
 	 *
 	 * @return array
 	 */
-	private static function get_currency_data() {
+	private static function get_currency_data(): array {
 		$currency = get_woocommerce_currency();

-		return [
-			'currency' => [
+		return array(
+			'currency' => array(
 				'code'              => $currency,
 				'precision'         => wc_get_price_decimals(),
 				'symbol'            => html_entity_decode( get_woocommerce_currency_symbol( $currency ) ),
@@ -153,8 +154,8 @@ trait BlocksSharedState {
 				'decimalSeparator'  => wc_get_price_decimal_separator(),
 				'thousandSeparator' => wc_get_price_thousand_separator(),
 				'priceFormat'       => html_entity_decode( get_woocommerce_price_format() ),
-			],
-		];
+			),
+		);
 	}

 	/**
@@ -162,24 +163,26 @@ trait BlocksSharedState {
 	 *
 	 * @return array
 	 */
-	private static function get_locale_data() {
+	private static function get_locale_data(): array {
 		global $wp_locale;

-		return [
-			'locale' => [
+		return array(
+			'locale' => array(
 				'siteLocale'    => get_locale(),
 				'userLocale'    => get_user_locale(),
 				'weekdaysShort' => array_values( $wp_locale->weekday_abbrev ),
-			],
-		];
+			),
+		);
 	}

 	/**
-	 * Add placeholder image.
+	 * Load placeholder image into interactivity config.
 	 *
-	 * @param string $consent_statement - The consent statement string.
+	 * @param string $consent_statement The consent statement string.
+	 * @return void
+	 * @throws InvalidArgumentException If consent statement doesn't match.
 	 */
-	public function placeholder_image( $consent_statement ) {
+	public static function load_placeholder_image( string $consent_statement ): void {
 		self::check_consent( $consent_statement );

 		wp_interactivity_config(