Commit bb9d620f84d for woocommerce
commit bb9d620f84df364f9c7a40f932fb99600104b5bd
Author: Faisal Ahammad <faisalahammad24@gmail.com>
Date: Fri Jul 10 18:42:42 2026 +0600
fix: add missing layout styles for brand thumbnails description shortcode (#66280)
* fix: add missing layout styles for brand thumbnails description shortcode
Add float, clearfix, list-style, and column margin rules for
.brand-thumbnails-description so the product_brand_thumbnails_description
shortcode renders a proper grid instead of a bare unstyled list.
Also add a columns-1 wrapper class to the template so the default
single-column output does not overflow with the new margin rule.
Fixes #59417
* fix(brands): clamp columns and add regression test for brand thumbnails description shortcode
* fix(brands): merge duplicate CSS for brand thumbnails description
- Merge .brand-thumbnails-description selectors into the existing
ul.brand-thumbnails block instead of duplicating rules
- Add width: 100% to the thumbnail image so oversized brand images
don't overflow the grid
Addresses PR feedback.
Refs #66280
* fix(brands): address PR review feedback
- Clamp columns in output_product_brand_thumbnails() to prevent division-by-zero
- Bump template version to 11.1.0
- Add regression test for columns=0 and columns=abc
Refs #66280
* fix(brands): preserve default columns for non-numeric shortcode value
Non-numeric columns attribute now falls back to the shortcode default
(4 for thumbnails, 1 for thumbnails description) instead of clamping
to 1, matching trunk behavior for existing stores. Numeric zero still
clamps to 1 to avoid division-by-zero.
Addresses PR feedback.
Refs #66280
* fix(brands): wrap new selectors in :where() for lowest specificity
Wrap all .brand-thumbnails-description selectors in :where() so they
add zero specificity, matching the pattern already used elsewhere in
brands.scss and woocommerce.scss. ul.brand-thumbnails is untouched.
Addresses PR review feedback.
Refs #66280
diff --git a/plugins/woocommerce/changelog/59417-brand-thumbnails-description-css b/plugins/woocommerce/changelog/59417-brand-thumbnails-description-css
new file mode 100644
index 00000000000..0a9b393c52f
--- /dev/null
+++ b/plugins/woocommerce/changelog/59417-brand-thumbnails-description-css
@@ -0,0 +1,4 @@
+Significance: patch
+Type: fix
+
+Fix missing default layout styles for the product_brand_thumbnails_description shortcode.
diff --git a/plugins/woocommerce/client/legacy/css/brands.scss b/plugins/woocommerce/client/legacy/css/brands.scss
index 060d28a0278..143715ae5d4 100644
--- a/plugins/woocommerce/client/legacy/css/brands.scss
+++ b/plugins/woocommerce/client/legacy/css/brands.scss
@@ -24,20 +24,23 @@
}
/* Brand thumbnails widget */
-ul.brand-thumbnails {
+ul.brand-thumbnails,
+:where(.brand-thumbnails-description) {
margin-left: 0;
margin-bottom: 0;
clear: both;
list-style: none;
}
-ul.brand-thumbnails:before {
+ul.brand-thumbnails:before,
+:where(.brand-thumbnails-description):before {
clear: both;
content: "";
display: table;
}
-ul.brand-thumbnails:after {
+ul.brand-thumbnails:after,
+:where(.brand-thumbnails-description):after {
clear: both;
content: "";
display: table;
@@ -55,11 +58,14 @@ ul.brand-thumbnails.fluid-columns li {
width: auto;
}
-ul.brand-thumbnails:not(.fluid-columns) li.first {
+ul.brand-thumbnails:not(.fluid-columns) li.first,
+:where(.brand-thumbnails-description) li.first {
clear: both;
}
-ul.brand-thumbnails:not(.fluid-columns) li.last {
+ul.brand-thumbnails:not(.fluid-columns) li.last,
+:where(.brand-thumbnails-description) li.last,
+:where(.brand-thumbnails-description.columns-1) li {
margin-right: 0;
}
@@ -117,15 +123,20 @@ ul.brand-thumbnails.columns-6 li {
}
/* Brand thumbnails description */
-.brand-thumbnails-description li {
+:where(.brand-thumbnails-description) li {
+ float: left;
+ margin: 0 2% 1em 0;
+ padding: 0;
+ position: relative;
text-align: center;
}
-.brand-thumbnails-description li .term-thumbnail img {
+:where(.brand-thumbnails-description) li .term-thumbnail img {
+ width: 100%;
display: inline;
}
-.brand-thumbnails-description li .term-description {
+:where(.brand-thumbnails-description) li .term-description {
margin-top: 1em;
text-align: left;
}
diff --git a/plugins/woocommerce/includes/class-wc-brands.php b/plugins/woocommerce/includes/class-wc-brands.php
index 5cb18913dba..da9956f3719 100644
--- a/plugins/woocommerce/includes/class-wc-brands.php
+++ b/plugins/woocommerce/includes/class-wc-brands.php
@@ -731,7 +731,7 @@ class WC_Brands {
'widgets/brand-thumbnails.php',
array(
'brands' => $brands,
- 'columns' => is_numeric( $args['columns'] ) ? intval( $args['columns'] ) : 4,
+ 'columns' => is_numeric( $args['columns'] ) ? max( 1, absint( $args['columns'] ) ) : 4,
'fluid_columns' => wp_validate_boolean( $args['fluid_columns'] ),
),
'woocommerce',
@@ -790,7 +790,7 @@ class WC_Brands {
'widgets/brand-thumbnails-description.php',
array(
'brands' => $brands,
- 'columns' => $args['columns'],
+ 'columns' => is_numeric( $args['columns'] ) ? max( 1, absint( $args['columns'] ) ) : 1,
),
'woocommerce',
WC()->plugin_path() . '/templates/brands/'
diff --git a/plugins/woocommerce/templates/brands/widgets/brand-thumbnails-description.php b/plugins/woocommerce/templates/brands/widgets/brand-thumbnails-description.php
index 777c3be4546..0af54ff2a68 100644
--- a/plugins/woocommerce/templates/brands/widgets/brand-thumbnails-description.php
+++ b/plugins/woocommerce/templates/brands/widgets/brand-thumbnails-description.php
@@ -12,12 +12,14 @@
*
* @see https://woocommerce.com/document/template-structure/
* @package WooCommerce\Templates
- * @version 9.4.0
+ * @version 11.1.0
*/
declare( strict_types = 1);
+
+$wrapper_class = 1 === (int) $columns ? 'columns-1' : '';
?>
-<ul class="brand-thumbnails-description">
+<ul class="brand-thumbnails-description <?php echo esc_attr( $wrapper_class ); ?>">
<?php
foreach ( $brands as $index => $brand ) :
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 75b82395356..74bbf6405f3 100644
--- a/plugins/woocommerce/tests/php/includes/class-wc-brands-test.php
+++ b/plugins/woocommerce/tests/php/includes/class-wc-brands-test.php
@@ -62,6 +62,46 @@ class WC_Brands_Test extends WC_Unit_Test_Case {
$this->assertStringContainsString( 'Empty Brand', $output );
}
+ /**
+ * Test that `product_brand_thumbnails_description` shortcode clamps invalid `columns`
+ * values instead of letting them reach the template raw.
+ *
+ * Regression test: `columns="0"` (or any non-numeric value) used to fall straight
+ * through to the template, where `$index % $columns` and the width calculation
+ * throw a ModuloByZeroError/DivisionByZeroError on PHP8.
+ */
+ public function test_product_brand_thumbnails_description_shortcode_clamps_invalid_columns() {
+ $data = $this->setup_brand_test_data();
+ $brands_instance = $data['brands_instance'];
+
+ $output = $brands_instance->output_product_brand_thumbnails_description( array( 'columns' => '0' ) );
+ $this->assertStringContainsString( 'columns-1', $output, 'columns="0" should be clamped to 1' );
+
+ $output = $brands_instance->output_product_brand_thumbnails_description( array( 'columns' => 'abc' ) );
+ $this->assertStringContainsString( 'columns-1', $output, 'Non-numeric columns should fall back to 1' );
+ }
+
+ /**
+ * Test that `product_brand_thumbnails` shortcode clamps invalid `columns`
+ * values instead of letting them reach the template raw.
+ *
+ * Regression test: `columns="0"` (or any non-numeric value) used to fall straight
+ * through to the template, where modulo/width calculations throw a
+ * ModuloByZeroError/DivisionByZeroError on PHP8.
+ */
+ public function test_product_brand_thumbnails_shortcode_clamps_invalid_columns() {
+ $data = $this->setup_brand_test_data();
+ $brands_instance = $data['brands_instance'];
+
+ // columns="0" should not throw a division-by-zero error.
+ $output = $brands_instance->output_product_brand_thumbnails( array( 'columns' => '0' ) );
+ $this->assertNotEmpty( $output, 'columns="0" should not produce empty output' );
+
+ // Non-numeric columns should not throw either.
+ $output = $brands_instance->output_product_brand_thumbnails( array( 'columns' => 'abc' ) );
+ $this->assertNotEmpty( $output, 'Non-numeric columns should not produce empty output' );
+ }
+
/**
* Test that `product_brand_list` shortcode's `show_empty_brands` argument works as expected.
*/