Commit d825abfef6 for woocommerce
commit d825abfef66ba5e3d7214f65e684a6fd37399625
Author: Lucio Giannotta <sunyatasattva@gmail.com>
Date: Tue Jul 1 20:22:03 2025 +0200
Fix brands shortcode being empty when `show_empty` was set to `false` (#59297)
* Fix brands shortcodes being empty when `show_empty` was set to `false`
This fixes a regression introduced in WooCommerce 9.9.4 where the
`[product_brand_thumbnails show_empty="false"]` shortcode would return
no results, even when brands with products existed.
The issue was caused by PR #58797 which modified `wc_change_term_counts()`.
This change resulted in brand terms having `$term->count = 0` even
when they had associated products, due to how the product_brand taxonomy
uses `_update_post_term_count` instead of WooCommerce’s `_wc_term_recount`.
Removed the redundant `remove_terms_with_empty_products()` calls in both shortcode
methods when `hide_empty` is true, since `get_terms()` already handles this filtering
correctly.
Fixes #59242
diff --git a/plugins/woocommerce/changelog/59297-wooplug-4823-woocommerce-brands-product_brand_thumbnails-shortcode-breaks b/plugins/woocommerce/changelog/59297-wooplug-4823-woocommerce-brands-product_brand_thumbnails-shortcode-breaks
new file mode 100644
index 0000000000..4502268ad1
--- /dev/null
+++ b/plugins/woocommerce/changelog/59297-wooplug-4823-woocommerce-brands-product_brand_thumbnails-shortcode-breaks
@@ -0,0 +1,4 @@
+Significance: patch
+Type: fix
+
+Fixed brands shortcode being empty when `show_empty` was set to `false`.
\ No newline at end of file
diff --git a/plugins/woocommerce/includes/class-wc-brands.php b/plugins/woocommerce/includes/class-wc-brands.php
index 5846476590..1eede1fa38 100644
--- a/plugins/woocommerce/includes/class-wc-brands.php
+++ b/plugins/woocommerce/includes/class-wc-brands.php
@@ -567,13 +567,6 @@ class WC_Brands {
$alphabet = apply_filters( 'woocommerce_brands_list_alphabet', range( 'a', 'z' ) );
$numbers = apply_filters( 'woocommerce_brands_list_numbers', '0-9' );
- /**
- * Check for empty brands and remove them from the list.
- */
- if ( ! $show_empty_brands ) {
- $terms = $this->remove_terms_with_empty_products( $terms );
- }
-
foreach ( $terms as $term ) {
$term_letter = $this->get_brand_name_first_character( $term->name );
@@ -672,10 +665,6 @@ class WC_Brands {
return;
}
- if ( $hide_empty ) {
- $brands = $this->remove_terms_with_empty_products( $brands );
- }
-
ob_start();
wc_get_template(
@@ -723,7 +712,7 @@ class WC_Brands {
$brands = get_terms(
'product_brand',
array(
- 'hide_empty' => $args['hide_empty'],
+ 'hide_empty' => $hide_empty,
'orderby' => $args['orderby'],
'exclude' => $exclude,
'number' => $args['number'],
@@ -735,10 +724,6 @@ class WC_Brands {
return;
}
- if ( $hide_empty ) {
- $brands = $this->remove_terms_with_empty_products( $brands );
- }
-
ob_start();
wc_get_template(
@@ -1026,22 +1011,6 @@ class WC_Brands {
$product->save();
}
- /**
- * Remove terms with empty products.
- *
- * @param WP_Term[] $terms The terms array that needs to be removed of empty products.
- *
- * @return WP_Term[]
- */
- private function remove_terms_with_empty_products( $terms ) {
- return array_filter(
- $terms,
- function ( $term ) {
- return $term->count > 0;
- }
- );
- }
-
/**
* Invalidates the layered nav counts cache.
*
diff --git a/plugins/woocommerce/tests/php/includes/class-wc-brands-test.php b/plugins/woocommerce/tests/php/includes/class-wc-brands-test.php
new file mode 100644
index 0000000000..1f1981645d
--- /dev/null
+++ b/plugins/woocommerce/tests/php/includes/class-wc-brands-test.php
@@ -0,0 +1,99 @@
+<?php
+/**
+ * WooCommerce Brands Unit tests suite
+ *
+ * @package woocommerce-brands
+ */
+
+declare( strict_types = 1);
+
+require_once WC_ABSPATH . '/includes/class-wc-brands.php';
+
+/**
+ * WC Brands test
+ */
+class WC_Brands_Test extends WC_Unit_Test_Case {
+ /**
+ * Test that `product_brand_thumbnails` shortcode's `show_empty` argument works as expected.
+ * This test prevents regression of the issue where double filtering caused no brands to be displayed.
+ */
+ public function test_product_brand_thumbnails_shortcode_with_show_empty_arg() {
+ $data = $this->setup_brand_test_data();
+ $brands_instance = $data['brands_instance'];
+
+ $output = $brands_instance->output_product_brand_thumbnails( array( 'show_empty' => 'false' ) );
+
+ // Full brand is shown, empty brand is not.
+ $this->assertStringContainsString( 'Full Brand', $output );
+ $this->assertStringNotContainsString( 'Empty Brand', $output );
+
+ $output = $brands_instance->output_product_brand_thumbnails( array( 'show_empty' => 'true' ) );
+
+ // Both brands are shown.
+ $this->assertStringContainsString( 'Full Brand', $output );
+ $this->assertStringContainsString( 'Empty Brand', $output );
+ }
+
+ /**
+ * Test that `product_brand_thumbnails_description` shortcode's `show_empty` argument works as expected.
+ */
+ public function test_product_brand_thumbnails_description_shortcode_with_show_empty_arg() {
+ $data = $this->setup_brand_test_data();
+ $brands_instance = $data['brands_instance'];
+
+ $output = $brands_instance->output_product_brand_thumbnails_description( array( 'show_empty' => 'false' ) );
+
+ // Full brand is shown, empty brand is not.
+ $this->assertStringContainsString( 'Full Brand', $output );
+ $this->assertStringNotContainsString( 'Empty Brand', $output );
+
+ $output = $brands_instance->output_product_brand_thumbnails_description( array( 'show_empty' => 'true' ) );
+
+ // Both brands are shown.
+ $this->assertStringContainsString( 'Full Brand', $output );
+ $this->assertStringContainsString( 'Empty Brand', $output );
+ }
+
+ /**
+ * Test that `product_brand_list` shortcode's `show_empty_brands` argument works as expected.
+ */
+ public function test_product_brand_list_shortcode_with_show_empty_brands_arg() {
+ $data = $this->setup_brand_test_data();
+ $brands_instance = $data['brands_instance'];
+
+ $output = $brands_instance->output_product_brand_list( array( 'show_empty_brands' => 'false' ) );
+
+ // Full brand is shown, empty brand is not.
+ $this->assertStringContainsString( 'Full Brand', $output );
+ $this->assertStringNotContainsString( 'Empty Brand', $output );
+
+ $output = $brands_instance->output_product_brand_list( array( 'show_empty_brands' => 'true' ) );
+
+ // Both brands are shown.
+ $this->assertStringContainsString( 'Full Brand', $output );
+ $this->assertStringContainsString( 'Empty Brand', $output );
+ }
+
+ /**
+ * Helper method to set up test data for brand shortcode tests.
+ *
+ * @return array Contains brands instance, brand term IDs and product ID.
+ */
+ private function setup_brand_test_data() {
+ WC_Brands::init_taxonomy();
+
+ $brand_with_products = wp_insert_term( 'Full Brand', 'product_brand' );
+ $empty_brand = wp_insert_term( 'Empty Brand', 'product_brand' );
+
+ $product = WC_Helper_Product::create_simple_product();
+ $product->save();
+ wp_set_object_terms( $product->get_id(), array( $brand_with_products['term_id'] ), 'product_brand' );
+
+ return array(
+ 'brands_instance' => new WC_Brands(),
+ 'brand_with_products' => $brand_with_products,
+ 'empty_brand' => $empty_brand,
+ 'product' => $product,
+ );
+ }
+}