Commit 3641f2bbda for woocommerce
commit 3641f2bbdaa13257bdaf2a9be6dc67f2fc6a6f36
Author: Sam Seay <samueljseay@gmail.com>
Date: Thu Dec 11 16:30:17 2025 +1300
Hydrate cartItem state server side to avoid Preact warning (#62155)
diff --git a/plugins/woocommerce/changelog/62155-dev-hydrate-mini-cart-cart-item-state b/plugins/woocommerce/changelog/62155-dev-hydrate-mini-cart-cart-item-state
new file mode 100644
index 0000000000..c9e97e99ed
--- /dev/null
+++ b/plugins/woocommerce/changelog/62155-dev-hydrate-mini-cart-cart-item-state
@@ -0,0 +1,4 @@
+Significance: minor
+Type: fix
+
+Fix a bug where Preact warns in development about inconsistent rendering between SSR content and client.
\ No newline at end of file
diff --git a/plugins/woocommerce/phpstan-baseline.neon b/plugins/woocommerce/phpstan-baseline.neon
index a8e4010e42..40c1b79a54 100644
--- a/plugins/woocommerce/phpstan-baseline.neon
+++ b/plugins/woocommerce/phpstan-baseline.neon
@@ -29700,6 +29700,12 @@ parameters:
count: 1
path: includes/data-stores/class-wc-product-data-store-cpt.php
+ -
+ message: '#^Call to function is_callable\(\) with ''_prime_post_caches'' will always evaluate to true\.$#'
+ identifier: function.alreadyNarrowedType
+ count: 1
+ path: includes/data-stores/class-wc-product-grouped-data-store-cpt.php
+
-
message: '#^Method WC_Product\:\:get_children\(\) invoked with 1 parameter, 0 required\.$#'
identifier: arguments.count
@@ -71247,12 +71253,6 @@ parameters:
count: 1
path: src/Blocks/AssetsController.php
- -
- message: '#^Constant WOOCOMMERCE_VERSION not found\.$#'
- identifier: constant.notFound
- count: 2
- path: src/Blocks/AssetsController.php
-
-
message: '#^Method Automattic\\WooCommerce\\Blocks\\AssetsController\:\:enqueue_wc_entities\(\) has no return type specified\.$#'
identifier: missingType.return
@@ -73654,19 +73654,19 @@ parameters:
path: src/Blocks/BlockTypes/MiniCartItemsBlock.php
-
- message: '#^Method Automattic\\WooCommerce\\Blocks\\BlockTypes\\MiniCartProductsTableBlock\:\:render_experimental_iapi_markup\(\) should return string but returns string\|false\.$#'
+ message: '#^Method Automattic\\WooCommerce\\Blocks\\BlockTypes\\MiniCartProductsTableBlock\:\:render\(\) should return string but returns string\|false\.$#'
identifier: return.type
count: 1
path: src/Blocks/BlockTypes/MiniCartProductsTableBlock.php
-
- message: '#^Method Automattic\\WooCommerce\\Blocks\\BlockTypes\\MiniCartProductsTableBlock\:\:render_experimental_iapi_product_details_item_markup\(\) should return string but returns string\|false\.$#'
+ message: '#^Method Automattic\\WooCommerce\\Blocks\\BlockTypes\\MiniCartProductsTableBlock\:\:render_product_details_item_markup\(\) should return string but returns string\|false\.$#'
identifier: return.type
count: 1
path: src/Blocks/BlockTypes/MiniCartProductsTableBlock.php
-
- message: '#^Method Automattic\\WooCommerce\\Blocks\\BlockTypes\\MiniCartProductsTableBlock\:\:render_experimental_iapi_product_details_markup\(\) should return string but returns string\|false\.$#'
+ message: '#^Method Automattic\\WooCommerce\\Blocks\\BlockTypes\\MiniCartProductsTableBlock\:\:render_product_details_markup\(\) should return string but returns string\|false\.$#'
identifier: return.type
count: 1
path: src/Blocks/BlockTypes/MiniCartProductsTableBlock.php
@@ -73677,12 +73677,6 @@ parameters:
count: 1
path: src/Blocks/BlockTypes/MiniCartProductsTableBlock.php
- -
- message: '#^Parameter \$block of method Automattic\\WooCommerce\\Blocks\\BlockTypes\\MiniCartProductsTableBlock\:\:render_experimental_iapi_markup\(\) has invalid type Automattic\\WooCommerce\\Blocks\\BlockTypes\\WP_Block\.$#'
- identifier: class.notFound
- count: 1
- path: src/Blocks/BlockTypes/MiniCartProductsTableBlock.php
-
-
message: '#^Method Automattic\\WooCommerce\\Blocks\\BlockTypes\\MiniCartShoppingButtonBlock\:\:render_experimental_iapi_markup\(\) should return string but returns string\|false\.$#'
identifier: return.type
diff --git a/plugins/woocommerce/src/Blocks/BlockTypes/MiniCartProductsTableBlock.php b/plugins/woocommerce/src/Blocks/BlockTypes/MiniCartProductsTableBlock.php
index 20d821dd37..e1a1405989 100644
--- a/plugins/woocommerce/src/Blocks/BlockTypes/MiniCartProductsTableBlock.php
+++ b/plugins/woocommerce/src/Blocks/BlockTypes/MiniCartProductsTableBlock.php
@@ -1,8 +1,6 @@
<?php
namespace Automattic\WooCommerce\Blocks\BlockTypes;
-use Automattic\WooCommerce\Admin\Features\Features;
-
/**
* MiniCartProductsTableBlock class.
*/
@@ -24,28 +22,31 @@ class MiniCartProductsTableBlock extends AbstractInnerBlock {
* @return string Rendered block type output.
*/
protected function render( $attributes, $content, $block ) {
- if ( Features::is_enabled( 'experimental-iapi-mini-cart' ) ) {
- return $this->render_experimental_iapi_markup( $attributes, $content, $block );
- }
-
- return $content;
- }
-
- /**
- * Render experimental iAPI block markup.
- *
- * @param array $attributes Block attributes.
- * @param string $content Block content.
- * @param WP_Block $block Block instance.
- * @return string Rendered block type output.
- */
- protected function render_experimental_iapi_markup( $attributes, $content, $block ) {
$screen_reader_text = __( 'Products in cart', 'woocommerce' );
$remove_item_label = __( 'Remove item', 'woocommerce' );
$head_product_label = __( 'Product', 'woocommerce' );
$head_details_label = __( 'Details', 'woocommerce' );
$head_total_label = __( 'Total', 'woocommerce' );
+ wp_interactivity_state(
+ $this->get_full_block_name(),
+ array(
+ 'cartItem' => function () {
+ $context = wp_interactivity_get_context( 'woocommerce' );
+ $cart_state = wp_interactivity_state( 'woocommerce' );
+ $item_key = $context['cartItem']['key'];
+
+ foreach ( $cart_state['cart']['items'] as $item ) {
+ if ( $item['key'] === $item_key ) {
+ return $item;
+ }
+ }
+
+ return null;
+ },
+ )
+ );
+
// translators: %s is the name of the product in cart.
$reduce_quantity_label = __( 'Reduce quantity of %s', 'woocommerce' );
@@ -181,8 +182,8 @@ class MiniCartProductsTableBlock extends AbstractInnerBlock {
<div data-wp-watch="callbacks.itemShortDescription" >
<div class="wc-block-components-product-metadata__description"></div>
</div>
- <?php echo $this->render_experimental_iapi_product_details_markup( 'item_data' ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>
- <?php echo $this->render_experimental_iapi_product_details_markup( 'variation' ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>
+ <?php echo $this->render_product_details_markup( 'item_data' ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>
+ <?php echo $this->render_product_details_markup( 'variation' ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>
</div>
<div class="wc-block-cart-item__quantity">
<div class="wc-block-components-quantity-selector" data-wp-bind--hidden="state.cartItem.sold_individually">
@@ -263,7 +264,7 @@ class MiniCartProductsTableBlock extends AbstractInnerBlock {
* @param string $property The property to render in the product details markup.
* @return string Rendered product details output.
*/
- protected function render_experimental_iapi_product_details_markup( $property ) {
+ protected function render_product_details_markup( $property ) {
$context = array( 'dataProperty' => $property );
// If the property is item_data, so not a variation, we need to skip the text directive.
@@ -276,7 +277,7 @@ class MiniCartProductsTableBlock extends AbstractInnerBlock {
class="wc-block-components-product-details"
data-wp-bind--hidden="state.shouldHideSingleProductDetails"
>
- <?php echo $this->render_experimental_iapi_product_details_item_markup( 'div', $is_item_data ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>
+ <?php echo $this->render_product_details_item_markup( 'div', $is_item_data ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>
</div>
<ul
<?php echo wp_interactivity_data_wp_context( $context ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>
@@ -287,7 +288,7 @@ class MiniCartProductsTableBlock extends AbstractInnerBlock {
data-wp-each--item-data="state.cartItem.<?php echo esc_attr( $property ); ?>"
data-wp-each-key="state.cartItemDataKey"
>
- <?php echo $this->render_experimental_iapi_product_details_item_markup( 'li', $is_item_data ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>
+ <?php echo $this->render_product_details_item_markup( 'li', $is_item_data ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>
</template>
</ul>
<?php
@@ -301,7 +302,7 @@ class MiniCartProductsTableBlock extends AbstractInnerBlock {
* @param bool $is_item_data Whether the item is of item_data type.
* @return string Rendered product detail item output based on item type.
*/
- private function render_experimental_iapi_product_details_item_markup( $tag_name, $is_item_data = false ) {
+ private function render_product_details_item_markup( $tag_name, $is_item_data = false ) {
ob_start();
?>
<<?php echo tag_escape( $tag_name ); ?>