Commit 3e23bb1c1ab for woocommerce
commit 3e23bb1c1abaebcfe0985641bbef0f4b11b1fd1f
Author: Vladimir Reznichenko <kalessil@gmail.com>
Date: Thu Aug 13 14:27:13 2026 +0200
[Performance] Tune up caches invalidation during product save (#66966)
Some meta and term APIs are clearing the underlying caches, causing cache re-reads and increasing the number of SQL queries in unpredictable ways across WooCommerce core and extension workflows.
This PR fixes several verified cases in product data stores, primarily on the product save path — reducing per-save DB and cache pressure, which delays performance degradation under concurrent updates during BFCM/flash sale events (managed stock products saving is involved via wc_update_product_stock/wc_update_product_stock_status).
diff --git a/plugins/woocommerce/changelog/performance-tuneup-product-caches-invalidation b/plugins/woocommerce/changelog/performance-tuneup-product-caches-invalidation
new file mode 100644
index 00000000000..dc7e50cdf95
--- /dev/null
+++ b/plugins/woocommerce/changelog/performance-tuneup-product-caches-invalidation
@@ -0,0 +1,4 @@
+Significance: minor
+Type: performance
+
+Tune terms and post meta cache invalidation during product saving.
diff --git a/plugins/woocommerce/includes/data-stores/class-wc-data-store-wp.php b/plugins/woocommerce/includes/data-stores/class-wc-data-store-wp.php
index 657d7c2c1d6..82428a59f55 100644
--- a/plugins/woocommerce/includes/data-stores/class-wc-data-store-wp.php
+++ b/plugins/woocommerce/includes/data-stores/class-wc-data-store-wp.php
@@ -256,6 +256,7 @@ class WC_Data_Store_WP {
* @return bool True if updated/deleted.
*/
protected function update_or_delete_post_meta( $object, $meta_key, $meta_value ) {
+ // Performance note: see \WC_Product_Data_Store_CPT::update_or_delete_post_meta — keep both in sync.
if ( in_array( $meta_value, array( array(), '' ), true ) && ! in_array( $meta_key, $this->must_exist_meta_keys, true ) ) {
$updated = delete_post_meta( $object->get_id(), $meta_key );
} else {
diff --git a/plugins/woocommerce/includes/data-stores/class-wc-product-data-store-cpt.php b/plugins/woocommerce/includes/data-stores/class-wc-product-data-store-cpt.php
index c77b7bee4b0..c2ce1041f92 100644
--- a/plugins/woocommerce/includes/data-stores/class-wc-product-data-store-cpt.php
+++ b/plugins/woocommerce/includes/data-stores/class-wc-product-data-store-cpt.php
@@ -695,6 +695,35 @@ class WC_Product_Data_Store_CPT extends WC_Data_Store_WP implements WC_Object_Da
}
}
+ /**
+ * Update meta data in, or delete it from, the database.
+ *
+ * Avoids storing meta when it's either an empty string or empty array.
+ * Other empty values such as numeric 0 and null should still be stored.
+ * Data-stores can force meta to exist using `must_exist_meta_keys`.
+ *
+ * Note: WordPress `get_metadata` function returns an empty string when meta data does not exist.
+ *
+ * @since 11.2.0
+ *
+ * @param WC_Data $product The WP_Data object (product).
+ * @param string $meta_key Meta key to update.
+ * @param mixed $meta_value Value to save.
+ *
+ * @return bool
+ */
+ protected function update_or_delete_post_meta( $product, $meta_key, $meta_value ) {
+ // Performance note: overrides \WC_Data_Store_WP::update_or_delete_post_meta — adds metadata_exists() guard to skip DELETE when meta is absent.
+ $product_id = $product->get_id();
+ if ( in_array( $meta_value, array( array(), '' ), true ) && ! in_array( $meta_key, $this->must_exist_meta_keys, true ) ) {
+ $updated = metadata_exists( 'post', $product_id, $meta_key ) && delete_post_meta( $product_id, $meta_key );
+ } else {
+ $updated = update_post_meta( $product_id, $meta_key, $meta_value );
+ }
+
+ return (bool) $updated;
+ }
+
/**
* Helper method that updates all the post meta for a product based on it's settings in the WC_Product class.
*
@@ -1132,16 +1161,25 @@ class WC_Product_Data_Store_CPT extends WC_Data_Store_WP implements WC_Object_Da
/**
* Make sure we store the product type and version (to track data changes).
*
- * @param WC_Product $product Product object.
+ * @since 11.2.0 Skips wp_set_object_terms() when the stored product type term already matches to avoid unnecessary term cache invalidation.
* @since 3.0.0
+ *
+ * @param WC_Product $product Product object.
* @return void
*/
protected function update_version_and_type( &$product ) {
- $old_type = WC_Product_Factory::get_product_type( $product->get_id() );
- $new_type = $product->get_type();
+ $product_id = $product->get_id();
+ $old_type = \WC_Product_Factory::get_product_type( $product_id );
+ $new_type = $product->get_type();
+ $stored_type_terms = get_the_terms( $product_id, 'product_type' );
+ $stored_type_slug = ! empty( $stored_type_terms ) && is_array( $stored_type_terms ) ? $stored_type_terms[0]->slug : null;
+
+ // Skip wp_set_object_terms() when the stored term already matches — it always clears the term cache even on no-op writes.
+ if ( $stored_type_slug !== $new_type ) {
+ wp_set_object_terms( $product_id, $new_type, 'product_type' );
+ }
- wp_set_object_terms( $product->get_id(), $new_type, 'product_type' );
- update_post_meta( $product->get_id(), '_product_version', Constants::get_constant( 'WC_VERSION' ) );
+ update_post_meta( $product_id, '_product_version', Constants::get_constant( 'WC_VERSION' ) );
// Action for the transition.
if ( $old_type !== $new_type ) {
diff --git a/plugins/woocommerce/includes/data-stores/class-wc-product-grouped-data-store-cpt.php b/plugins/woocommerce/includes/data-stores/class-wc-product-grouped-data-store-cpt.php
index f21b9e6fa74..5295cd71ea3 100644
--- a/plugins/woocommerce/includes/data-stores/class-wc-product-grouped-data-store-cpt.php
+++ b/plugins/woocommerce/includes/data-stores/class-wc-product-grouped-data-store-cpt.php
@@ -86,9 +86,12 @@ class WC_Product_Grouped_Data_Store_CPT extends WC_Product_Data_Store_CPT implem
$child_prices = array_filter( $child_prices );
}
- delete_post_meta( $product_id, '_price' );
- delete_post_meta( $product_id, '_sale_price' );
- delete_post_meta( $product_id, '_regular_price' );
+ // Performance note: prefilter with metadata_exists, to avoid unnecessary meta cache invalidations and SQLs.
+ $price_metas = array_filter(
+ array( '_price', '_sale_price', '_regular_price' ),
+ static fn( $meta_key ) => metadata_exists( 'post', $product_id, $meta_key )
+ );
+ array_walk( $price_metas, static fn( $meta_key ) => delete_post_meta( $product_id, $meta_key ) );
if ( ! empty( $child_prices ) ) {
add_post_meta( $product_id, '_price', min( $child_prices ) );
diff --git a/plugins/woocommerce/includes/data-stores/class-wc-product-variable-data-store-cpt.php b/plugins/woocommerce/includes/data-stores/class-wc-product-variable-data-store-cpt.php
index 8a13ac2fa8e..d7d60ea21f0 100644
--- a/plugins/woocommerce/includes/data-stores/class-wc-product-variable-data-store-cpt.php
+++ b/plugins/woocommerce/includes/data-stores/class-wc-product-variable-data-store-cpt.php
@@ -937,9 +937,12 @@ class WC_Product_Variable_Data_Store_CPT extends WC_Product_Data_Store_CPT imple
$product_id = $product->get_id();
- delete_post_meta( $product_id, '_price' );
- delete_post_meta( $product_id, '_sale_price' );
- delete_post_meta( $product_id, '_regular_price' );
+ // Performance note: prefilter with metadata_exists, to avoid unnecessary meta cache invalidations and SQLs.
+ $price_metas = array_filter(
+ array( '_price', '_sale_price', '_regular_price' ),
+ static fn( $meta_key ) => metadata_exists( 'post', $product_id, $meta_key )
+ );
+ array_walk( $price_metas, static fn( $meta_key ) => delete_post_meta( $product_id, $meta_key ) );
if ( $prices ) {
sort( $prices, SORT_NUMERIC );
diff --git a/plugins/woocommerce/includes/data-stores/class-wc-product-variation-data-store-cpt.php b/plugins/woocommerce/includes/data-stores/class-wc-product-variation-data-store-cpt.php
index 731f2d0a242..f9ec70e6246 100644
--- a/plugins/woocommerce/includes/data-stores/class-wc-product-variation-data-store-cpt.php
+++ b/plugins/woocommerce/includes/data-stores/class-wc-product-variation-data-store-cpt.php
@@ -345,12 +345,21 @@ class WC_Product_Variation_Data_Store_CPT extends WC_Product_Data_Store_CPT impl
/**
* Make sure we store the product version (to track data changes).
*
- * @param WC_Product $product Product object.
+ * @since 11.2.0 Skips wp_set_object_terms() when the product type is unchanged to avoid unnecessary term cache invalidation.
* @since 3.0.0
+ *
+ * @param WC_Product $product Product object.
+ * @return void
*/
protected function update_version_and_type( &$product ) {
- wp_set_object_terms( $product->get_id(), '', 'product_type' );
- update_post_meta( $product->get_id(), '_product_version', Constants::get_constant( 'WC_VERSION' ) );
+ $product_id = $product->get_id();
+ // Skip wp_set_object_terms() when the type is unchanged — it always clears the term cache even on no-op writes.
+ $stored_type_terms = get_the_terms( $product_id, 'product_type' );
+ if ( ! empty( $stored_type_terms ) ) {
+ wp_set_object_terms( $product_id, '', 'product_type' );
+ }
+
+ update_post_meta( $product_id, '_product_version', Constants::get_constant( 'WC_VERSION' ) );
}
/**
diff --git a/plugins/woocommerce/src/Internal/Utilities/ProductUtil.php b/plugins/woocommerce/src/Internal/Utilities/ProductUtil.php
index c5d5b8633f7..2ec6f40fcb3 100644
--- a/plugins/woocommerce/src/Internal/Utilities/ProductUtil.php
+++ b/plugins/woocommerce/src/Internal/Utilities/ProductUtil.php
@@ -54,6 +54,7 @@ class ProductUtil {
// Kept for compatibility, WooCommerce core doesn't use product transient versions anymore.
\WC_Cache_Helper::get_transient_version( 'product', true );
+ \WC_Cache_Helper::get_transient_version( 'product_query', true );
foreach ( $product_ids as $product_id ) {
/**
diff --git a/plugins/woocommerce/tests/php/includes/data-stores/class-wc-data-store-wp-test.php b/plugins/woocommerce/tests/php/includes/data-stores/class-wc-data-store-wp-test.php
new file mode 100644
index 00000000000..679b1e115b1
--- /dev/null
+++ b/plugins/woocommerce/tests/php/includes/data-stores/class-wc-data-store-wp-test.php
@@ -0,0 +1,50 @@
+<?php declare( strict_types = 1 );
+
+/**
+ * Class WC_Data_Store_WP_Test
+ */
+final class WC_Data_Store_WP_Test extends WC_Unit_Test_Case {
+
+ /**
+ * @return array
+ */
+ public function provider_update_or_delete_post_meta(): array {
+ return array(
+ 'empty string — key absent' => array( static fn() => null, '', false, '' ),
+ 'empty string — key present' => array( static fn( $id ) => add_post_meta( $id, '_sku', 'old' ), '', true, '' ),
+ 'empty array — key absent' => array( static fn() => null, array(), false, '' ),
+ 'empty array — key present' => array( static fn( $id ) => add_post_meta( $id, '_sku', 'old' ), array(), true, '' ),
+ 'non-empty — key absent' => array( static fn() => null, 'new-sku', true, 'new-sku' ),
+ 'non-empty — key present' => array( static fn( $id ) => add_post_meta( $id, '_sku', 'old' ), 'new-sku', true, 'new-sku' ),
+ );
+ }
+
+ /**
+ * @dataProvider provider_update_or_delete_post_meta
+ * @testdox update_or_delete_post_meta writes, deletes, or skips based on value and key presence.
+ *
+ * @param Closure $setup Receives the product ID; sets up pre-existing meta if needed.
+ * @param mixed $meta_value Value passed to update_or_delete_post_meta.
+ * @param bool $expected_result Expected boolean return value.
+ * @param mixed $expected_stored Expected get_post_meta result after the call.
+ */
+ public function test_update_or_delete_post_meta( Closure $setup, $meta_value, bool $expected_result, $expected_stored ): void {
+ $store = new class() extends WC_Product_Data_Store_CPT {
+ public function update_or_delete_post_meta( $product, $meta_key, $meta_value ): bool { // phpcs:ignore Generic.CodeAnalysis.UselessOverridingMethod.Found, Squiz.Commenting.FunctionComment.Missing
+ return parent::update_or_delete_post_meta( $product, $meta_key, $meta_value );
+ }
+ };
+
+ $product = new WC_Product();
+ $product->save();
+ $product_id = $product->get_id();
+ $setup( $product_id );
+
+ $result = $store->update_or_delete_post_meta( $product, '_sku', $meta_value );
+
+ $this->assertSame( $expected_result, $result );
+ $this->assertSame( $expected_stored, get_post_meta( $product_id, '_sku', true ) );
+
+ $product->delete();
+ }
+}
diff --git a/plugins/woocommerce/tests/php/includes/data-stores/class-wc-product-data-store-cpt-test.php b/plugins/woocommerce/tests/php/includes/data-stores/class-wc-product-data-store-cpt-test.php
index 039ed53ba35..8a76b6b050d 100644
--- a/plugins/woocommerce/tests/php/includes/data-stores/class-wc-product-data-store-cpt-test.php
+++ b/plugins/woocommerce/tests/php/includes/data-stores/class-wc-product-data-store-cpt-test.php
@@ -613,6 +613,108 @@ class WC_Product_Data_Store_CPT_Test extends WC_Unit_Test_Case {
$this->assertSame( '30.000000', get_post_meta( $product_id, '_stock', true ) );
}
+ /**
+ * @testdox update_version_and_type sets the product_type term when the type changes, skips it when unchanged, and writes _product_version when stale.
+ */
+ public function test_update_version_and_type_fires_when_type_changes(): void {
+ $store = new class() extends WC_Product_Data_Store_CPT {
+ public function update_version_and_type( &$product ): void { // phpcs:ignore Generic.CodeAnalysis.UselessOverridingMethod.Found, Squiz.Commenting.FunctionComment.Missing
+ parent::update_version_and_type( $product );
+ }
+ };
+
+ $product = new WC_Product_Simple();
+ $product->save();
+ $product_id = $product->get_id();
+ $external_product = new WC_Product_External( $product_id );
+
+ update_post_meta( $product_id, '_product_version', '1.0.0-stale' );
+
+ $store->update_version_and_type( $external_product );
+
+ $this->assertSame( 'external', get_the_terms( $product_id, 'product_type' )[0]->slug );
+ $this->assertSame( WC_VERSION, get_post_meta( $product_id, '_product_version', true ) );
+
+ // Type is now unchanged — calling again must not alter the term or the version.
+ $store->update_version_and_type( $external_product );
+
+ $this->assertSame( 'external', get_the_terms( $product_id, 'product_type' )[0]->slug );
+
+ $product->delete();
+ }
+
+ /**
+ * @testdox update_version_and_type uses the filtered product type as $old_type, not the stored term.
+ */
+ public function test_update_version_and_type_respects_product_type_query_filter(): void {
+ $store = new class() extends WC_Product_Data_Store_CPT {
+ public function update_version_and_type( &$product ): void { // phpcs:ignore Generic.CodeAnalysis.UselessOverridingMethod.Found, Squiz.Commenting.FunctionComment.Missing
+ parent::update_version_and_type( $product );
+ }
+ };
+
+ // Mimics WC_Product_Booking: stored as 'variable' term, but filter overrides type to 'booking' at runtime.
+ $product = new WC_Product_Variable();
+ $product->save();
+ $product_id = $product->get_id();
+
+ $external = new WC_Product_External( $product_id );
+ $filter = static fn ( $override, $id ) => $id === $product_id ? 'external' : false;
+ add_filter( 'woocommerce_product_type_query', $filter, 10, 2 );
+
+ $fired_args = null;
+ $tracker = function ( $p, $from, $to ) use ( &$fired_args ) {
+ $fired_args = array( $from, $to );
+ };
+ add_action( 'woocommerce_product_type_changed', $tracker, 10, 3 );
+
+ try {
+ $store->update_version_and_type( $external );
+ } finally {
+ remove_filter( 'woocommerce_product_type_query', $filter, 10 );
+ remove_action( 'woocommerce_product_type_changed', $tracker, 10 );
+ }
+
+ // Filter overrides old type to 'external', matching new type — no transition expected.
+ $this->assertNull( $fired_args );
+
+ $product->delete( true );
+ }
+
+ /**
+ * @testdox update_version_and_type corrects a stale stored term when a filter makes $old_type match $new_type but the DB term differs.
+ */
+ public function test_update_version_and_type_corrects_stale_term_under_filter(): void {
+ $store = new class() extends WC_Product_Data_Store_CPT {
+ public function update_version_and_type( &$product ): void { // phpcs:ignore Generic.CodeAnalysis.UselessOverridingMethod.Found, Squiz.Commenting.FunctionComment.Missing
+ parent::update_version_and_type( $product );
+ }
+ };
+
+ // Create a variable product — stored term is 'variable'.
+ $product = new WC_Product_Variable();
+ $product->save();
+ $product_id = $product->get_id();
+ $this->assertSame( 'variable', get_the_terms( $product_id, 'product_type' )[0]->slug );
+
+ // Filter makes old_type match new_type ('external'), but stored term is still 'variable' — must be corrected.
+ $external = new WC_Product_External( $product_id );
+ $filter = static fn ( $override, $id ) => $id === $product_id ? 'external' : false;
+ add_filter( 'woocommerce_product_type_query', $filter, 10, 2 );
+
+ try {
+ $store->update_version_and_type( $external );
+ } finally {
+ remove_filter( 'woocommerce_product_type_query', $filter, 10 );
+ }
+
+ // The stored term must now be 'external', not the stale 'variable'.
+ $terms = get_the_terms( $product_id, 'product_type' );
+ $this->assertSame( 'external', $terms[0]->slug, 'Stored term should be corrected to match $new_type even when the filter masks the mismatch.' );
+
+ $product->delete( true );
+ }
+
/**
* Test update_product_sales updates on the meta-entry.
*/
diff --git a/plugins/woocommerce/tests/php/includes/data-stores/class-wc-product-grouped-data-store-cpt-test.php b/plugins/woocommerce/tests/php/includes/data-stores/class-wc-product-grouped-data-store-cpt-test.php
new file mode 100644
index 00000000000..7e910a686ac
--- /dev/null
+++ b/plugins/woocommerce/tests/php/includes/data-stores/class-wc-product-grouped-data-store-cpt-test.php
@@ -0,0 +1,48 @@
+<?php declare( strict_types = 1 );
+
+/**
+ * Class WC_Product_Grouped_Data_Store_CPT_Test
+ */
+final class WC_Product_Grouped_Data_Store_CPT_Test extends WC_Unit_Test_Case {
+
+ /**
+ * @testdox sync_price updates parent price meta from children and re-populates it when absent.
+ */
+ public function test_sync_price_updates_and_repopulates_price_meta(): void {
+ $child1 = new WC_Product_Simple();
+ $child1->set_regular_price( '3.00' );
+ $child1->set_price( '3.00' );
+ $child1->save();
+
+ $child2 = new WC_Product_Simple();
+ $child2->set_regular_price( '7.00' );
+ $child2->set_price( '7.00' );
+ $child2->save();
+
+ $grouped = new WC_Product_Grouped();
+ $grouped->set_children( array( $child1->get_id(), $child2->get_id() ) );
+ $grouped->save();
+ $grouped_id = $grouped->get_id();
+
+ $this->assertSame( array( '3.00', '7.00' ), get_post_meta( $grouped_id, '_price', false ) );
+
+ $child2->set_price( '9.00' );
+ $child2->set_regular_price( '9.00' );
+ $child2->save();
+
+ ( new WC_Product_Grouped_Data_Store_CPT() )->sync_price( $grouped );
+
+ $this->assertSame( array( '3.00', '9.00' ), get_post_meta( $grouped_id, '_price', false ) );
+
+ delete_post_meta( $grouped_id, '_price' );
+ $this->assertFalse( metadata_exists( 'post', $grouped_id, '_price' ) );
+
+ ( new WC_Product_Grouped_Data_Store_CPT() )->sync_price( $grouped );
+
+ $this->assertSame( array( '3.00', '9.00' ), get_post_meta( $grouped_id, '_price', false ) );
+
+ $child1->delete();
+ $child2->delete();
+ $grouped->delete();
+ }
+}
diff --git a/plugins/woocommerce/tests/php/includes/data-stores/class-wc-product-variable-data-store-cpt-test.php b/plugins/woocommerce/tests/php/includes/data-stores/class-wc-product-variable-data-store-cpt-test.php
index 48107c4f789..0fd0d8a4fce 100644
--- a/plugins/woocommerce/tests/php/includes/data-stores/class-wc-product-variable-data-store-cpt-test.php
+++ b/plugins/woocommerce/tests/php/includes/data-stores/class-wc-product-variable-data-store-cpt-test.php
@@ -1756,6 +1756,23 @@ class WC_Product_Variable_Data_Store_CPT_Test extends WC_Unit_Test_Case {
$product->delete();
}
+ /**
+ * @testdox sync_price correctly writes child prices to the parent when no price meta existed before (CREATE path).
+ */
+ public function test_sync_price_writes_prices_when_parent_has_no_prior_price_meta(): void {
+ $product = WC_Helper_Product::create_variation_product();
+ $product_id = $product->get_id();
+
+ delete_post_meta( $product_id, '_price' );
+ $this->assertFalse( metadata_exists( 'post', $product_id, '_price' ) );
+
+ ( new WC_Product_Variable_Data_Store_CPT() )->sync_price( $product );
+
+ $this->assertTrue( metadata_exists( 'post', $product_id, '_price' ) );
+
+ $product->delete();
+ }
+
/**
* @dataProvider provider_lookup_table_generating
* @testdox sync_stock_status sets instock when at least one child is in stock.
diff --git a/plugins/woocommerce/tests/php/includes/data-stores/class-wc-product-variations-data-store-cpt-test.php b/plugins/woocommerce/tests/php/includes/data-stores/class-wc-product-variations-data-store-cpt-test.php
index d1fdb94a2dc..5df7cb2cdbd 100644
--- a/plugins/woocommerce/tests/php/includes/data-stores/class-wc-product-variations-data-store-cpt-test.php
+++ b/plugins/woocommerce/tests/php/includes/data-stores/class-wc-product-variations-data-store-cpt-test.php
@@ -295,6 +295,37 @@ class WC_Product_Variation_Data_Store_CPT_Test extends WC_Unit_Test_Case {
$this->assertEquals( $flag_value ? 'yes' : '', get_post_meta( $product->get_id(), '_cogs_value_is_additive', true ) );
}
+ /**
+ * @testdox update_version_and_type clears any product_type term when present, skips wp_set_object_terms() when absent, and always writes _product_version.
+ */
+ public function test_update_version_and_type_clears_type_term_when_present_skips_when_absent(): void {
+ $store = new class() extends WC_Product_Variation_Data_Store_CPT {
+ public function update_version_and_type( &$product ): void { // phpcs:ignore Generic.CodeAnalysis.UselessOverridingMethod.Found, Squiz.Commenting.FunctionComment.Missing
+ parent::update_version_and_type( $product );
+ }
+ };
+
+ $variation = $this->get_variation();
+ $variation_id = $variation->get_id();
+
+ // Variations must not carry a product_type term — gate must skip wp_set_object_terms().
+ $this->assertEmpty( get_the_terms( $variation_id, 'product_type' ) );
+ update_post_meta( $variation_id, '_product_version', '1.0.0-stale' );
+
+ $store->update_version_and_type( $variation );
+
+ $this->assertEmpty( get_the_terms( $variation_id, 'product_type' ) );
+ $this->assertSame( WC_VERSION, get_post_meta( $variation_id, '_product_version', true ) );
+
+ // If a product_type term exists (e.g. left over from a type conversion), the gate must clear it.
+ wp_set_object_terms( $variation_id, 'simple', 'product_type' );
+ $this->assertNotEmpty( get_the_terms( $variation_id, 'product_type' ) );
+
+ $store->update_version_and_type( $variation );
+
+ $this->assertEmpty( get_the_terms( $variation_id, 'product_type' ) );
+ }
+
/**
* Create a variable product and return one of its variations.
*
diff --git a/plugins/woocommerce/tests/php/src/Internal/Utilities/ProductUtilTest.php b/plugins/woocommerce/tests/php/src/Internal/Utilities/ProductUtilTest.php
index c1f838aeebd..d057c41188d 100644
--- a/plugins/woocommerce/tests/php/src/Internal/Utilities/ProductUtilTest.php
+++ b/plugins/woocommerce/tests/php/src/Internal/Utilities/ProductUtilTest.php
@@ -89,7 +89,9 @@ class ProductUtilTest extends \WC_Unit_Test_Case {
$deleted_ids[] = (int) $product_id;
};
- set_transient( 'wc_products_onsale', 'foobar' );
+ set_transient( 'wc_products_onsale', 'before' );
+ set_transient( 'product-transient-version', 'before' );
+ set_transient( 'product_query-transient-version', 'before' );
add_action( 'woocommerce_delete_product_transients', $track_hook );
try {
wc_get_container()->get( ProductUtil::class )->delete_product_transients_for_products( $product_ids );
@@ -97,8 +99,10 @@ class ProductUtilTest extends \WC_Unit_Test_Case {
remove_action( 'woocommerce_delete_product_transients', $track_hook );
}
- $this->assertFalse( get_transient( 'wc_products_onsale' ) );
$this->assertSame( array( 0, 123, 456 ), $deleted_ids );
+ $this->assertNotSame( 'before', get_transient( 'wc_products_onsale' ) );
+ $this->assertNotSame( 'before', get_transient( 'product-transient-version' ) );
+ $this->assertNotSame( 'before', get_transient( 'product_query-transient-version' ) );
}
/**