Commit b3938be1557 for woocommerce

commit b3938be15575bf2fd3b48886b1f6d53f7565b7c2
Author: Tung Du <dinhtungdu@gmail.com>
Date:   Mon Aug 3 16:30:23 2026 +0700

    Preserve product archive rewrite rules when WP-CLI skips the active theme and another plugin flushes permalinks (#67101)

    * fix: preserve shop rewrites when WP-CLI skips themes

    * chore: add shop rewrite fix changelog

    * refactor: clarify product archive registration decision

    * fix: trust runtime theme support during cron

    * test: remove product archive E2E coverage

    * refactor: narrow WP-CLI config callback

diff --git a/plugins/woocommerce/changelog/fix-cli-skipped-theme-rewrite-rules b/plugins/woocommerce/changelog/fix-cli-skipped-theme-rewrite-rules
new file mode 100644
index 00000000000..a04a1ac29b0
--- /dev/null
+++ b/plugins/woocommerce/changelog/fix-cli-skipped-theme-rewrite-rules
@@ -0,0 +1,4 @@
+Significance: patch
+Type: fix
+
+Preserve product archive rewrite rules when WP-CLI skips the active theme and another plugin flushes permalinks.
diff --git a/plugins/woocommerce/includes/class-wc-post-types.php b/plugins/woocommerce/includes/class-wc-post-types.php
index 357d04dc707..d64ac91955f 100644
--- a/plugins/woocommerce/includes/class-wc-post-types.php
+++ b/plugins/woocommerce/includes/class-wc-post-types.php
@@ -344,9 +344,11 @@ class WC_Post_Types {
 			$supports[] = 'comments';
 		}

-		$shop_page_id = wc_get_page_id( 'shop' );
+		$shop_page_id         = wc_get_page_id( 'shop' );
+		$theme_support        = wc_current_theme_supports_woocommerce_or_fse();
+		$active_theme_skipped = self::wp_cli_skips_active_theme();

-		if ( wc_current_theme_supports_woocommerce_or_fse() ) {
+		if ( self::should_register_product_archive( $theme_support, $active_theme_skipped ) ) {
 			$has_archive = $shop_page_id && get_post( $shop_page_id ) ? urldecode( get_page_uri( $shop_page_id ) ) : 'shop';
 		} else {
 			$has_archive = false;
@@ -356,7 +358,7 @@ class WC_Post_Types {
 		// Skip this check in WP-CLI and cron contexts: themes may not be loaded (e.g. --skip-themes),
 		// which would incorrectly record theme support as "no" and corrupt rewrite rules on the frontend.
 		if ( ! ( defined( 'WP_CLI' ) && WP_CLI ) && ! wp_doing_cron() ) {
-			$theme_support = wc_current_theme_supports_woocommerce_or_fse() ? 'yes' : 'no';
+			$theme_support = $theme_support ? 'yes' : 'no';
 			if ( get_option( 'current_theme_supports_woocommerce' ) !== $theme_support && update_option( 'current_theme_supports_woocommerce', $theme_support ) ) {
 				update_option( 'woocommerce_queue_flush_rewrite_rules', 'yes' );
 			}
@@ -541,6 +543,46 @@ class WC_Post_Types {
 		do_action( 'woocommerce_after_register_post_type' );
 	}

+	/**
+	 * Resolve theme support used to register the product archive.
+	 *
+	 * @param bool $theme_support        Whether the current request reports theme support.
+	 * @param bool $active_theme_skipped Whether WP-CLI skipped the active theme.
+	 * @return bool
+	 */
+	private static function should_register_product_archive( bool $theme_support, bool $active_theme_skipped ): bool {
+		if ( $theme_support || ! $active_theme_skipped ) {
+			return $theme_support;
+		}
+
+		return 'yes' === get_option( 'current_theme_supports_woocommerce' );
+	}
+
+	/**
+	 * Determine whether WP-CLI skipped the active theme.
+	 *
+	 * @return bool
+	 */
+	private static function wp_cli_skips_active_theme(): bool {
+		$get_wp_cli_config = array( 'WP_CLI', 'get_config' );
+
+		if ( ! ( defined( 'WP_CLI' ) && WP_CLI ) || ! is_callable( $get_wp_cli_config ) ) {
+			return false;
+		}
+
+		$skipped_themes = $get_wp_cli_config( 'skip-themes' );
+
+		if ( true === $skipped_themes ) {
+			return true;
+		}
+
+		if ( ! is_array( $skipped_themes ) ) {
+			$skipped_themes = explode( ',', (string) $skipped_themes );
+		}
+
+		return in_array( get_stylesheet(), $skipped_themes, true );
+	}
+
 	/**
 	 * Customize taxonomies update messages.
 	 *
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
new file mode 100644
index 00000000000..7ca0094401e
--- /dev/null
+++ b/plugins/woocommerce/tests/php/includes/class-wc-post-types-test.php
@@ -0,0 +1,85 @@
+<?php
+/**
+ * Tests for WC_Post_Types.
+ *
+ * @package WooCommerce\Tests\PostTypes
+ */
+
+declare( strict_types = 1 );
+
+/**
+ * Tests for WC_Post_Types.
+ */
+class WC_Post_Types_Test extends WC_Unit_Test_Case {
+
+	/**
+	 * Original stored theme support value.
+	 *
+	 * @var mixed
+	 */
+	private $original_theme_support;
+
+	/**
+	 * Set up test fixtures.
+	 */
+	public function setUp(): void {
+		parent::setUp();
+
+		$this->original_theme_support = get_option( 'current_theme_supports_woocommerce', '__missing__' );
+	}
+
+	/**
+	 * Restore test fixtures.
+	 */
+	public function tearDown(): void {
+		if ( '__missing__' === $this->original_theme_support ) {
+			delete_option( 'current_theme_supports_woocommerce' );
+		} else {
+			update_option( 'current_theme_supports_woocommerce', $this->original_theme_support );
+		}
+
+		parent::tearDown();
+	}
+
+	/**
+	 * @testdox Product archive registration uses runtime support unless WP-CLI skipped the active theme.
+	 * @dataProvider provide_product_archive_theme_support_cases
+	 *
+	 * @param bool   $runtime_support      Whether the current request reports theme support.
+	 * @param bool   $active_theme_skipped Whether WP-CLI skipped the active theme.
+	 * @param string $stored_support       Stored support from the last trusted request.
+	 * @param bool   $expected              Expected resolved support.
+	 */
+	public function test_should_register_product_archive(
+		bool $runtime_support,
+		bool $active_theme_skipped,
+		string $stored_support,
+		bool $expected
+	): void {
+		update_option( 'current_theme_supports_woocommerce', $stored_support );
+
+		$method = new ReflectionMethod( WC_Post_Types::class, 'should_register_product_archive' );
+		$method->setAccessible( true );
+
+		$this->assertSame(
+			$expected,
+			$method->invoke( null, $runtime_support, $active_theme_skipped ),
+			'Product archive support should only fall back to trusted stored support when WP-CLI skipped the active theme.'
+		);
+	}
+
+	/**
+	 * Data provider for product archive theme support resolution.
+	 *
+	 * @return array<string, array{bool, bool, string, bool}>
+	 */
+	public function provide_product_archive_theme_support_cases(): array {
+		return array(
+			'supported runtime'                    => array( true, false, 'no', true ),
+			'ordinary cron ignores stored support' => array( false, false, 'yes', false ),
+			'WP-CLI skipped supported theme'       => array( false, true, 'yes', true ),
+			'WP-CLI skipped unsupported theme'     => array( false, true, 'no', false ),
+			'supported WP-CLI runtime'             => array( true, true, 'no', true ),
+		);
+	}
+}