Commit 043817bfd02 for woocommerce

commit 043817bfd0222d8158cf24eafa86630e9a75408c
Author: Pavel Dohnal <pavel.dohnal@automattic.com>
Date:   Tue Mar 24 15:25:38 2026 +0100

    Email Editor: Fix double margin-top in flex layout and list block rendering (#63790)

    * Email Editor: Fix double margin-top in flex layout and list block rendering

    Both Flex_Layout_Renderer and List_Block applied margin-top inside
    render_content(), duplicating the margin already applied by
    add_spacer() in Abstract_Block_Renderer::render(). This resulted
    in 2x the intended gap above buttons and list blocks in rendered emails.

    * Add changefile(s) from automation for the following project(s): packages/php/email-editor

    * Email Editor: Fix double margin-top in rendered emails

    Flex_Layout_Renderer and List_Block apply margin-top on inner elements
    where Gmail preserves it. The parent add_spacer() was applying the same
    margin-top on the outer wrapper, which Gmail strips — but other clients
    rendered both, doubling the gap.

    Override render() in Buttons and List_Block to unset margin-top from
    email_attrs before passing to add_spacer(), keeping the inner margin
    as the single effective source.

    * Restore missing docblock on render_content()

    * Fix lint: capitalize doc comment long description

    * Remove duplicate docblock and add integration tests

    Remove stacked docblock on render_content() in Buttons. Add integration
    tests for Buttons and List_Block verifying that margin-top appears on
    the inner element but not on the outer email-block-layout wrapper.

    ---------

    Co-authored-by: woocommercebot <woocommercebot@users.noreply.github.com>

diff --git a/packages/php/email-editor/changelog/63790-wooprd-3077-fix-double-top-margin-in-flex-layout-rendering b/packages/php/email-editor/changelog/63790-wooprd-3077-fix-double-top-margin-in-flex-layout-rendering
new file mode 100644
index 00000000000..f5e7ce30776
--- /dev/null
+++ b/packages/php/email-editor/changelog/63790-wooprd-3077-fix-double-top-margin-in-flex-layout-rendering
@@ -0,0 +1,4 @@
+Significance: patch
+Type: fix
+
+Fix double margin-top applied to buttons and list blocks in rendered emails.
\ No newline at end of file
diff --git a/packages/php/email-editor/src/Integrations/Core/Renderer/Blocks/class-buttons.php b/packages/php/email-editor/src/Integrations/Core/Renderer/Blocks/class-buttons.php
index 3d65ce68724..49c644b62e2 100644
--- a/packages/php/email-editor/src/Integrations/Core/Renderer/Blocks/class-buttons.php
+++ b/packages/php/email-editor/src/Integrations/Core/Renderer/Blocks/class-buttons.php
@@ -33,6 +33,25 @@ class Buttons extends Abstract_Block_Renderer {
 		$this->flex_layout_renderer = $flex_layout_renderer;
 	}

+	/**
+	 * Render the block.
+	 *
+	 * Flex_Layout_Renderer applies margin-top on its inner div/td where Gmail
+	 * preserves it. Strip margin-top from email_attrs so add_spacer() doesn't
+	 * apply it again on the outer wrapper (which Gmail ignores).
+	 *
+	 * @param string            $block_content The block content.
+	 * @param array             $parsed_block The parsed block.
+	 * @param Rendering_Context $rendering_context The rendering context.
+	 * @return string
+	 */
+	public function render( string $block_content, array $parsed_block, Rendering_Context $rendering_context ): string {
+		$content     = $this->render_content( $block_content, $parsed_block, $rendering_context );
+		$email_attrs = $parsed_block['email_attrs'] ?? array();
+		unset( $email_attrs['margin-top'] );
+		return $this->add_spacer( $content, $email_attrs );
+	}
+
 	/**
 	 * Renders the block content.
 	 *
diff --git a/packages/php/email-editor/src/Integrations/Core/Renderer/Blocks/class-list-block.php b/packages/php/email-editor/src/Integrations/Core/Renderer/Blocks/class-list-block.php
index 1f97fdd4696..ae414ce2cab 100644
--- a/packages/php/email-editor/src/Integrations/Core/Renderer/Blocks/class-list-block.php
+++ b/packages/php/email-editor/src/Integrations/Core/Renderer/Blocks/class-list-block.php
@@ -16,6 +16,25 @@ use Automattic\WooCommerce\EmailEditor\Integrations\Utils\Styles_Helper;
  * We have to avoid using keyword `List`
  */
 class List_Block extends Abstract_Block_Renderer {
+	/**
+	 * Render the block.
+	 *
+	 * The render_content() method applies margin-top on its inner wrapper div
+	 * where Gmail preserves it. Strip margin-top from email_attrs so
+	 * add_spacer() doesn't apply it again on the outer wrapper.
+	 *
+	 * @param string            $block_content The block content.
+	 * @param array             $parsed_block The parsed block.
+	 * @param Rendering_Context $rendering_context The rendering context.
+	 * @return string
+	 */
+	public function render( string $block_content, array $parsed_block, Rendering_Context $rendering_context ): string {
+		$content     = $this->render_content( $block_content, $parsed_block, $rendering_context );
+		$email_attrs = $parsed_block['email_attrs'] ?? array();
+		unset( $email_attrs['margin-top'] );
+		return $this->add_spacer( $content, $email_attrs );
+	}
+
 	/**
 	 * Renders the block content
 	 *
diff --git a/packages/php/email-editor/tests/integration/Engine/Renderer/ContentRenderer/Layout/Flex_Layout_Renderer_Test.php b/packages/php/email-editor/tests/integration/Engine/Renderer/ContentRenderer/Layout/Flex_Layout_Renderer_Test.php
index bc8653d7cc6..01857f96882 100644
--- a/packages/php/email-editor/tests/integration/Engine/Renderer/ContentRenderer/Layout/Flex_Layout_Renderer_Test.php
+++ b/packages/php/email-editor/tests/integration/Engine/Renderer/ContentRenderer/Layout/Flex_Layout_Renderer_Test.php
@@ -96,6 +96,25 @@ class Flex_Layout_Renderer_Test extends \Email_Editor_Integration_Test_Case {
 		$this->assertStringContainsString( 'align="center"', $output );
 	}

+	/**
+	 * Test it applies margin-top from email_attrs on the inner div for Gmail compatibility.
+	 */
+	public function testItAppliesMarginTopFromEmailAttrs(): void {
+		$parsed_block = array(
+			'innerBlocks' => array(
+				array(
+					'blockName' => 'dummy/block',
+					'innerHTML' => 'Dummy 1',
+				),
+			),
+			'email_attrs' => array(
+				'margin-top' => '16px',
+			),
+		);
+		$output       = $this->renderer->render_inner_blocks_in_layout( $parsed_block, $this->rendering_context );
+		$this->assertStringContainsString( 'margin-top: 16px', $output );
+	}
+
 	/**
 	 * Test it escapes attributes.
 	 */
diff --git a/packages/php/email-editor/tests/integration/Integrations/Core/Renderer/Blocks/Buttons_Test.php b/packages/php/email-editor/tests/integration/Integrations/Core/Renderer/Blocks/Buttons_Test.php
new file mode 100644
index 00000000000..1bfd5b16e61
--- /dev/null
+++ b/packages/php/email-editor/tests/integration/Integrations/Core/Renderer/Blocks/Buttons_Test.php
@@ -0,0 +1,92 @@
+<?php
+/**
+ * This file is part of the WooCommerce Email Editor package
+ *
+ * @package Automattic\WooCommerce\EmailEditor
+ */
+
+declare(strict_types = 1);
+namespace Automattic\WooCommerce\EmailEditor\Integrations\Core\Renderer\Blocks;
+
+use Automattic\WooCommerce\EmailEditor\Engine\Renderer\ContentRenderer\Dummy_Block_Renderer;
+use Automattic\WooCommerce\EmailEditor\Engine\Renderer\ContentRenderer\Layout\Flex_Layout_Renderer;
+use Automattic\WooCommerce\EmailEditor\Engine\Renderer\ContentRenderer\Rendering_Context;
+use Automattic\WooCommerce\EmailEditor\Engine\Theme_Controller;
+
+require_once __DIR__ . '/../../../../Engine/Renderer/ContentRenderer/Dummy_Block_Renderer.php';
+
+/**
+ * Integration test for Buttons class
+ */
+class Buttons_Test extends \Email_Editor_Integration_Test_Case {
+	/**
+	 * Buttons renderer instance.
+	 *
+	 * @var Buttons
+	 */
+	private $buttons_renderer;
+
+	/**
+	 * Rendering context instance.
+	 *
+	 * @var Rendering_Context
+	 */
+	private $rendering_context;
+
+	/**
+	 * Set up before each test.
+	 */
+	public function setUp(): void {
+		parent::setUp();
+		$theme_controller        = $this->di_container->get( Theme_Controller::class );
+		$this->rendering_context = new Rendering_Context( $theme_controller->get_theme() );
+		$this->buttons_renderer  = new Buttons( new Flex_Layout_Renderer() );
+		register_block_type( 'dummy/block', array() );
+		add_filter( 'render_block', array( $this, 'renderDummyBlock' ), 10, 2 );
+	}
+
+	/**
+	 * Test it does not double margin-top between flex renderer and add_spacer().
+	 */
+	public function testItDoesNotDoubleMarginTop(): void {
+		$parsed_block = array(
+			'blockName'   => 'core/buttons',
+			'attrs'       => array(),
+			'innerBlocks' => array(
+				array(
+					'blockName' => 'dummy/block',
+					'innerHTML' => 'Click me',
+				),
+			),
+			'email_attrs' => array(
+				'margin-top' => '20px',
+			),
+		);
+		$rendered     = $this->buttons_renderer->render( '', $parsed_block, $this->rendering_context );
+		// The inner flex div has margin-top (for Gmail).
+		$this->assertStringContainsString( 'margin-top: 20px', $rendered );
+		// The outer email-block-layout wrapper should not have margin-top.
+		$this->assertStringNotContainsString( 'email-block-layout" style="margin-top', $rendered );
+	}
+
+	/**
+	 * Render a dummy block.
+	 *
+	 * @param string $block_content Block content.
+	 * @param array  $parsed_block Parsed block data.
+	 * @return string
+	 */
+	public function renderDummyBlock( $block_content, $parsed_block ): string {
+		$dummy_renderer = new Dummy_Block_Renderer();
+		return $dummy_renderer->render( $block_content, $parsed_block, $this->rendering_context );
+	}
+
+	/**
+	 * Clean up after each test.
+	 */
+	public function tearDown(): void {
+		parent::tearDown();
+		unregister_block_type( 'dummy/block' );
+		remove_filter( 'render_block', array( $this, 'renderDummyBlock' ), 10 );
+	}
+}
diff --git a/packages/php/email-editor/tests/integration/Integrations/Core/Renderer/Blocks/List_Block_Test.php b/packages/php/email-editor/tests/integration/Integrations/Core/Renderer/Blocks/List_Block_Test.php
index 188686c79c4..86cea83b0b6 100644
--- a/packages/php/email-editor/tests/integration/Integrations/Core/Renderer/Blocks/List_Block_Test.php
+++ b/packages/php/email-editor/tests/integration/Integrations/Core/Renderer/Blocks/List_Block_Test.php
@@ -100,6 +100,20 @@ class List_Block_Test extends \Email_Editor_Integration_Test_Case {
 		$this->assertStringContainsString( 'font-size:20px;', $rendered );
 	}

+	/**
+	 * Test it does not double margin-top between render_content() and add_spacer().
+	 */
+	public function testItDoesNotDoubleMarginTop(): void {
+		$parsed_list                = $this->parsed_list;
+		$parsed_list['email_attrs'] = array(
+			'margin-top' => '20px',
+		);
+		$rendered                   = $this->list_renderer->render( '<ul><li>Item 1</li></ul>', $parsed_list, $this->rendering_context );
+		$this->assertStringContainsString( 'margin-top:20px', $rendered );
+		// The inner wrapper div has margin-top, but the outer email-block-layout should not.
+		$this->assertStringNotContainsString( 'email-block-layout" style="margin-top', $rendered );
+	}
+
 	/**
 	 * Test it preserves custom set colors
 	 */