fix: backend email rendering for new button/card syntax

ROOT CAUSE:
Frontend blocksToMarkdown outputs NEW syntax:
- [card:type]...[/card]
- [button:style](url)Text[/button]

But backend EmailRenderer.php only had regex for OLD syntax:
- [card type="..."]...[/card]
- [button url="..."]Text[/button]

FIXES:
1. parse_cards() now handles BOTH syntaxes:
   - NEW [card:type] regex first (extracts type from :type)
   - OLD [card type="..."] regex for backward compatibility

2. render_card() now handles BOTH button syntaxes:
   - NEW [button:style](url)Text[/button] regex
   - OLD [button url="..."] regex for backward compatibility

3. Card types properly styled with inline CSS:
   - hero: gradient background
   - success: green background + border
   - info: blue background + border
   - warning: yellow background + orange border

4. Buttons rendered with full inline styles + table wrapper
   for Gmail/email client compatibility
This commit is contained in:
Dwindi Ramadhana
2026-01-01 22:27:20 +07:00
parent 1af1add5d4
commit 47a1e78eb7

View File

@@ -288,22 +288,44 @@ class EmailRenderer {
* @return string
*/
private function parse_cards($content) {
// Match [card ...] ... [/card] patterns
preg_match_all('/\[card([^\]]*)\](.*?)\[\/card\]/s', $content, $matches, PREG_SET_ORDER);
$html = '';
$has_cards = false;
if (empty($matches)) {
// No cards found, wrap entire content in a single card
return $this->render_card($content, []);
// Match NEW syntax [card:type]...[/card] first
preg_match_all('/\[card:(\w+)\](.*?)\[\/card\]/s', $content, $new_matches, PREG_SET_ORDER);
if (!empty($new_matches)) {
$has_cards = true;
foreach ($new_matches as $match) {
$attributes = ['type' => $match[1]];
$card_content = $match[2];
$html .= $this->render_card($card_content, $attributes);
$html .= $this->render_card_spacing();
// Remove matched content to avoid double processing
$content = str_replace($match[0], '', $content);
}
}
$html = '';
foreach ($matches as $match) {
// Match OLD syntax [card type="..."]...[/card]
preg_match_all('/\[card([^\]]*)\](.*?)\[\/card\]/s', $content, $old_matches, PREG_SET_ORDER);
if (!empty($old_matches)) {
$has_cards = true;
foreach ($old_matches as $match) {
$attributes = $this->parse_card_attributes($match[1]);
$card_content = $match[2];
$html .= $this->render_card($card_content, $attributes);
$html .= $this->render_card_spacing();
}
}
if (!$has_cards) {
// No cards found, wrap entire content in a single card
return $this->render_card($content, []);
}
// Remove last spacing
$html = preg_replace('/<table[^>]*class="card-spacing"[^>]*>.*?<\/table>\s*$/s', '', $html);
@@ -360,14 +382,8 @@ class EmailRenderer {
$hero_text_color = $email_settings['hero_text_color'] ?? '#ffffff';
// Parse button shortcodes with FULL INLINE STYLES for Gmail compatibility
// Format: [button url="..." style="solid|outline"]Text[/button]
$content = preg_replace_callback(
'/\[button\s+url=["\']([^"\']+)["\'](?:\s+style=["\']?(solid|outline)["\']?)?\]([^\[]+)\[\/button\]/',
function($matches) use ($primary_color, $secondary_color, $button_text_color) {
$url = $matches[1];
$style = $matches[2] ?? 'solid';
$text = trim($matches[3]);
// Helper function to generate button HTML
$generateButtonHtml = function($url, $style, $text) use ($primary_color, $secondary_color, $button_text_color) {
if ($style === 'outline') {
// Outline button - transparent background with border
$button_style = sprintf(
@@ -391,6 +407,28 @@ class EmailRenderer {
$button_style,
esc_html($text)
);
};
// NEW FORMAT: [button:style](url)Text[/button]
$content = preg_replace_callback(
'/\[button:(\w+)\]\(([^)]+)\)([^\[]+)\[\/button\]/',
function($matches) use ($generateButtonHtml) {
$style = $matches[1]; // solid or outline
$url = $matches[2];
$text = trim($matches[3]);
return $generateButtonHtml($url, $style, $text);
},
$content
);
// OLD FORMAT: [button url="..." style="solid|outline"]Text[/button]
$content = preg_replace_callback(
'/\[button\s+url=["\']([^"\']+)["\'](?:\s+style=["\'](solid|outline)["\'])?\]([^\[]+)\[\/button\]/',
function($matches) use ($generateButtonHtml) {
$url = $matches[1];
$style = $matches[2] ?? 'solid';
$text = trim($matches[3]);
return $generateButtonHtml($url, $style, $text);
},
$content
);