Commit d888c595947 for woocommerce
commit d888c5959473fbd58399343ddd9d7c40ad1a8093
Author: Adrian Moldovan <3854374+adimoldovan@users.noreply.github.com>
Date: Mon Oct 12 19:33:23 2026 +0200
Stop untrash from firing the order update hook with HPOS (#69303)
diff --git a/plugins/woocommerce/changelog/fix-untrash-order-extra-update-hook b/plugins/woocommerce/changelog/fix-untrash-order-extra-update-hook
new file mode 100644
index 00000000000..a223d7ae1ab
--- /dev/null
+++ b/plugins/woocommerce/changelog/fix-untrash-order-extra-update-hook
@@ -0,0 +1,4 @@
+Significance: patch
+Type: fix
+
+Restoring an order from the trash no longer sends an extra "order updated" webhook or event when HPOS is on.
diff --git a/plugins/woocommerce/src/Internal/DataStores/Orders/OrdersTableDataStore.php b/plugins/woocommerce/src/Internal/DataStores/Orders/OrdersTableDataStore.php
index 1834b8d0a7e..f53382e86c8 100644
--- a/plugins/woocommerce/src/Internal/DataStores/Orders/OrdersTableDataStore.php
+++ b/plugins/woocommerce/src/Internal/DataStores/Orders/OrdersTableDataStore.php
@@ -120,6 +120,9 @@ class OrdersTableDataStore extends \Abstract_WC_Order_Data_Store_CPT implements
*/
protected $ephemeral_meta_keys = array(
EditLock::META_KEY_NAME,
+ '_wp_trash_meta_status',
+ '_wp_trash_meta_time',
+ '_wp_trash_meta_comments_status',
);
/**
diff --git a/plugins/woocommerce/tests/php/src/Internal/DataStores/Orders/OrdersTableDataStoreTests.php b/plugins/woocommerce/tests/php/src/Internal/DataStores/Orders/OrdersTableDataStoreTests.php
index 51c6add1411..d35b08e84f4 100644
--- a/plugins/woocommerce/tests/php/src/Internal/DataStores/Orders/OrdersTableDataStoreTests.php
+++ b/plugins/woocommerce/tests/php/src/Internal/DataStores/Orders/OrdersTableDataStoreTests.php
@@ -643,6 +643,73 @@ class OrdersTableDataStoreTests extends \HposTestCase {
$this->assertEmpty( $order->get_meta( '_wp_trash_meta_status' ), 'Trash meta should still be cleaned up on the pending fallback path' );
}
+ /**
+ * Data provider for tests that run with the posts sync both on and off.
+ *
+ * @return array[]
+ */
+ public function data_provider_sync_enabled(): array {
+ return array(
+ 'sync off' => array( false ),
+ 'sync on' => array( true ),
+ );
+ }
+
+ /**
+ * @testdox Untrash does not fire 'woocommerce_update_order' when the clock ticks over a second during the restore, but a later save does.
+ * @dataProvider data_provider_sync_enabled
+ *
+ * @param bool $sync_enabled Whether the posts sync is on.
+ */
+ public function test_cot_datastore_untrash_does_not_fire_update_hook_across_second_boundary( bool $sync_enabled ) {
+ $this->toggle_cot_feature_and_usage( true );
+ if ( $sync_enabled ) {
+ $this->enable_cot_sync();
+ } else {
+ $this->disable_cot_sync();
+ }
+
+ $order = $this->create_complex_cot_order();
+ $order->set_status( OrderStatus::ON_HOLD );
+ $order->save();
+
+ $this->sut->trash_order( $order );
+ $this->sut->read( $order );
+
+ // Make the post-save meta cleanup see a "later" time than the date_modified the save just wrote.
+ $this->register_legacy_proxy_function_mocks(
+ array(
+ 'current_time' => function ( $type, $gmt = 0 ) {
+ unset( $type, $gmt );
+ return gmdate( 'Y-m-d H:i:s', time() + HOUR_IN_SECONDS );
+ },
+ )
+ );
+
+ $update_count = 0;
+ $callback = function () use ( &$update_count ) {
+ ++$update_count;
+ };
+ add_action( 'woocommerce_update_order', $callback );
+
+ $this->assertTrue( $this->sut->untrash_order( $order ) );
+ $this->assertSame( 0, $update_count, 'Untrash should not fire woocommerce_update_order' );
+
+ $order = wc_get_order( $order->get_id() );
+ $this->assertSame( OrderStatus::ON_HOLD, $order->get_status() );
+ $this->assertEmpty( $order->get_meta( '_wp_trash_meta_status' ) );
+ if ( $sync_enabled ) {
+ $this->assertSame( OrderInternalStatus::ON_HOLD, get_post_status( $order->get_id() ) );
+ $this->assertEmpty( get_post_meta( $order->get_id(), '_wp_trash_meta_status', true ) );
+ }
+
+ $order->set_customer_note( 'Edited after restore' );
+ $order->save();
+ remove_action( 'woocommerce_update_order', $callback );
+
+ $this->assertSame( 1, $update_count, 'A save after the restore should fire woocommerce_update_order' );
+ }
+
/**
* @testdox Notes are still restored on untrash even without a comment-status record.
*/