Skip to content

Commit 75416e5

Browse files
authored
Merge pull request NeoRazorX#1918 from daniel89fg/shortcodes-email
Añadir soporte para shortcodes de bloques en la clase NewMail
2 parents cf9b974 + f7984a7 commit 75416e5

2 files changed

Lines changed: 135 additions & 49 deletions

File tree

Core/Lib/Email/MailNotifier.php

Lines changed: 0 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,6 @@ public static function send(string $notificationName, string $email, string $nam
8383
$newMail->to($email, $name);
8484
$newMail->title = static::getText($notification->subject, $params);
8585
$newMail->text = static::getText($notification->body, $params);
86-
static::replaceTextToBlock($newMail, $params);
8786

8887
foreach ($mainBlocks as $block) {
8988
$newMail->addMainBlock($block);
@@ -100,52 +99,4 @@ public static function send(string $notificationName, string $email, string $nam
10099
return $newMail->send();
101100
}
102101

103-
/**
104-
* Los bloques se añaden al campo de params como 'block1', 'block2', ...
105-
* Cada bloque se compone de un string o de un objeto que herede de BaseBlock.
106-
* El texto del email puede contener {block1}, {block2}, ... Para indicar
107-
* dónde se debe insertar cada bloque. Si no se encuentra la etiqueta, el bloque
108-
* se añade al final del email.
109-
*/
110-
protected static function replaceTextToBlock(DinNewMail &$newMail, array $params): void
111-
{
112-
// si no hay parámetros o texto, no hacemos nada
113-
if (empty($params) || empty($newMail->text)) {
114-
return;
115-
}
116-
117-
// Obtenemos las coincidencias de {block1}, {block2}, ... sobre el texto
118-
preg_match_all('/{block(\d+)}/', $newMail->text, $matches);
119-
120-
// si no hay coincidencias, no hacemos nada
121-
if (empty($matches[1])) {
122-
return;
123-
}
124-
125-
// obtenemos el texto hasta el primer bloque, y entre los bloques
126-
// para añadir un TextBlock con el texto encontrado
127-
$text = $newMail->text;
128-
$newMail->text = '';
129-
$lastPos = 0;
130-
131-
// recorremos los bloques encontrados
132-
foreach ($matches[1] as $blockIndex) {
133-
$substr = substr($text, $lastPos, strpos($text, '{block' . $blockIndex . '}') - $lastPos);
134-
$lastPos = strpos($text, '{block' . $blockIndex . '}') + strlen('{block' . $blockIndex . '}');
135-
if (empty($substr) && isset($params['block' . $blockIndex]) && $params['block' . $blockIndex] instanceof BaseBlock) {
136-
$newMail->addMainBlock($params['block' . $blockIndex]);
137-
continue;
138-
}
139-
140-
$newMail->addMainBlock(new TextBlock($substr));
141-
if (isset($params['block' . $blockIndex]) && $params['block' . $blockIndex] instanceof BaseBlock) {
142-
$newMail->addMainBlock($params['block' . $blockIndex]);
143-
}
144-
}
145-
146-
$substr = substr($text, $lastPos);
147-
if (false === empty($substr)) {
148-
$newMail->addMainBlock(new TextBlock($substr));
149-
}
150-
}
151102
}

Core/Lib/Email/NewMail.php

Lines changed: 135 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,9 @@ class NewMail
7373
/** @var array */
7474
private static $mailer = ['mail' => 'Mail', 'sendmail' => 'SendMail', 'smtp' => 'SMTP'];
7575

76+
/** @var array<string, callable> */
77+
private static $blockHandlers = [];
78+
7679
/** @var BaseBlock[] */
7780
protected $mainBlocks = [];
7881

@@ -133,6 +136,16 @@ public function __construct()
133136
$this->verificode = Tools::randomString(20);
134137
}
135138

139+
/**
140+
* Registra un handler personalizado para un tipo de shortcode de bloque.
141+
* El callable recibe (array $attrs, string $content) y debe devolver un BaseBlock o null.
142+
* Ejemplo: NewMail::addBlockHandler('myblock', fn($attrs, $content) => new MyBlock($content));
143+
*/
144+
public static function addBlockHandler(string $tag, callable $handler): void
145+
{
146+
self::$blockHandlers[strtolower($tag)] = $handler;
147+
}
148+
136149
public static function addMailer(string $key, string $name): void
137150
{
138151
if (array_key_exists($key, self::$mailer)) {
@@ -411,6 +424,9 @@ public function send(): bool
411424
}
412425
}
413426

427+
// procesamos los shortcodes de bloque en el texto antes de renderizar
428+
$this->replaceTextToBlock();
429+
414430
$this->renderHTML();
415431
$this->mail->msgHTML($this->html);
416432

@@ -531,6 +547,125 @@ public function to(string $email, string $name = ''): NewMail
531547
return $this;
532548
}
533549

