CMS: Absatz-Tags aus dem Rich-Text-Editor erscheinen nicht mehr als Text

Der Editor packt eingefügten Text in <p>; Felder wie die FAQ-Antwort gibt die Website als Text
aus, die Tags waren sichtbar. Beim Speichern entfernt unwrapParagraphs() die Absätze (ein
Absatz ohne <p>, mehrere mit <br><br>, Blockinhalte unverändert). cms_inline() gibt die
Felder als bereinigtes Inline-HTML aus – auch schon gespeicherte Texte mit <p> erscheinen
sauber, Fett und Hervorhebung werden dargestellt.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Kevin Adametz 2026-10-12 06:58:48 +00:00
parent 07816dce19
commit 451e738c8b
20 changed files with 147 additions and 23 deletions

View file

@ -48,6 +48,30 @@ final class CmsFluxEditorHtmlTransformer
return self::marksToSecondarySpans($html);
}
/**
* Der Editor packt jeden Text in Absätze – auch eingefügten Klartext (12.10.2026). Für Felder,
* die die Website innerhalb einer Zeile oder eines eigenen Absatzes ausgibt, wird daraus
* Inline-HTML: ein Absatz ohne `<p>`, mehrere durch `<br><br>` getrennt, reiner Text als
* Klartext. Enthält der Text Blockelemente (Überschriften, Listen …), bleibt er unverändert.
*/
public static function unwrapParagraphs(string $html): string
{
$html = trim((string) preg_replace('#<p[^>]*>(\s|&nbsp;|<br\s*/?>)*</p>#i', '', $html));
if ($html === '' || ! str_contains($html, '<p')) {
return $html;
}
if (preg_match('#<(?!/?(?:p|strong|b|em|i|mark|span|br|a)\b)[a-z]#i', $html) === 1) {
return $html;
}
$html = (string) preg_replace('#</p>\s*<p[^>]*>#i', '<br><br>', $html);
$html = trim((string) preg_replace('#^<p[^>]*>|</p>$#i', '', $html));
return str_contains($html, '<') ? $html : html_entity_decode($html, ENT_QUOTES | ENT_HTML5, 'UTF-8');
}
/**
* @param array<int, array<string, mixed>|array{_value: string}> $items
* @return array<int, array<string, mixed>|array{_value: string}>
@ -92,7 +116,7 @@ final class CmsFluxEditorHtmlTransformer
$out = [];
foreach ($item as $key => $value) {
if (in_array($key, self::RICH_TEXT_JSON_FIELDS, true) && is_string($value)) {
$out[$key] = self::fromEditor($value);
$out[$key] = self::unwrapParagraphs(self::fromEditor($value));
} else {
$out[$key] = $value;
}

View file

@ -74,6 +74,37 @@ if (! function_exists('references_page_enabled')) {
}
}
if (! function_exists('cms_inline')) {
/**
* CMS-Text für die Ausgabe innerhalb einer Zeile oder eines Absatzes (12.10.2026): Klartext
* wird escaped, Editor-HTML auf Inline-Auszeichnung reduziert (fett, kursiv, Hervorhebung,
* Links, Zeilenumbrüche) – Absatz-Tags aus dem Editor erscheinen so nicht als Text.
*/
function cms_inline(mixed $value): \Illuminate\Support\HtmlString
{
$text = trim((string) $value);
if (! str_contains($text, '<')) {
return new \Illuminate\Support\HtmlString(e(html_entity_decode($text, ENT_QUOTES | ENT_HTML5, 'UTF-8')));
}
$html = \App\Services\CmsFluxEditorHtmlTransformer::unwrapParagraphs(
\App\Services\CmsFluxEditorHtmlTransformer::fromEditor($text)
);
if (! str_contains($html, '<')) {
return new \Illuminate\Support\HtmlString(e($html));
}
$html = (string) preg_replace('#</(p|div|li|h[1-6])>\s*<\1[^>]*>#i', '<br><br>', $html);
$html = strip_tags($html, '<strong><b><em><i><span><br><a>');
// Nur harmlose Attribute: keine Event-Handler, keine javascript:-Links.
$html = (string) preg_replace('#\s+on[a-z]+\s*=\s*("[^"]*"|\'[^\']*\'|[^\s>]+)#i', '', $html);
$html = (string) preg_replace('#href\s*=\s*(["\'])\s*javascript:[^"\']*\1#i', 'href="#"', $html);
return new \Illuminate\Support\HtmlString(trim($html));
}
}
if (! function_exists('whatsapp_link')) {
/**
* Klick-zum-Chat-Link, sofern im CMS eine Nummer hinterlegt ist (global.contact.whatsapp).