Commit 729e9263722 for woocommerce

commit 729e92637228830b1ac1a465071ecf2310ff10b3
Author: Cvetan Cvetanov <cvetan.cvetanov@automattic.com>
Date:   Fri Aug 7 19:13:27 2026 +0300

    Update product brand taxonomy labels for clarity (#66725)

    * Update product brand taxonomy labels for clarity

    * Add changelog entry for product brand taxonomy labels

    * Update brands filter label in Product Collection e2e tests

    The Product Collection block derives its Filters menu item labels from
    the taxonomy name, so renaming the product_brand taxonomy to Product
    brands changed the menu item from Show Brands to Show Product Brands.
    Update the e2e page object and spec to match, consistent with the
    existing Show product categories and Show product tags entries.

    * fix(brands): keep product brand menu label on non-contextual translation

    Vlad's review flagged a compatibility wrinkle in the taxonomy label update.
    Before this change WordPress derived the `product_brand` submenu label from
    `labels['name']`, i.e. `__( 'Brands', 'woocommerce' )`, so existing
    translations and `gettext_woocommerce` customizations applied to it.

    Registering `menu_name` with `_x( 'Brands', 'Admin menu name', 'woocommerce' )`
    kept the English output identical but routed the string through
    `gettext_with_context_woocommerce` and a new catalog entry. Non-English sites
    that already translate "Brands" would fall back to English on the submenu, and
    extensions filtering the non-contextual string would stop affecting it, for the
    one label the issue asks us to keep stable.

    Use `__( 'Brands', 'woocommerce' )` to preserve the original catalog identity
    and filter path. Add a test that installs a `gettext_woocommerce` filter and
    asserts it reaches `menu_name`, restoring the taxonomy in `finally`.

    Refs #56021

    * Fix Product Collection E2E helper formatting

    * Add E2E coverage for product brand taxonomy labels

    * test: drop intent-pinning brand label assertions

    Review feedback on PR 66725: the label-array PHPUnit assertion and the
    e2e heading/title test only fail when the labels are edited on purpose,
    so they pin intended copy rather than guard against regressions.

    Remove both. The gettext_woocommerce menu_name test stays: it protects
    the translation-path contract that an English-invisible _x() refactor
    would silently break.

    Refs #56021

    * fix: qualify only the plural brand taxonomy label

    Review feedback on PR 66725: singular_name is not admin-only. It is
    rendered by show_brand() on every classic-theme product page and by the
    Product Filters chips, so qualifying it changes shopper-facing copy and
    introduces a new untranslated msgid. Core precedent (product_cat,
    product_tag) qualifies only the plural.

    Revert singular_name to Brand and the inert label argument (overwritten
    by core from labels name) to Brands. Document in code why menu_name
    deliberately uses the non-contextual translation call.

    Refs #56021

diff --git a/plugins/woocommerce/changelog/add-56021-product-brand-taxonomy-labels b/plugins/woocommerce/changelog/add-56021-product-brand-taxonomy-labels
new file mode 100644
index 00000000000..df9989f5377
--- /dev/null
+++ b/plugins/woocommerce/changelog/add-56021-product-brand-taxonomy-labels
@@ -0,0 +1,4 @@
+Significance: patch
+Type: update
+
+Update product brand taxonomy labels to clarify they apply to products.
diff --git a/plugins/woocommerce/includes/class-wc-brands.php b/plugins/woocommerce/includes/class-wc-brands.php
index 24d58c42988..2a601715d50 100644
--- a/plugins/woocommerce/includes/class-wc-brands.php
+++ b/plugins/woocommerce/includes/class-wc-brands.php
@@ -321,8 +321,12 @@ class WC_Brands {
 					'update_count_callback' => '_wc_term_recount',
 					'label'                 => __( 'Brands', 'woocommerce' ),
 					'labels'                => array(
-						'name'              => __( 'Brands', 'woocommerce' ),
+						'name'              => __( 'Product brands', 'woocommerce' ),
 						'singular_name'     => __( 'Brand', 'woocommerce' ),
+						// Non-contextual on purpose: keeps the pre-existing `Brands` msgid so existing
+						// translations and `gettext_woocommerce` customizations keep applying. Guarded by
+						// WC_Brands_Test::test_product_brand_menu_name_uses_non_contextual_brands_translation().
+						'menu_name'         => __( 'Brands', 'woocommerce' ),
 						'template_name'     => _x( 'Products by Brand', 'Template name', 'woocommerce' ),
 						'search_items'      => __( 'Search Brands', 'woocommerce' ),
 						'all_items'         => __( 'All Brands', 'woocommerce' ),
diff --git a/plugins/woocommerce/tests/e2e/tests/blocks/product-collection/inspector-controls.block_theme.spec.ts b/plugins/woocommerce/tests/e2e/tests/blocks/product-collection/inspector-controls.block_theme.spec.ts
index cab223ec258..a192d7e60f9 100644
--- a/plugins/woocommerce/tests/e2e/tests/blocks/product-collection/inspector-controls.block_theme.spec.ts
+++ b/plugins/woocommerce/tests/e2e/tests/blocks/product-collection/inspector-controls.block_theme.spec.ts
@@ -190,7 +190,7 @@ test.describe( 'Product Collection: Inspector Controls', () => {
 	} ) => {
 		await pageObject.createNewPostAndInsertBlock();

-		await pageObject.addFilter( 'Show Brands' );
+		await pageObject.addFilter( 'Show Product Brands' );
 		await pageObject.checkTaxonomyTerm( 'brands', 'WooCommerce' );
 		await expect( pageObject.productTitles ).toHaveText( [
 			'Album',
diff --git a/plugins/woocommerce/tests/e2e/tests/blocks/product-collection/product-collection.page.ts b/plugins/woocommerce/tests/e2e/tests/blocks/product-collection/product-collection.page.ts
index 176b15d1c4a..b0e68158d70 100644
--- a/plugins/woocommerce/tests/e2e/tests/blocks/product-collection/product-collection.page.ts
+++ b/plugins/woocommerce/tests/e2e/tests/blocks/product-collection/product-collection.page.ts
@@ -227,9 +227,8 @@ class ProductCollectionPage {
 	}

 	async chooseCollectionInTemplate( collection?: Collections ) {
-		const collectionButton = await this.locateCollectionButtonInEditor(
-			collection
-		);
+		const collectionButton =
+			await this.locateCollectionButtonInEditor( collection );

 		await collectionButton.click();
 	}
@@ -428,7 +427,7 @@ class ProductCollectionPage {
 			| 'Keyword'
 			| 'Show product categories'
 			| 'Show product tags'
-			| 'Show Brands'
+			| 'Show Product Brands'
 			| 'Show Product Attributes'
 			| 'Featured'
 			| 'Created'
diff --git a/plugins/woocommerce/tests/e2e/tests/brands/create-product-brand.spec.ts b/plugins/woocommerce/tests/e2e/tests/brands/create-product-brand.spec.ts
index 9e09e710e43..03c04b9f764 100644
--- a/plugins/woocommerce/tests/e2e/tests/brands/create-product-brand.spec.ts
+++ b/plugins/woocommerce/tests/e2e/tests/brands/create-product-brand.spec.ts
@@ -16,6 +16,9 @@ interface Brand {
 	thumbnailFileName: string;
 }

+const productBrandsPageUrl =
+	'wp-admin/edit-tags.php?taxonomy=product_brand&post_type=product';
+
 test.use( { storageState: ADMIN_STATE_PATH } );

 test( 'Merchant can add brands', async ( { page } ) => {
@@ -26,9 +29,7 @@ test( 'Merchant can add brands', async ( { page } ) => {
 	 * This is to workaround the hover menu for now.
 	 */
 	const goToBrandsPage = async () => {
-		await page.goto(
-			'wp-admin/edit-tags.php?taxonomy=product_brand&post_type=product'
-		);
+		await page.goto( productBrandsPageUrl );

 		// Wait for the Brands page to load.
 		// This is needed so that checking for existing brands would work.
diff --git a/plugins/woocommerce/tests/php/includes/class-wc-brands-test.php b/plugins/woocommerce/tests/php/includes/class-wc-brands-test.php
index dcb937c4377..2242722b269 100644
--- a/plugins/woocommerce/tests/php/includes/class-wc-brands-test.php
+++ b/plugins/woocommerce/tests/php/includes/class-wc-brands-test.php
@@ -12,6 +12,46 @@ declare( strict_types = 1);
  */
 class WC_Brands_Test extends WC_Unit_Test_Case {

+	/**
+	 * The admin menu label must keep translating through the non-contextual `Brands` string.
+	 *
+	 * The menu label is the one label the taxonomy update deliberately keeps as `Brands`. Before the
+	 * update WordPress derived `menu_name` from `labels['name']`, i.e. `__( 'Brands', 'woocommerce' )`,
+	 * so existing translations and `gettext_woocommerce` customizations applied to it. This asserts that
+	 * contract by filtering the non-contextual string and confirming it still reaches `menu_name`, which
+	 * would fail if the label were registered with a context (`_x()` routes through
+	 * `gettext_with_context_woocommerce` and a different catalog entry instead).
+	 *
+	 * @testdox Product brand admin menu label keeps translating through the non-contextual `Brands` string.
+	 */
+	public function test_product_brand_menu_name_uses_non_contextual_brands_translation(): void {
+		$translate_brands = static function ( $translation, $text, $domain ) {
+			if ( 'woocommerce' === $domain && 'Brands' === $text ) {
+				return 'Translated brands';
+			}
+			return $translation;
+		};
+
+		add_filter( 'gettext_woocommerce', $translate_brands, 10, 3 );
+
+		try {
+			WC_Brands::init_taxonomy();
+			$taxonomy = get_taxonomy( 'product_brand' );
+
+			$this->assertInstanceOf( WP_Taxonomy::class, $taxonomy, 'The product brand taxonomy should be registered.' );
+			$this->assertSame(
+				'Translated brands',
+				$taxonomy->labels->menu_name,
+				'The admin menu label should keep resolving through the non-contextual `Brands` translation.'
+			);
+		} finally {
+			remove_filter( 'gettext_woocommerce', $translate_brands, 10 );
+
+			// Restore the taxonomy with its unfiltered labels so later tests are unaffected.
+			WC_Brands::init_taxonomy();
+		}
+	}
+
 	/**
 	 * Tear down test data.
 	 */