From 1225d7b0ff9be961b80014464ca2bf39990b4d04 Mon Sep 17 00:00:00 2001 From: dwindown Date: Tue, 18 Nov 2025 21:46:06 +0700 Subject: [PATCH] fix: Email rendering - newlines, hero text color, and card borders MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 🐛 Three Critical Email Issues Fixed: 1. Newlines Not Working ❌ "Order Number: #359 Order Total: Rp129.000" on same line ✅ Fixed by adding
for line continuations in paragraphs Key change in MarkdownParser.php: - Accumulate paragraph content with
between lines - Match TypeScript behavior exactly - Protect variables from markdown parsing Before: $paragraph_content = $trimmed; After: if ($paragraph_content) { $paragraph_content .= '
' . $trimmed; } else { $paragraph_content = $trimmed; } 2. Hero Card Text Color ❌ Heading black instead of white in Gmail ✅ Add inline color styles to all headings/paragraphs Problem: Gmail doesn't inherit color from parent Solution: Add style="color: white;" to each element $content = preg_replace( '/<(h[1-6]|p)([^>]*)>/', '<$1$2 style="color: ' . $hero_text_color . ';">', $content ); 3. Blue Border on Cards ❌ Unwanted blue border in Gmail (screenshot 2) ✅ Removed borders from .card-info, .card-warning, .card-success Problem: CSS template had borders Solution: Removed border declarations Before: .card-info { border: 1px solid #0071e3; } After: .card-info { background-color: #f0f7ff; } �� Additional Improvements: - Variable protection during markdown parsing - Don't match bold/italic across newlines - Proper list handling - Block-level tag detection - Paragraph accumulation with line breaks 🎯 Result: - ✅ Proper line breaks in paragraphs - ✅ White text in hero cards (Gmail compatible) - ✅ No unwanted borders - ✅ Variables preserved during parsing - ✅ Professional email appearance Test: Create order, check email - should now show: - Order Number: #359 - Order Total: Rp129.000 - Estimated Delivery: 3-5 business days (Each on separate line with proper spacing) --- includes/Core/Notifications/EmailRenderer.php | 7 ++ .../Core/Notifications/MarkdownParser.php | 97 ++++++++++++++----- templates/emails/base.html | 3 - 3 files changed, 81 insertions(+), 26 deletions(-) diff --git a/includes/Core/Notifications/EmailRenderer.php b/includes/Core/Notifications/EmailRenderer.php index 95a5452..0e69fa0 100644 --- a/includes/Core/Notifications/EmailRenderer.php +++ b/includes/Core/Notifications/EmailRenderer.php @@ -311,6 +311,13 @@ class EmailRenderer { esc_attr($hero_gradient_end) ); $content_style .= sprintf(' color: %s;', esc_attr($hero_text_color)); + + // Add inline color to all headings and paragraphs for email client compatibility + $content = preg_replace( + '/<(h[1-6]|p)([^>]*)>/', + '<$1$2 style="color: ' . esc_attr($hero_text_color) . ';">', + $content + ); } } diff --git a/includes/Core/Notifications/MarkdownParser.php b/includes/Core/Notifications/MarkdownParser.php index a53e62b..20512ce 100644 --- a/includes/Core/Notifications/MarkdownParser.php +++ b/includes/Core/Notifications/MarkdownParser.php @@ -71,59 +71,110 @@ class MarkdownParser { private static function parse_basics($text) { $html = $text; + // Protect variables from markdown parsing by temporarily replacing them + $variables = []; + $var_index = 0; + $html = preg_replace_callback('/\{([^}]+)\}/', function($matches) use (&$variables, &$var_index) { + $placeholder = ''; + $variables[$placeholder] = $matches[0]; + $var_index++; + return $placeholder; + }, $html); + // Headings (must be done in order from h4 to h1 to avoid conflicts) $html = preg_replace('/^#### (.*)$/m', '

$1

', $html); $html = preg_replace('/^### (.*)$/m', '

$1

', $html); $html = preg_replace('/^## (.*)$/m', '

$1

', $html); $html = preg_replace('/^# (.*)$/m', '

$1

', $html); - // Bold - $html = preg_replace('/\*\*(.*?)\*\*/s', '$1', $html); - $html = preg_replace('/__(.*?)__/s', '$1', $html); + // Bold (don't match across newlines) + $html = preg_replace('/\*\*([^\n*]+?)\*\*/', '$1', $html); + $html = preg_replace('/__([^\n_]+?)__/', '$1', $html); - // Italic - $html = preg_replace('/\*([^\*]+?)\*/', '$1', $html); - $html = preg_replace('/_([^_]+?)_/', '$1', $html); + // Italic (don't match across newlines) + $html = preg_replace('/\*([^\n*]+?)\*/', '$1', $html); + $html = preg_replace('/_([^\n_]+?)_/', '$1', $html); + + // Horizontal rules + $html = preg_replace('/^---$/m', '
', $html); // Links (but not button syntax) $html = preg_replace('/\[(?!button)([^\]]+)\]\(([^)]+)\)/', '$1', $html); - // Unordered lists (including checkmarks and bullets) - $html = preg_replace('/^[\*\-•✓✔] (.*)$/m', '
  • $1
  • ', $html); - - // Wrap consecutive
  • in '; + $in_list = false; + } + $close_paragraph(); $processed_lines[] = ''; continue; } - // Skip lines that are already HTML tags or shortcodes - if (preg_match('/^'; + $in_list = true; + } + $processed_lines[] = '
  • ' . $content . '
  • '; + continue; + } + + // Close list if we're in one + if ($in_list) { + $processed_lines[] = ''; + $in_list = false; + } + + // Block-level HTML tags - don't wrap in paragraph + if (preg_match('/^<(div|h1|h2|h3|h4|h5|h6|p|ul|ol|li|hr|table|blockquote)/i', $trimmed)) { + $close_paragraph(); $processed_lines[] = $line; continue; } - // Wrap in paragraph - $processed_lines[] = '

    ' . $line . '

    '; + // Regular text line - accumulate in paragraph + if ($paragraph_content) { + // Add line break before continuation (THIS IS THE KEY FIX!) + $paragraph_content .= '
    ' . $trimmed; + } else { + // Start new paragraph + $paragraph_content = $trimmed; + } } + // Close any open tags + if ($in_list) { + $processed_lines[] = ''; + } + $close_paragraph(); + $html = implode("\n", $processed_lines); - // Clean up extra newlines in HTML - $html = preg_replace('/\n{3,}/', "\n\n", $html); + // Restore variables + foreach ($variables as $placeholder => $original) { + $html = str_replace($placeholder, $original, $html); + } return $html; } diff --git a/templates/emails/base.html b/templates/emails/base.html index 434cdde..19e1f89 100644 --- a/templates/emails/base.html +++ b/templates/emails/base.html @@ -99,17 +99,14 @@ .card-info { background-color: #f0f7ff; - border: 1px solid #0071e3; } .card-warning { background-color: #fff8e1; - border: 1px solid #ff9800; } .card-success { background-color: #e8f5e9; - border: 1px solid #4caf50; } .card-bg {