Commit d427a0b14fa for woocommerce

commit d427a0b14fa9d7979120e939ff5c96dd2900f436
Author: Tung Du <dinhtungdu@gmail.com>
Date:   Thu Oct 15 16:21:08 2026 +0700

    Fix duplicate margins on product sale badges (#69835)

    * Fix duplicate sale badge margins

    * Add changelog entry for sale badge margins

    * Fix sale badge test expectation for fluid typography

    * chore: keep unreleased sale badge fix out of release notes

    Amp-Thread-ID: https://ampcode.com/threads/T-01a13ba5-fcda-75af-9c97-c5aa30c1eec8
    Co-authored-by: Amp <amp@ampcode.com>

    ---------

    Co-authored-by: Amp <amp@ampcode.com>

diff --git a/plugins/woocommerce/changelog/fix-sale-badge-margins b/plugins/woocommerce/changelog/fix-sale-badge-margins
new file mode 100644
index 00000000000..63faabed14c
--- /dev/null
+++ b/plugins/woocommerce/changelog/fix-sale-badge-margins
@@ -0,0 +1,3 @@
+Significance: patch
+Type: dev
+Comment: Fix duplicate sale-badge margins in an unreleased change; no release-note entry.
diff --git a/plugins/woocommerce/client/blocks/assets/js/blocks/product-elements-blocks/sale-badge/block.json b/plugins/woocommerce/client/blocks/assets/js/blocks/product-elements-blocks/sale-badge/block.json
index 56c8ea77112..d7a32671b5d 100644
--- a/plugins/woocommerce/client/blocks/assets/js/blocks/product-elements-blocks/sale-badge/block.json
+++ b/plugins/woocommerce/client/blocks/assets/js/blocks/product-elements-blocks/sale-badge/block.json
@@ -40,7 +40,8 @@
 			"__experimentalSkipSerialization": true
 		},
 		"spacing": {
-			"margin": true
+			"margin": true,
+			"__experimentalSkipSerialization": true
 		},
 		"email": true
 	},
diff --git a/plugins/woocommerce/tests/php/src/Blocks/BlockTypes/ProductSaleBadge.php b/plugins/woocommerce/tests/php/src/Blocks/BlockTypes/ProductSaleBadge.php
index 5ae476a4131..7b7af2d5ea8 100644
--- a/plugins/woocommerce/tests/php/src/Blocks/BlockTypes/ProductSaleBadge.php
+++ b/plugins/woocommerce/tests/php/src/Blocks/BlockTypes/ProductSaleBadge.php
@@ -106,6 +106,59 @@ class ProductSaleBadge extends \WP_UnitTestCase {
 		$this->assert_sale_badge_labels( $markup, $expected );
 	}

+	/**
+	 * @testdox Product Sale Badge applies margins once while preserving its inner badge styles.
+	 */
+	public function test_product_sale_badge_applies_margins_once(): void {
+		$product = \WC_Helper_Product::create_simple_product();
+		$product->set_regular_price( '20' );
+		$product->set_sale_price( '15' );
+		$product->save();
+
+		$attributes = array(
+			'style' => array(
+				'spacing'    => array(
+					'margin' => array(
+						'top'    => '32px',
+						'right'  => '16px',
+						'bottom' => '48px',
+						'left'   => '24px',
+					),
+				),
+				'color'      => array(
+					'text'       => '#123456',
+					'background' => '#abcdef',
+				),
+				'border'     => array(
+					'color'  => '#654321',
+					'width'  => '3px',
+					'radius' => '8px',
+				),
+				'typography' => array(
+					'fontSize'   => '24px',
+					'lineHeight' => '1.5',
+				),
+			),
+		);
+		$markup     = do_blocks( '<!-- wp:woocommerce/single-product {"productId":' . $product->get_id() . '} --><div class="wp-block-woocommerce-single-product woocommerce"><!-- wp:woocommerce/product-sale-badge ' . wp_json_encode( $attributes ) . ' /--></div><!-- /wp:woocommerce/single-product -->' );
+		$html       = new \WP_HTML_Tag_Processor( $markup );
+
+		$this->assertTrue( $html->next_tag( array( 'class_name' => 'wp-block-woocommerce-product-sale-badge' ) ) );
+		$this->assertStringNotContainsString( 'margin', (string) $html->get_attribute( 'style' ), 'The wrapper must not duplicate the inner badge margins.' );
+		$this->assertTrue( $html->next_tag( array( 'class_name' => 'wc-block-components-product-sale-badge' ) ) );
+		$style = str_replace( ' ', '', (string) $html->get_attribute( 'style' ) );
+
+		foreach ( $attributes['style']['spacing']['margin'] as $side => $value ) {
+			$this->assertStringContainsString( 'margin-' . $side . ':' . $value . ';', $style );
+		}
+		foreach ( array( 'color:#123456;', 'background-color:#abcdef;', 'border-color:#654321;', 'border-width:3px;', 'border-radius:8px;', 'line-height:1.5;' ) as $declaration ) {
+			$this->assertStringContainsString( $declaration, $style, 'Supported styles should remain on the inner badge.' );
+		}
+		// WordPress may resolve the custom font size to a fluid clamp() value.
+		$font_size = (string) wp_get_typography_font_size_value( array( 'size' => $attributes['style']['typography']['fontSize'] ) );
+		$this->assertStringContainsString( 'font-size:' . str_replace( ' ', '', $font_size ) . ';', $style, 'The resolved font size should remain on the inner badge.' );
+	}
+
 	/**
 	 * Sale badge content options.
 	 *