Commit 64d3ec832ce for woocommerce
commit 64d3ec832cec31d1b5c64528b9dc6ba8072e56ec
Author: Chris Huber <chubes@extrachill.com>
Date: Thu Jul 9 13:24:07 2026 -0400
Fix deferred product transient shutdown order (#66168)
* Fix deferred product transient shutdown order
* Match deferred transient shutdown removal priority
* Add changefile(s) from automation for the following project(s): woocommerce
* Add transient deferrer shutdown ordering coverage
* Add changefile(s) from automation for the following project(s): woocommerce
* Update tests
---------
Co-authored-by: Jorge Torres <jorge.torres@automattic.com>
diff --git a/plugins/woocommerce/changelog/66168-fix-65686-transient-deferrer-shutdown-order b/plugins/woocommerce/changelog/66168-fix-65686-transient-deferrer-shutdown-order
new file mode 100644
index 00000000000..8655d9d50a4
--- /dev/null
+++ b/plugins/woocommerce/changelog/66168-fix-65686-transient-deferrer-shutdown-order
@@ -0,0 +1,4 @@
+Significance: patch
+Type: fix
+
+Fix deferred product transient shutdown ordering before parent product sync.
diff --git a/plugins/woocommerce/src/Internal/Caches/ProductTransientsDeferrer.php b/plugins/woocommerce/src/Internal/Caches/ProductTransientsDeferrer.php
index 474f6333c05..fe8840c225e 100644
--- a/plugins/woocommerce/src/Internal/Caches/ProductTransientsDeferrer.php
+++ b/plugins/woocommerce/src/Internal/Caches/ProductTransientsDeferrer.php
@@ -13,6 +13,14 @@ use Automattic\WooCommerce\Internal\Utilities\ProductUtil;
*/
class ProductTransientsDeferrer {
+ /**
+ * Priority for the shutdown safety-net hook.
+ *
+ * This must run before WC_Post_Data::do_deferred_product_sync() at priority 10
+ * so stale product transients are cleared before parent product sync reads them.
+ */
+ private const SHUTDOWN_HOOK_PRIORITY = 0;
+
/**
* The product utility instance.
*
@@ -54,7 +62,7 @@ class ProductTransientsDeferrer {
public function start_deferring(): void {
++$this->deferral_level;
if ( 1 === $this->deferral_level ) {
- add_action( 'shutdown', array( $this, 'handle_shutdown' ) );
+ add_action( 'shutdown', array( $this, 'handle_shutdown' ), self::SHUTDOWN_HOOK_PRIORITY );
}
}
@@ -72,7 +80,7 @@ class ProductTransientsDeferrer {
--$this->deferral_level;
if ( 0 === $this->deferral_level ) {
- remove_action( 'shutdown', array( $this, 'handle_shutdown' ) );
+ remove_action( 'shutdown', array( $this, 'handle_shutdown' ), self::SHUTDOWN_HOOK_PRIORITY );
$this->flush();
}
}
diff --git a/plugins/woocommerce/tests/php/src/Internal/Caches/ProductTransientsDeferrerTest.php b/plugins/woocommerce/tests/php/src/Internal/Caches/ProductTransientsDeferrerTest.php
index 61fcc305253..e4ceaa10be9 100644
--- a/plugins/woocommerce/tests/php/src/Internal/Caches/ProductTransientsDeferrerTest.php
+++ b/plugins/woocommerce/tests/php/src/Internal/Caches/ProductTransientsDeferrerTest.php
@@ -11,6 +11,29 @@ use Automattic\WooCommerce\Internal\Caches\ProductTransientsDeferrer;
*/
class ProductTransientsDeferrerTest extends \WC_Unit_Test_Case {
+ /**
+ * @testdox Shutdown fallback flushes product transients before deferred parent product sync.
+ */
+ public function test_shutdown_fallback_runs_before_deferred_product_sync() {
+ $deferrer = wc_get_container()->get( ProductTransientsDeferrer::class );
+
+ try {
+ $deferrer->start_deferring();
+
+ $sync_priority = has_action( 'shutdown', array( 'WC_Post_Data', 'do_deferred_product_sync' ) );
+ $priority = has_action( 'shutdown', array( $deferrer, 'handle_shutdown' ) );
+
+ $this->assertNotFalse( $priority );
+ $this->assertNotFalse( $sync_priority );
+ $this->assertLessThan( $sync_priority, $priority );
+
+ $deferrer->stop_deferring();
+ $this->assertFalse( has_action( 'shutdown', array( $deferrer, 'handle_shutdown' ) ) );
+ } finally {
+ $deferrer->stop_deferring();
+ }
+ }
+
/**
* @testdox Product transient deferral coalesces repeated deletions until the outermost deferral ends.
*/