Commit 1f396922632 for woocommerce

commit 1f3969226324ac97ab413405af499e9a7bc029ff
Author: Jorge A. Torres <jorge.torres@automattic.com>
Date:   Tue Aug 25 14:21:39 2026 +0100

    Fix orphaned order notes when HPOS orders are deleted (#67935)

    * Fix: Delete orphaned order notes when order is deleted with HPOS (sync disabled) (#62620)

    - Use wp_delete_comment() API for proper cache invalidation and meta cleanup
    - Add regression tests for both deletion paths:
      1. Placeholder post: verifies notes and commentmeta are deleted
      2. Non-placeholder post: verifies notes are preserved + deletion marker created

    Addresses review feedback from @jorgeatorres and follow-up from @isaeedam-ir

    * Delete order notes immediately regardless of sync state or post type

    * Simplify order notes tests, dropping a redundant one

    ---------

    Co-authored-by: shsajalchowdhury <sajal.marketer@gmail.com>

diff --git a/plugins/woocommerce/changelog/fix-62620-hpos-order-notes-orphaned b/plugins/woocommerce/changelog/fix-62620-hpos-order-notes-orphaned
new file mode 100644
index 00000000000..c210a410bdb
--- /dev/null
+++ b/plugins/woocommerce/changelog/fix-62620-hpos-order-notes-orphaned
@@ -0,0 +1,4 @@
+Significance: patch
+Type: fix
+
+Delete orphaned order notes (comments) when an order is permanently deleted with HPOS enabled and sync disabled.
diff --git a/plugins/woocommerce/src/Internal/DataStores/Orders/OrdersTableDataStore.php b/plugins/woocommerce/src/Internal/DataStores/Orders/OrdersTableDataStore.php
index 4b8c7c3778a..c9b072378e6 100644
--- a/plugins/woocommerce/src/Internal/DataStores/Orders/OrdersTableDataStore.php
+++ b/plugins/woocommerce/src/Internal/DataStores/Orders/OrdersTableDataStore.php
@@ -2710,6 +2710,18 @@ FROM $order_meta_table
 	protected function handle_order_deletion_with_sync_disabled( $order_id ): void {
 		global $wpdb;

+		// Notes are the order's own data, not the backup post's, so they shouldn't wait on a deferred post record.
+		$comments = $wpdb->get_col(
+			$wpdb->prepare(
+				"SELECT comment_ID FROM {$wpdb->comments} WHERE comment_post_ID = %d",
+				$order_id
+			)
+		);
+
+		foreach ( $comments as $comment_id ) {
+			wp_delete_comment( $comment_id, true );
+		}
+
 		$post_type = $wpdb->get_var(
 			$wpdb->prepare( "SELECT post_type FROM {$wpdb->posts} WHERE ID=%d", $order_id )
 		);
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 a5db22b42eb..f36e0a78a12 100644
--- a/plugins/woocommerce/tests/php/src/Internal/DataStores/Orders/OrdersTableDataStoreTests.php
+++ b/plugins/woocommerce/tests/php/src/Internal/DataStores/Orders/OrdersTableDataStoreTests.php
@@ -4264,4 +4264,38 @@ class OrdersTableDataStoreTests extends \HposTestCase {
 		$order->delete();
 		$product->delete();
 	}
+
+	/**
+	 * @testDox Order notes (and their commentmeta) are deleted immediately when an order is deleted, regardless of whether sync was enabled when the order was created or when it's deleted.
+	 *
+	 * @testWith [false, false]
+	 *           [true, false]
+	 *           [false, true]
+	 *           [true, true]
+	 *
+	 * @param bool $sync_enabled_at_creation Whether sync was enabled when the order (and its backup post) was created.
+	 * @param bool $sync_enabled_at_deletion Whether sync is enabled when the order is deleted.
+	 */
+	public function test_order_notes_deleted_regardless_of_sync_state( bool $sync_enabled_at_creation, bool $sync_enabled_at_deletion ) {
+		$this->allow_current_user_to_delete_posts();
+		$this->toggle_cot_feature_and_usage( true );
+		$this->toggle_cot_authoritative( true );
+		$sync_enabled_at_creation ? $this->enable_cot_sync() : $this->disable_cot_sync();
+
+		$order    = OrderHelper::create_order();
+		$order_id = $order->get_id();
+		$note_id  = $order->add_order_note( 'Test note' );
+		add_comment_meta( $note_id, 'test_key', 'test_value' );
+
+		$this->assertSame( 'test_value', get_comment_meta( $note_id, 'test_key', true ), 'Commentmeta should exist before the order is deleted' );
+
+		$expected_post_type = $sync_enabled_at_creation ? 'shop_order' : DataSynchronizer::PLACEHOLDER_ORDER_POST_TYPE;
+		$this->assertEquals( $expected_post_type, get_post_type( $order_id ) );
+
+		$sync_enabled_at_deletion ? $this->enable_cot_sync() : $this->disable_cot_sync();
+		$order->delete( true );
+
+		$this->assertNull( get_comment( $note_id ), 'Order note should be deleted' );
+		$this->assertEmpty( get_comment_meta( $note_id ), 'Commentmeta should be deleted along with the note' );
+	}
 }