fix: resolve container width issues, spa redirects, and appearance settings overwrite. feat: enhance order/sub details and newsletter layout
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Markdown to Email HTML Parser
|
||||
*
|
||||
@@ -17,21 +18,23 @@
|
||||
|
||||
namespace WooNooW\Core\Notifications;
|
||||
|
||||
class MarkdownParser {
|
||||
|
||||
class MarkdownParser
|
||||
{
|
||||
|
||||
/**
|
||||
* Parse markdown to email HTML
|
||||
*
|
||||
* @param string $markdown
|
||||
* @return string
|
||||
*/
|
||||
public static function parse($markdown) {
|
||||
public static function parse($markdown)
|
||||
{
|
||||
$html = $markdown;
|
||||
|
||||
|
||||
// Parse card blocks first (:::card or :::card[type])
|
||||
$html = preg_replace_callback(
|
||||
'/:::card(?:\[(\w+)\])?\n([\s\S]*?):::/s',
|
||||
function($matches) {
|
||||
function ($matches) {
|
||||
$type = $matches[1] ?? '';
|
||||
$content = trim($matches[2]);
|
||||
$parsed_content = self::parse_basics($content);
|
||||
@@ -39,12 +42,12 @@ class MarkdownParser {
|
||||
},
|
||||
$html
|
||||
);
|
||||
|
||||
|
||||
// Parse button blocks [button url="..."]Text[/button] - already in correct format
|
||||
// Also support legacy [button](url){text} syntax
|
||||
$html = preg_replace_callback(
|
||||
'/\[button(?:\s+style="(solid|outline)")?\]\((.*?)\)\s*\{([^}]+)\}/',
|
||||
function($matches) {
|
||||
function ($matches) {
|
||||
$style = $matches[1] ?? '';
|
||||
$url = $matches[2];
|
||||
$text = $matches[3];
|
||||
@@ -52,71 +55,88 @@ class MarkdownParser {
|
||||
},
|
||||
$html
|
||||
);
|
||||
|
||||
|
||||
// Horizontal rules
|
||||
$html = preg_replace('/^---$/m', '<hr>', $html);
|
||||
|
||||
|
||||
// Parse remaining markdown (outside cards)
|
||||
$html = self::parse_basics($html);
|
||||
|
||||
|
||||
return $html;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Parse basic markdown syntax
|
||||
*
|
||||
* @param string $text
|
||||
* @return string
|
||||
*/
|
||||
private static function parse_basics($text) {
|
||||
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) {
|
||||
$html = preg_replace_callback('/\{([^}]+)\}/', function ($matches) use (&$variables, &$var_index) {
|
||||
$placeholder = '<!--VAR' . $var_index . '-->';
|
||||
$variables[$placeholder] = $matches[0];
|
||||
$var_index++;
|
||||
return $placeholder;
|
||||
}, $html);
|
||||
|
||||
|
||||
// Protect existing HTML tags (h1-h6, p) with style attributes from being overwritten
|
||||
$html_tags = [];
|
||||
$tag_index = 0;
|
||||
$html = preg_replace_callback('/<(h[1-6]|p)([^>]*style=[^>]*)>/', function ($matches) use (&$html_tags, &$tag_index) {
|
||||
$placeholder = '<!--HTMLTAG' . $tag_index . '-->';
|
||||
$html_tags[$placeholder] = $matches[0];
|
||||
$tag_index++;
|
||||
return $placeholder;
|
||||
}, $html);
|
||||
|
||||
// Headings (must be done in order from h4 to h1 to avoid conflicts)
|
||||
// Only match markdown syntax (lines starting with #), not existing HTML
|
||||
$html = preg_replace('/^#### (.*)$/m', '<h4>$1</h4>', $html);
|
||||
$html = preg_replace('/^### (.*)$/m', '<h3>$1</h3>', $html);
|
||||
$html = preg_replace('/^## (.*)$/m', '<h2>$1</h2>', $html);
|
||||
$html = preg_replace('/^# (.*)$/m', '<h1>$1</h1>', $html);
|
||||
|
||||
|
||||
// Restore protected HTML tags
|
||||
foreach ($html_tags as $placeholder => $original) {
|
||||
$html = str_replace($placeholder, $original, $html);
|
||||
}
|
||||
|
||||
// Bold (don't match across newlines)
|
||||
$html = preg_replace('/\*\*([^\n*]+?)\*\*/', '<strong>$1</strong>', $html);
|
||||
$html = preg_replace('/__([^\n_]+?)__/', '<strong>$1</strong>', $html);
|
||||
|
||||
|
||||
// Italic (don't match across newlines)
|
||||
$html = preg_replace('/\*([^\n*]+?)\*/', '<em>$1</em>', $html);
|
||||
$html = preg_replace('/_([^\n_]+?)_/', '<em>$1</em>', $html);
|
||||
|
||||
|
||||
// Horizontal rules
|
||||
$html = preg_replace('/^---$/m', '<hr>', $html);
|
||||
|
||||
|
||||
// Links (but not button syntax)
|
||||
$html = preg_replace('/\[(?!button)([^\]]+)\]\(([^)]+)\)/', '<a href="$2">$1</a>', $html);
|
||||
|
||||
|
||||
// Process lines for paragraphs and lists
|
||||
$lines = explode("\n", $html);
|
||||
$in_list = false;
|
||||
$paragraph_content = '';
|
||||
$processed_lines = [];
|
||||
|
||||
$close_paragraph = function() use (&$paragraph_content, &$processed_lines) {
|
||||
|
||||
$close_paragraph = function () use (&$paragraph_content, &$processed_lines) {
|
||||
if ($paragraph_content) {
|
||||
$processed_lines[] = '<p>' . $paragraph_content . '</p>';
|
||||
$paragraph_content = '';
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
foreach ($lines as $line) {
|
||||
$trimmed = trim($line);
|
||||
|
||||
|
||||
// Empty line - close paragraph or list
|
||||
if (empty($trimmed)) {
|
||||
if ($in_list) {
|
||||
@@ -127,7 +147,7 @@ class MarkdownParser {
|
||||
$processed_lines[] = '';
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
// Check if line is a list item
|
||||
if (preg_match('/^[\*\-•✓✔]\s/', $trimmed)) {
|
||||
$close_paragraph();
|
||||
@@ -139,20 +159,20 @@ class MarkdownParser {
|
||||
$processed_lines[] = '<li>' . $content . '</li>';
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
// Close list if we're in one
|
||||
if ($in_list) {
|
||||
$processed_lines[] = '</ul>';
|
||||
$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;
|
||||
}
|
||||
|
||||
|
||||
// Regular text line - accumulate in paragraph
|
||||
if ($paragraph_content) {
|
||||
// Add line break before continuation (THIS IS THE KEY FIX!)
|
||||
@@ -162,30 +182,31 @@ class MarkdownParser {
|
||||
$paragraph_content = $trimmed;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Close any open tags
|
||||
if ($in_list) {
|
||||
$processed_lines[] = '</ul>';
|
||||
}
|
||||
$close_paragraph();
|
||||
|
||||
|
||||
$html = implode("\n", $processed_lines);
|
||||
|
||||
|
||||
// Restore variables
|
||||
foreach ($variables as $placeholder => $original) {
|
||||
$html = str_replace($placeholder, $original, $html);
|
||||
}
|
||||
|
||||
|
||||
return $html;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Convert newlines to <br> tags for email rendering
|
||||
*
|
||||
* @param string $html
|
||||
* @return string
|
||||
*/
|
||||
public static function nl2br_email($html) {
|
||||
public static function nl2br_email($html)
|
||||
{
|
||||
// Don't convert newlines inside HTML tags
|
||||
$html = preg_replace('/(?<!>)\n(?!<)/', '<br>', $html);
|
||||
return $html;
|
||||
|
||||
Reference in New Issue
Block a user