Commit afdc536af33 for woocommerce

commit afdc536af33e331d3fa9593923fa60076f118e2a
Author: Vlad Olaru <vlad.olaru@automattic.com>
Date:   Tue Sep 15 16:05:45 2026 +0300

    [tests] Cover the trashed shop page rewrite-flush guard (#68686)

    * test(php): Cover the trashed shop page rewrite-flush guard

    `queue_rewrite_rules_on_shop_page_save()` returns early when the saved
    page is trashed, so a trashed shop page keeps serving the product
    archive at its previous URL. #65967 added that guard and no test held
    it: `class-wc-post-types-test.php` exercised the flush queue in several
    ways but never through a status change.

    An E2E spec used to be the only thing that would go red if the guard
    were removed, and #68642 demotes that spec, so add the coverage here
    instead. Two tests, because a negative assertion on its own would pass
    just as happily if the hook stopped firing: one saves the published
    shop page and expects the flush queued, the other trashes it and
    expects the queue untouched.

    Refs TESTOPS-288

    Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

    * test(php): Point the shop page option away from the trashed page

    The trash test leaves `woocommerce_shop_page_id` pointing at a page
    WordPress has renamed to `shop__trashed`. The class tear down then runs
    `unregister_post_type( 'product' )` and `WC_Post_Types::register_post_types()`
    before the transaction rolls back, and that reads the option to build
    `has_archive`.

    The WordPress base class only resets post types when WP_RUN_CORE_TESTS is
    set, which the WooCommerce suite never sets, so the registered object
    survives into the rest of the process. Measured with theme support on:
    the archive registers as `shop__trashed` and stays there. It does not
    fire today only because `should_register_product_archive()` is false for
    the suite's active theme, which this test neither controls nor asserts.

    Restore the option in a `finally` so the tear down re-registers against
    the published page. Verified the same way: `shop__trashed` before the
    restore, `shop` after.

    Refs #68686

    Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

    * test(php): Trash the shop page through wp_trash_post()

    The trash test moved the shop page to the trash with wp_update_post()
    and a post_status of trash. Merchants trash pages from the editor or
    the REST API, and both call wp_trash_post(), which also fires the
    wp_trash_post and trashed_post actions and records the trash meta
    before saving through the same wp_update_post() call.

    Calling wp_trash_post() exercises that real path. It still reaches the
    save_post_page guard, and the test still fails when the trash check is
    removed from the guard.

    Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

    ---------

    Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>

diff --git a/plugins/woocommerce/changelog/test-shop-page-trash-rewrite-guard b/plugins/woocommerce/changelog/test-shop-page-trash-rewrite-guard
new file mode 100644
index 00000000000..6cab33d743f
--- /dev/null
+++ b/plugins/woocommerce/changelog/test-shop-page-trash-rewrite-guard
@@ -0,0 +1,4 @@
+Significance: patch
+Type: dev
+
+Cover the trashed-shop-page guard that keeps a rewrite flush from being queued.
diff --git a/plugins/woocommerce/tests/php/includes/class-wc-post-types-test.php b/plugins/woocommerce/tests/php/includes/class-wc-post-types-test.php
index 13beadefaae..7e0b91de911 100644
--- a/plugins/woocommerce/tests/php/includes/class-wc-post-types-test.php
+++ b/plugins/woocommerce/tests/php/includes/class-wc-post-types-test.php
@@ -444,6 +444,70 @@ class WC_Post_Types_Test extends WC_Unit_Test_Case {
 		$this->assertSame( $original_blog_id, get_current_blog_id(), 'The original site context should be restored.' );
 	}

+	/**
+	 * @testdox Saving the shop page queues a rewrite flush.
+	 */
+	public function test_saving_the_shop_page_queues_a_rewrite_flush(): void {
+		$shop_page_id = $this->prepare_shop_page();
+
+		wp_update_post(
+			array(
+				'ID'         => $shop_page_id,
+				'post_title' => 'Shop, renamed',
+			)
+		);
+
+		$this->assertSame(
+			'yes',
+			get_option( 'woocommerce_queue_flush_rewrite_rules' ),
+			'Saving the shop page should queue a rewrite flush.'
+		);
+	}
+
+	/**
+	 * @testdox Trashing the shop page does not queue a rewrite flush.
+	 */
+	public function test_trashing_the_shop_page_does_not_queue_a_rewrite_flush(): void {
+		$previous_shop_page_id = get_option( 'woocommerce_shop_page_id' );
+		$shop_page_id          = $this->prepare_shop_page();
+
+		try {
+			wp_trash_post( $shop_page_id );
+
+			$this->assertSame(
+				'no',
+				get_option( 'woocommerce_queue_flush_rewrite_rules' ),
+				'A trashed shop page keeps serving the product archive at its previous URL, so it must not queue a flush.'
+			);
+		} finally {
+			// Trashing renames the page to `shop__trashed`, and `tearDown()` re-registers the
+			// product post type before the transaction rolls back. The base class only resets
+			// post types for core's own suite, so a theme that supports WooCommerce would hand
+			// that name to `has_archive` and leave it there for the rest of the process.
+			update_option( 'woocommerce_shop_page_id', $previous_shop_page_id );
+		}
+	}
+
+	/**
+	 * Publish a page, make it the shop page, and empty the rewrite flush queue.
+	 *
+	 * @return int The shop page ID.
+	 */
+	private function prepare_shop_page(): int {
+		$shop_page_id = self::factory()->post->create(
+			array(
+				'post_type'   => 'page',
+				'post_status' => 'publish',
+				'post_title'  => 'Shop',
+			)
+		);
+
+		update_option( 'woocommerce_shop_page_id', $shop_page_id );
+		update_option( 'woocommerce_queue_flush_rewrite_rules', 'no' );
+
+		return $shop_page_id;
+	}
+
 	/**
 	 * Register a public post type standing in for one owned by a third-party plugin.
 	 */