550+
/**
551+
* Busca shortcodes de bloque en el texto del email y los convierte en objetos BaseBlock.
552+
* Sintaxis: [blockTipo atributos]contenido[/blockTipo] o [blockTipo atributos] (auto-cierre)
553+
* Ejemplos:
554+
* [blockTitle type="h2"]Bienvenido[/blockTitle]
555+
* [blockText]Párrafo de texto[/blockText]
556+
* [blockHtml]<ul><li>item</li></ul>[/blockHtml]
557+
* [blockButton label="Reservar" href="https://..."]
558+
* [blockSpace height="20"]
559+
* Los plugins pueden registrar tipos adicionales con NewMail::addBlockHandler().
560+
*/
561+
protected function replaceTextToBlock(): void
562+
{
563+
if (empty($this->text)) {
564+
return;
565+
}
566+
567+
// buscamos shortcodes con o sin contenido interior: [blockXxx attrs]...[/blockXxx] o [blockXxx attrs]
568+
preg_match_all(
569+
'/\[block(\w+)([^\]]*)\](?:(.*?)\[\/block\1\])?/s',
570+
$this->text,
571+
$matches,
572+
PREG_OFFSET_CAPTURE
573+
);
574+
575+
// si no hay shortcodes, no hacemos nada
576+
if (empty($matches[0])) {
577+
return;
578+
}
579+
580+
// guardamos los bloques existentes para añadirlos al final
581+
$existingBlocks = $this->mainBlocks;
582+
$this->mainBlocks = [];
583+
$text = $this->text;
584+
$this->text = '';
585+
$lastPos = 0;
586+
587+
foreach ($matches[0] as $idx => $match) {
588+
$fullMatch = $match[0];
589+
$offset = $match[1];
590+
$blockType = $matches[1][$idx][0];
591+
$attrsStr = $matches[2][$idx][0];
592+
$content = $matches[3][$idx][0] ?? '';
593+
594+
// texto antes del shortcode → TextBlock
595+
$before = trim(substr($text, $lastPos, $offset - $lastPos));
596+
if ('' !== $before) {
597+
$this->addMainBlock(new TextBlock($before));
598+
}
599+
$lastPos = $offset + strlen($fullMatch);
600+
601+
// creamos el bloque correspondiente al shortcode
602+
$attrs = static::parseShortcodeAttributes($attrsStr);
603+
$block = $this->createBlockFromShortcode($blockType, $attrs, $content);
604+
if ($block !== null) {
605+
$this->addMainBlock($block);
606+
}
607+
}
608+
609+
// texto restante tras el último shortcode → TextBlock
610+
$remaining = trim(substr($text, $lastPos));
611+
if ('' !== $remaining) {
612+
$this->addMainBlock(new TextBlock($remaining));
613+
}
614+
615+
// reañadimos los bloques que existían antes
616+
foreach ($existingBlocks as $block) {
617+
$this->mainBlocks[] = $block;
618+
}
619+
}
620+
621+
/**
622+
* Instancia el bloque correspondiente al tipo de shortcode.
623+
* Los plugins pueden ampliar los tipos usando NewMail::addBlockHandler().
624+
*/
625+
protected function createBlockFromShortcode(string $type, array $attrs, string $content): ?BaseBlock
626+
{
627+
// primero comprobamos si hay un handler registrado por un plugin
628+
$lowerType = strtolower($type);
629+
if (isset(self::$blockHandlers[$lowerType])) {
630+
return (self::$blockHandlers[$lowerType])($attrs, $content);
631+
}
632+
633+
// tipos nativos del core
634+
switch ($lowerType) {
635+
case 'title':
636+
return new TitleBlock($content, $attrs['type'] ?? 'h2', $attrs['css'] ?? '', $attrs['style'] ?? '');
637+
case 'text':
638+
return new TextBlock($content, $attrs['css'] ?? '', $attrs['style'] ?? '');
639+
case 'html':
640+
return new HtmlBlock($content);
641+
case 'button':
642+
return new ButtonBlock(
643+
$attrs['label'] ?? $content,
644+
$attrs['href'] ?? '',
645+
$attrs['css'] ?? '',
646+
$attrs['style'] ?? ''
647+
);
648+
case 'space':
649+
return new SpaceBlock((float)($attrs['height'] ?? 30));
650+
}
651+
652+
return null;
653+
}
654+
655+
/**
656+
* Parsea los atributos de un shortcode en un array clave => valor.
657+
* Soporta comillas simples y dobles: attr="valor" o attr='valor'
658+
*/
659+
protected static function parseShortcodeAttributes(string $attrsStr): array
660+
{
661+
preg_match_all('/(\w+)=["\']([^"\']*)["\']/', $attrsStr, $matches);
662+
$attrs = [];
663+
foreach ($matches[1] as $i => $key) {
664+
$attrs[$key] = $matches[2][$i];
665+
}
666+
return $attrs;
667+
}
668+
534669
/**
535670
* Devuelve los bloques del pie del correo.
536671
*/

0 commit comments

Comments
 (0)