Commit d28cce04ad6 for woocommerce
commit d28cce04ad67dc1aced28d5708098076d5bf0c75
Author: Lazizbek Ergashev <lazerg2@gmail.com>
Date: Mon Nov 2 19:38:04 2026 +0500
[Email Editor] Keep text blocks whose only content is a personalization tag (#70454)
* [Email Editor] Keep text blocks whose only content is a personalization tag
* Accept closing brackets in quoted personalization tag attributes
diff --git a/packages/php/email-editor/changelog/fix-70318-text-block-personalization-tag b/packages/php/email-editor/changelog/fix-70318-text-block-personalization-tag
new file mode 100644
index 00000000000..fd04633a8bb
--- /dev/null
+++ b/packages/php/email-editor/changelog/fix-70318-text-block-personalization-tag
@@ -0,0 +1,4 @@
+Significance: patch
+Type: fix
+
+Keep paragraphs and headings in emails when their only content is a personalization tag.
diff --git a/packages/php/email-editor/src/Integrations/Core/Renderer/Blocks/class-text.php b/packages/php/email-editor/src/Integrations/Core/Renderer/Blocks/class-text.php
index 710f69845b7..eef2528fc59 100644
--- a/packages/php/email-editor/src/Integrations/Core/Renderer/Blocks/class-text.php
+++ b/packages/php/email-editor/src/Integrations/Core/Renderer/Blocks/class-text.php
@@ -27,7 +27,7 @@ class Text extends Abstract_Block_Renderer {
*/
protected function render_content( string $block_content, array $parsed_block, Rendering_Context $rendering_context ): string {
// Do not render empty blocks.
- if ( empty( trim( wp_strip_all_tags( $block_content ) ) ) ) {
+ if ( empty( trim( wp_strip_all_tags( $block_content ) ) ) && ! $this->has_personalization_tag( $block_content ) ) {
return '';
}
@@ -98,6 +98,21 @@ class Text extends Abstract_Block_Renderer {
return Table_Wrapper_Helper::render_table_wrapper( $block_content, $table_attrs, $cell_attrs );
}
+ /**
+ * Checks whether the content contains a personalization tag, e.g. <!--[woocommerce/customer-first-name]-->.
+ *
+ * @param string $block_content Block content.
+ */
+ private function has_personalization_tag( string $block_content ): bool {
+ $html = new \WP_HTML_Tag_Processor( $block_content );
+ while ( $html->next_token() ) {
+ if ( '#comment' === $html->get_token_type() && preg_match( '/^\[[a-zA-Z0-9\-\/]+(?:\s+.*)?\]$/s', trim( $html->get_modifiable_text() ) ) ) {
+ return true;
+ }
+ }
+ return false;
+ }
+
/**
* 1) We need to remove padding because we render padding on wrapping table cell
* 2) We also need to replace font-size to avoid clamp() because clamp() is not supported in many email clients.
diff --git a/packages/php/email-editor/tests/integration/Integrations/Core/Renderer/Blocks/Heading_Test.php b/packages/php/email-editor/tests/integration/Integrations/Core/Renderer/Blocks/Heading_Test.php
index b9114b150b6..533f0391346 100644
--- a/packages/php/email-editor/tests/integration/Integrations/Core/Renderer/Blocks/Heading_Test.php
+++ b/packages/php/email-editor/tests/integration/Integrations/Core/Renderer/Blocks/Heading_Test.php
@@ -70,6 +70,14 @@ class Heading_Test extends \Email_Editor_Integration_Test_Case {
$this->rendering_context = new Rendering_Context( $theme_controller->get_theme() );
}
+ /**
+ * Test it renders a heading that only contains a personalization tag
+ */
+ public function testItRendersHeadingWithOnlyPersonalizationTag(): void {
+ $rendered = $this->heading_renderer->render( '<h1><!--[woocommerce/customer-first-name]--></h1>', $this->parsed_heading, $this->rendering_context );
+ $this->assertStringContainsString( '<!--[woocommerce/customer-first-name]-->', $rendered );
+ }
+
/**
* Test it renders content
*/
diff --git a/packages/php/email-editor/tests/integration/Integrations/Core/Renderer/Blocks/Paragraph_Test.php b/packages/php/email-editor/tests/integration/Integrations/Core/Renderer/Blocks/Paragraph_Test.php
index f48bc024238..10d40a07d69 100644
--- a/packages/php/email-editor/tests/integration/Integrations/Core/Renderer/Blocks/Paragraph_Test.php
+++ b/packages/php/email-editor/tests/integration/Integrations/Core/Renderer/Blocks/Paragraph_Test.php
@@ -74,6 +74,34 @@ class Paragraph_Test extends \Email_Editor_Integration_Test_Case {
$this->assertStringContainsString( 'align="left"', $rendered ); // Check the default align.
}
+ /**
+ * Test it renders a paragraph that only contains a personalization tag
+ */
+ public function testItRendersParagraphWithOnlyPersonalizationTag(): void {
+ $content = '<p><!--[woocommerce/customer-first-name]--></p>';
+ $rendered = $this->paragraph_renderer->render( $content, $this->parsed_paragraph, $this->rendering_context );
+ $this->assertStringContainsString( '<!--[woocommerce/customer-first-name]-->', $rendered );
+
+ $content = "<p>\n\t<!--[woocommerce/customer-first-name default=\"there\"]--> </p>";
+ $rendered = $this->paragraph_renderer->render( $content, $this->parsed_paragraph, $this->rendering_context );
+ $this->assertStringContainsString( '<!--[woocommerce/customer-first-name default="there"]-->', $rendered );
+
+ $content = '<p><!--[woocommerce/customer-first-name default="[guest]"]--></p>';
+ $rendered = $this->paragraph_renderer->render( $content, $this->parsed_paragraph, $this->rendering_context );
+ $this->assertStringContainsString( '<!--[woocommerce/customer-first-name default="[guest]"]-->', $rendered );
+ }
+
+ /**
+ * Test it does not render an empty paragraph
+ */
+ public function testItDoesNotRenderEmptyParagraph(): void {
+ $rendered = $this->paragraph_renderer->render( '<p> </p>', $this->parsed_paragraph, $this->rendering_context );
+ $this->assertStringNotContainsString( 'email-text-block', $rendered );
+
+ $rendered = $this->paragraph_renderer->render( '<p><!-- comment --></p>', $this->parsed_paragraph, $this->rendering_context );
+ $this->assertStringNotContainsString( 'email-text-block', $rendered );
+ }
+
/**
* Test it uses RTL default alignment when alignment is absent.
*/