Commit 9d96517b71f for woocommerce

commit 9d96517b71faaff6f9447fb1e664aa2ea91be435
Author: Ann <annchichi@users.noreply.github.com>
Date:   Mon Aug 17 19:04:18 2026 +0800

    [Email Editor] Fix social links spacing in rendered emails (#67642)

    * Fix social links spacing in rendered emails

    * Add changelog entry for social links spacing fix

    * Add RTL coverage for social links spacing

    * Fix pill shape padding for social link sizes

    * Update social links tests to assert individual wrappers

diff --git a/packages/php/email-editor/changelog/fix-social-links-rendered-spacing b/packages/php/email-editor/changelog/fix-social-links-rendered-spacing
new file mode 100644
index 00000000000..243b3df356e
--- /dev/null
+++ b/packages/php/email-editor/changelog/fix-social-links-rendered-spacing
@@ -0,0 +1,4 @@
+Significance: patch
+Type: fix
+
+Render spacing between Social Links icons in emails and match pill-shape icon padding with the editor.
diff --git a/packages/php/email-editor/src/Integrations/Core/Renderer/Blocks/class-social-links.php b/packages/php/email-editor/src/Integrations/Core/Renderer/Blocks/class-social-links.php
index 0d883fc9970..f6ad80c5869 100644
--- a/packages/php/email-editor/src/Integrations/Core/Renderer/Blocks/class-social-links.php
+++ b/packages/php/email-editor/src/Integrations/Core/Renderer/Blocks/class-social-links.php
@@ -44,9 +44,20 @@ class Social_Links extends Abstract_Block_Renderer {

 		$inner_blocks = $parsed_block['innerBlocks'] ?? array();

-		$content = '';
+		$content                = '';
+		$is_first_rendered_link = true;
 		foreach ( $inner_blocks as $block ) {
-			$content .= $this->generate_social_link_content( $block, $attrs );
+			$social_link_content = $this->generate_social_link_content(
+				$block,
+				$attrs,
+				! $is_first_rendered_link,
+				$rendering_context->get_start_side()
+			);
+			if ( '' === $social_link_content ) {
+				continue;
+			}
+			$is_first_rendered_link = false;
+			$content               .= $social_link_content;
 		}

 		return str_replace(
@@ -59,11 +70,13 @@ class Social_Links extends Abstract_Block_Renderer {
 	/**
 	 * Generates the social link content.
 	 *
-	 * @param array $block The block data.
-	 * @param array $parent_block_attrs The parent block attributes.
+	 * @param array  $block The block data.
+	 * @param array  $parent_block_attrs The parent block attributes.
+	 * @param bool   $render_gap Whether to render a gap before the item.
+	 * @param string $gap_side The physical side used for the horizontal gap.
 	 * @return string The generated content.
 	 */
-	private function generate_social_link_content( $block, $parent_block_attrs ) {
+	private function generate_social_link_content( $block, $parent_block_attrs, bool $render_gap = false, string $gap_side = 'left' ) {
 		$service_name = $block['attrs']['service'] ?? '';
 		$service_url  = $block['attrs']['url'] ?? '';
 		$label        = $block['attrs']['label'] ?? '';
@@ -123,10 +136,11 @@ class Social_Links extends Abstract_Block_Renderer {

 		$main_table_styles = $this->compile_css(
 			array(
-				'background-color' => $icon_background_color_value,
-				'border-radius'    => '9999px',
-				'display'          => 'inline-table',
-				'float'            => 'none',
+				'background-color'    => $icon_background_color_value,
+				'border-radius'       => '9999px',
+				'display'             => 'inline-table',
+				'float'               => 'none',
+				'margin-' . $gap_side => $render_gap ? '16px' : '',
 			)
 		);

@@ -154,8 +168,9 @@ class Social_Links extends Abstract_Block_Renderer {
 		);

 		if ( $is_pill_shape ) {
-			$row_container_styles['padding-left']  = '17px';
-			$row_container_styles['padding-right'] = '17px';
+			$pill_shape_horizontal_padding         = round( $font_size_value * 2 / 3, 2 ) . 'px';
+			$row_container_styles['padding-left']  = $pill_shape_horizontal_padding;
+			$row_container_styles['padding-right'] = $pill_shape_horizontal_padding;
 		}
 		$row_container_styles = $this->compile_css( $row_container_styles );

@@ -207,7 +222,11 @@ class Social_Links extends Abstract_Block_Renderer {

 		$main_table = Table_Wrapper_Helper::render_table_wrapper( $social_link_content, $main_table_attrs, array(), $main_row_attrs, false );

-		return Table_Wrapper_Helper::render_outlook_table_cell( $main_table );
+		$outlook_cell_attrs = array(
+			'style' => $render_gap ? 'padding-' . $gap_side . ':16px;' : '',
+		);
+
+		return Table_Wrapper_Helper::render_outlook_table_cell( $main_table, $outlook_cell_attrs );
 	}

 	/**
diff --git a/packages/php/email-editor/tests/integration/Integrations/Core/Renderer/Blocks/Social_Links_Test.php b/packages/php/email-editor/tests/integration/Integrations/Core/Renderer/Blocks/Social_Links_Test.php
index 20f3e5401a4..4617b8bb377 100644
--- a/packages/php/email-editor/tests/integration/Integrations/Core/Renderer/Blocks/Social_Links_Test.php
+++ b/packages/php/email-editor/tests/integration/Integrations/Core/Renderer/Blocks/Social_Links_Test.php
@@ -119,8 +119,72 @@ class Social_Links_Test extends \Email_Editor_Integration_Test_Case {

 		$rendered = $this->social_links_renderer->render( '', $parsed_social_links, $this->rendering_context );
 		$this->checkValidHTML( $rendered );
-		$this->assertStringContainsString( 'padding-left:17px;', $rendered );
-		$this->assertStringContainsString( 'padding-right:17px;', $rendered );
+		$link_wrappers = $this->getRenderedSocialLinkWrappers( $rendered );
+		foreach ( $link_wrappers as $link_wrapper ) {
+			$this->assertStringContainsString( 'padding-left:16px;', $link_wrapper );
+			$this->assertStringContainsString( 'padding-right:16px;', $link_wrapper );
+		}
+	}
+
+	/**
+	 * Test it renders pill shape padding based on the selected icon size.
+	 */
+	public function testItRendersSocialLinksWithPillShapePaddingForDifferentSizes(): void {
+		$sizes = array(
+			'has-small-icon-size'  => '10.67px',
+			'has-normal-icon-size' => '16px',
+			'has-large-icon-size'  => '24px',
+			'has-huge-icon-size'   => '32px',
+		);
+
+		foreach ( $sizes as $size_class => $expected_padding ) {
+			$parsed_social_links                       = $this->parsed_social_links;
+			$parsed_social_links['attrs']['className'] = 'is-style-pill-shape';
+			$parsed_social_links['attrs']['size']      = $size_class;
+
+			$rendered = $this->social_links_renderer->render( '', $parsed_social_links, $this->rendering_context );
+			$this->checkValidHTML( $rendered );
+			$link_wrappers = $this->getRenderedSocialLinkWrappers( $rendered );
+			foreach ( $link_wrappers as $link_wrapper ) {
+				$this->assertStringContainsString( "padding-left:{$expected_padding};", $link_wrapper );
+				$this->assertStringContainsString( "padding-right:{$expected_padding};", $link_wrapper );
+			}
+		}
+	}
+
+	/**
+	 * Test it renders a gap between social link items.
+	 */
+	public function testItRendersGapBetweenSocialLinkItems(): void {
+		$parsed_social_links                        = $this->parsed_social_links;
+		$parsed_social_links['attrs']['className']  = '';
+		$parsed_social_links['attrs']['showLabels'] = false;
+
+		$rendered = $this->social_links_renderer->render( '', $parsed_social_links, $this->rendering_context );
+		$this->checkValidHTML( $rendered );
+		$link_wrappers = $this->getRenderedSocialLinkWrappers( $rendered );
+		$this->assertStringNotContainsString( 'margin-left:16px;', $link_wrappers['facebook'] );
+		$this->assertStringNotContainsString( 'padding-left:16px;', $link_wrappers['facebook'] );
+		$this->assertStringContainsString( 'margin-left:16px;', $link_wrappers['twitter'] );
+		$this->assertStringContainsString( 'padding-left:16px;', $link_wrappers['twitter'] );
+	}
+
+	/**
+	 * Test it renders a gap between social link items in RTL.
+	 */
+	public function testItRendersRtlGapBetweenSocialLinkItems(): void {
+		$parsed_social_links                        = $this->parsed_social_links;
+		$parsed_social_links['attrs']['className']  = '';
+		$parsed_social_links['attrs']['showLabels'] = false;
+		$rtl_rendering_context                      = new Rendering_Context( $this->rendering_context->get_theme_json(), array( 'is_rtl' => true ) );
+
+		$rendered = $this->social_links_renderer->render( '', $parsed_social_links, $rtl_rendering_context );
+		$this->checkValidHTML( $rendered );
+		$link_wrappers = $this->getRenderedSocialLinkWrappers( $rendered );
+		$this->assertStringNotContainsString( 'margin-right:16px;', $link_wrappers['facebook'] );
+		$this->assertStringNotContainsString( 'padding-right:16px;', $link_wrappers['facebook'] );
+		$this->assertStringContainsString( 'margin-right:16px;', $link_wrappers['twitter'] );
+		$this->assertStringContainsString( 'padding-right:16px;', $link_wrappers['twitter'] );
 	}

 	/**
@@ -216,4 +280,49 @@ class Social_Links_Test extends \Email_Editor_Integration_Test_Case {
 		$non_existing_service_icon_url = $this->social_links_renderer->get_service_icon_url( 'non-existing-service' );
 		$this->assertEquals( '', $non_existing_service_icon_url );
 	}
+
+	/**
+	 * Gets the rendered wrapper fragment for each social link.
+	 *
+	 * @param string $rendered The rendered social links block.
+	 * @return array<string, string>
+	 */
+	private function getRenderedSocialLinkWrappers( string $rendered ): array {
+		$urls = array(
+			'facebook' => 'https://facebook.com',
+			'twitter'  => 'https://twitter.com',
+		);
+
+		$wrapper_starts = array();
+		foreach ( $urls as $service => $url ) {
+			$url_position = strpos( $rendered, 'href="' . $url . '"' );
+			if ( false === $url_position ) {
+				$this->fail( sprintf( 'Expected to find rendered %s social link.', $service ) );
+			}
+
+			$content_before_url = substr( $rendered, 0, $url_position );
+			$wrapper_start      = strrpos( $content_before_url, '<!--[if mso | IE]><td' );
+			if ( false === $wrapper_start ) {
+				$this->fail( sprintf( 'Expected to find rendered %s social link wrapper.', $service ) );
+			}
+
+			$wrapper_starts[ $service ] = $wrapper_start;
+		}
+
+		asort( $wrapper_starts );
+
+		$link_wrappers    = array();
+		$ordered_services = array_keys( $wrapper_starts );
+		foreach ( $ordered_services as $index => $service ) {
+			$wrapper_start = $wrapper_starts[ $service ];
+			$next_service  = $ordered_services[ $index + 1 ] ?? null;
+			$wrapper_end   = null === $next_service ? strlen( $rendered ) : $wrapper_starts[ $next_service ];
+
+			$link_wrappers[ $service ] = substr( $rendered, $wrapper_start, $wrapper_end - $wrapper_start );
+		}
+
+		$this->assertCount( 2, $link_wrappers );
+
+		return $link_wrappers;
+	}
 }