Eine moderne Alternative zum xoutputfilter (Danke Andreas ❤️) AddOn und als Ergänzung zu Sprog (Danke Thomas ❤️). Snippets können Texte sein oder kleine Code-Schnipsel die global verwendet werden können. Die Ausgabe erfolgt über den Outputfilter.
Das Snippets-AddOn bietet zentrale Verwaltung von wiederverwendbaren Code-Fragmenten und automatische HTML-Manipulation mit PHP 8.4 DOM:
- Snippets – Wiederverwendbare HTML/PHP-Fragmente mit Parametern
- String-Übersetzungen – Mehrsprachige Key-Value-Übersetzungen (Sprog-Alternative) mit DeepL-Integration
- Filter – 26+ Filter für Textformatierung
- HTML-Ersetzungen – CSS-Selektoren, Regex und PHP-Callbacks
- PHP-API –
Snippets::get(),Snippets::apply(),SnippetsTranslate::get()für PHP-Zugriff - Scope-Kontrolle – Templates, Kategorien, URLs, Backend-Seiten
- Berechtigungssystem – Admin, Editor, Viewer Rollen
- String-Übersetzungen: Neues mehrsprachiges Übersetzungssystem – eine schlanke Sprog-Alternative für String-Übersetzungen, direkt im Snippets-AddOn
- Inline-Bearbeitung: Alle Sprachen in einer Tabelle, Click-to-Edit, sofortiges Speichern per AJAX
- DeepL-Integration: KI-Übersetzung per DeepL – einzeln oder als Batch für eine komplette Zielsprache
- Nutzt WriteAssist-Token: Kein separater API-Key nötig – DeepL-Key aus dem WriteAssist-AddOn wird automatisch verwendet
- PHP-API:
SnippetsTranslate::get('key')für direkten Zugriff in Modulen, Templates und PHP-Code - Sprog-Import: Bestehende Sprog-Wildcards können mit einem Klick übernommen werden
- Paginierung: Übersetzungsliste mit Seitennavigation bei vielen Keys
- Seiten-Icons: Alle Unterseiten haben passende FontAwesome-Icons
- AddOn im Ordner
/redaxo/src/addons/snippetsinstallieren - Im Backend unter AddOns aktivieren
- Berechtigungen für Benutzer einrichten (optional)
[[snippet:key_name]]
[[snippet:key_name|param1=wert1|param2=wert2]]
[[snippet:key_name|upper|truncate(100)]]
[[snippet:key_name|filter|param=wert]]
Snippet erstellen:
- Key:
footer_copyright - Typ:
html - Inhalt:
© 2026 Meine Firma GmbH
Verwendung:
<footer>
[[snippet:footer_copyright]]
</footer>Ausgabe:
<footer>
© 2026 Meine Firma GmbH
</footer>Snippet erstellen:
- Key:
alert - Typ:
php - Inhalt:
<?php
$typ = $SNIPPET_PARAMS['typ'] ?? 'info';
$text = $SNIPPET_PARAMS['text'] ?? '';
$titel = $SNIPPET_PARAMS['titel'] ?? '';
$icons = [
'info' => 'fa-info-circle',
'success' => 'fa-check-circle',
'warning' => 'fa-exclamation-triangle',
'danger' => 'fa-times-circle'
];
$icon = $icons[$typ] ?? 'fa-info-circle';
?>
<div class="alert alert-<?= htmlspecialchars($typ) ?>">
<?php if ($titel): ?>
<h4><i class="fa <?= $icon ?>"></i> <?= htmlspecialchars($titel) ?></h4>
<?php endif; ?>
<p><?= htmlspecialchars($text) ?></p>
</div>Verwendung:
[[snippet:alert|typ=success|titel=Gespeichert!|text=Ihre Daten wurden erfolgreich gespeichert.]]Ausgabe:
<div class="alert alert-success">
<h4><i class="fa fa-check-circle"></i> Gespeichert!</h4>
<p>Ihre Daten wurden erfolgreich gespeichert.</p>
</div>Snippet erstellen:
- Key:
kontakt - Typ:
php - Inhalt:
<?php
$name = $SNIPPET_PARAMS['name'] ?? '';
$position = $SNIPPET_PARAMS['position'] ?? '';
$tel = $SNIPPET_PARAMS['tel'] ?? '';
$email = $SNIPPET_PARAMS['email'] ?? '';
$foto = $SNIPPET_PARAMS['foto'] ?? '';
?>
<div class="kontaktbox">
<?php if ($foto): ?>
<img src="<?= rex_url::media($foto) ?>" alt="<?= htmlspecialchars($name) ?>">
<?php endif; ?>
<h4><?= htmlspecialchars($name) ?></h4>
<?php if ($position): ?>
<p class="position"><?= htmlspecialchars($position) ?></p>
<?php endif; ?>
<?php if ($tel): ?>
<p><i class="fa fa-phone"></i> <a href="tel:<?= htmlspecialchars($tel) ?>"><?= htmlspecialchars($tel) ?></a></p>
<?php endif; ?>
<?php if ($email): ?>
<p><i class="fa fa-envelope"></i> <a href="mailto:<?= htmlspecialchars($email) ?>"><?= htmlspecialchars($email) ?></a></p>
<?php endif; ?>
</div>Verwendung:
[[snippet:kontakt|name=Max Mustermann|position=Geschäftsführer|tel=+49 123 456789|email=max@firma.de|foto=max.jpg]]<?php
// Array mit allen übergebenen Parametern
$wert = $SNIPPET_PARAMS['mein_param'] ?? 'standard';
// Der Snippet-Key als String
echo $SNIPPET_KEY; // z.B. "kontakt"
// Das Snippet-Objekt mit allen Eigenschaften
$snippet->getTitle();
$snippet->getDescription();
$snippet->getId();| Typ | Beschreibung |
|---|---|
html |
HTML-Code, wird direkt ausgegeben |
text |
Reiner Text, wird escaped |
php |
PHP-Code mit Zugriff auf $SNIPPET_PARAMS (nur Admins) |
Das Snippets-AddOn enthält ein eigenes mehrsprachiges Übersetzungssystem – eine schlanke Alternative zu Sprog, spezialisiert auf String-Übersetzungen.
Übersetzungsschlüssel werden mit der Syntax [[ key ]] im Content platziert und per OUTPUT_FILTER automatisch durch den passenden Wert der aktuellen Sprache ersetzt.
<h1>[[ nav.home ]]</h1>
<p>[[ footer.copyright ]]</p>
<a href="/kontakt">[[ btn.contact ]]</a>Für direkten Zugriff in PHP – ohne OUTPUT_FILTER – steht die Service-Klasse zur Verfügung:
use FriendsOfREDAXO\Snippets\Service\SnippetsTranslate;
echo SnippetsTranslate::get('nav.home'); // aktuelle Sprache
echo SnippetsTranslate::get('nav.home', 2); // Sprach-ID 2
echo SnippetsTranslate::get('nav.home', null, 'Startseite'); // mit Fallback
// Platzhalter in beliebigem Content ersetzen
$html = SnippetsTranslate::replace($content, rex_clang::getCurrentId());Snippet-Werte können selbst wieder [[ key ]]-Platzhalter enthalten – diese werden rekursiv aufgelöst (max. 5 Ebenen).
Beispiel:
| Key | Wert |
|---|---|
company.name |
ACME GmbH |
footer.copyright |
© 2026 [[ company.name ]] |
footer.full |
[[ footer.copyright ]] – Alle Rechte vorbehalten |
Ergebnis von [[ footer.full ]]:
© 2026 ACME GmbH – Alle Rechte vorbehalten
Das funktioniert sowohl im OUTPUT_FILTER als auch per PHP-API:
// Verschachtelte Platzhalter werden automatisch aufgelöst
echo SnippetsTranslate::get('footer.full');
// → "© 2026 ACME GmbH – Alle Rechte vorbehalten"Hinweis: Zirkuläre Referenzen (A → B → A) werden nach 5 Durchläufen abgebrochen – der nicht auflösbare Platzhalter bleibt dann stehen.
Wenn eine Übersetzung für eine Sprache nicht vorhanden ist, kann automatisch der Wert einer Basis-Sprache übernommen werden. Damit müssen Texte, die in allen Sprachen gleich sind (z.B. Markennamen, technische Begriffe), nur einmal gepflegt werden.
Aktivierung: Einstellungen → „Sprach-Vererbung aktivieren" → Basis-Sprache wählen (Standard: erste Sprache)
Beispiel:
| Key | Deutsch (Basis) | Englisch | Französisch |
|---|---|---|---|
company.name |
ACME GmbH |
(leer) | (leer) |
nav.home |
Startseite |
Home |
Accueil |
Ergebnis: [[ company.name ]] liefert in allen Sprachen ACME GmbH, während [[ nav.home ]] sprachspezifisch ersetzt wird.
Performance: Die Fallback-Werte werden beim ersten Zugriff einmalig geladen und gecacht – keine zusätzlichen DB-Queries pro Platzhalter.
In den Einstellungen findet sich die Analyse-Funktion „Fehlende Platzhalter erkennen". Sie scannt alle Artikelinhalte (rex_article_slice value1–20) nach [[ key ]]-Platzhaltern und vergleicht sie mit den definierten Übersetzungs-Schlüsseln.
Das Ergebnis zeigt:
- Anzahl definierter Schlüssel
- Anzahl in Artikeln verwendeter Platzhalter
- Fehlende Schlüssel mit Vorkommen und Links zu den betroffenen Artikeln
- Direkte „+"-Buttons zum Anlegen der fehlenden Übersetzung
Ideal für:
- Qualitätssicherung nach dem Einpflegen neuer Module
- Migration von anderen Systemen
- Überprüfung ob alle Platzhalter korrekt angelegt sind
Für professionelle Übersetzer kann das Standard-Format XLIFF 1.2 verwendet werden – kompatibel mit allen gängigen CAT-Tools (SDL Trados, memoQ, Memsource, Phrase, Crowdin u.a.).
Export: Import/Export → XLIFF → Quell- und Zielsprache wählen → .xliff-Datei herunterladen
Die XLIFF-Datei enthält:
- Quell- und Zieltexte als
<trans-unit>Elemente state="translated"oderstate="new"für den Übersetzungsstatus- Kategorien als
<note>Elemente - Tool-Informationen im Header
Import: Vom Übersetzer bearbeitete XLIFF-Datei hochladen → Zielsprache wird automatisch erkannt → Werte werden aktualisiert
// Programmatischer XLIFF-Export
$result = ImportExportService::exportTranslationsXliff(
targetClangId: 2, // Englisch
sourceClangId: 1 // Deutsch
);
// Programmatischer XLIFF-Import
$result = ImportExportService::importTranslationsXliff(
$xmlString,
createMissing: true // Neue Keys anlegen
);Wenn das WriteAssist-AddOn installiert und ein DeepL-API-Key konfiguriert ist, stehen KI-Übersetzungen zur Verfügung:
- Einzelübersetzung: DeepL-Button (🔤) in jeder Sprachzelle – übersetzt den Quelltext und speichert sofort
- Batch-Übersetzung: Zielsprache wählen → alle leeren (oder alle) Strings werden serverseitig per DeepL übersetzt
Ein separater API-Key ist nicht nötig – der DeepL-Token aus WriteAssist wird automatisch verwendet.
Platzhalter [[ key ]] werden auch im Backend aufgelöst – allerdings nicht blind per OUTPUT_FILTER (wie Sprog), sondern gezielt per SLICE_SHOW Extension Point. Das bedeutet:
- Slice-Vorschau: Redakteure sehen „Startseite" statt
[[ nav.home ]]in der Artikelbearbeitung - Formulare geschützt: Textareas, Input-Felder und Code-Editoren werden nicht ersetzt – Platzhalter bleiben dort erhalten
- Backend-UI unberührt: Menüs, Labels und Navigation werden nicht beeinflusst
- Sprachrichtig: Es wird die im Backend gewählte Content-Sprache verwendet (= die Sprache des Artikels)
Hinweis: Im Gegensatz zu Sprog, das den kompletten Backend-Output ersetzt und dabei riskiert, Formularinhalte zu verändern, arbeitet die Snippets-Lösung chirurgisch nur auf dem gerenderten Slice-Output.
- Syntax: Optional kann zusätzlich die
{{ key }}-Syntax aktiviert werden (Einstellungen → „Sprog-Syntax unterstützen") - Import: Bestehende Sprog-Wildcards können mit einem Klick in die Snippets-Übersetzungen importiert werden (Admin-Bereich)
- Das Sprog-AddOn wird dafür nicht benötigt – der Import liest direkt aus der
rex_sprog_wildcard-Tabelle
REDAXO-Sprachcodes werden automatisch auf DeepL-Codes gemappt (z. B. de → DE, en → EN-GB). Falls ein Code nicht erkannt wird, kann das Mapping in den Einstellungen manuell konfiguriert werden:
sl=SL
hr=HR
Filter formatieren die Snippet-Ausgabe. Sie werden mit | notiert und können kombiniert werden.
| Filter | Beschreibung | Beispiel |
|---|---|---|
upper |
GROSSBUCHSTABEN | [[snippet:key|upper]] |
lower |
kleinbuchstaben | [[snippet:key|lower]] |
title |
Title Case | [[snippet:key|title]] |
capitalize |
Erster Buchstabe groß | [[snippet:key|capitalize]] |
trim |
Whitespace entfernen | [[snippet:key|trim]] |
truncate(n,suffix) |
Auf n Zeichen kürzen | [[snippet:key|truncate(100,...)]] |
limit(n,suffix) |
Alias für truncate | [[snippet:key|limit(50)]] |
words(n,suffix) |
Auf n Wörter kürzen | [[snippet:key|words(20)]] |
nl2br |
Zeilenumbrüche → <br> |
[[snippet:key|nl2br]] |
raw |
Keine nl2br-Konvertierung | [[snippet:key|raw]] |
markdown |
Markdown → HTML | [[snippet:key|markdown]] |
strip_tags(allowed) |
HTML-Tags entfernen | [[snippet:key|strip_tags(<p><br>)]] |
escape |
HTML-Entities escapen | [[snippet:key|escape]] |
sanitize |
HTML sicher machen | [[snippet:key|sanitize]] |
format(args...) |
sprintf-Formatierung | [[snippet:key|format(5,Baum)]] |
default(value) |
Fallback wenn leer | [[snippet:key|default(Kein Inhalt)]] |
replace(s,r) |
Text ersetzen | [[snippet:key|replace(alt,neu)]] |
prefix(text) |
Text voranstellen | [[snippet:key|prefix(>>> )]] |
suffix(text) |
Text anhängen | [[snippet:key|suffix( <<<)]] |
wrap(b,a) |
Text umschließen | [[snippet:key|wrap(<em>,</em>)]] |
date(format) |
Datum formatieren | [[snippet:key|date(d.m.Y)]] |
intldate(format) |
Internationales Datum | [[snippet:key|intldate(LONG)]] |
number(d,dp,ts) |
Zahl formatieren | [[snippet:key|number(2,",",".")]] |
bytes(precision) |
Bytes formatieren | [[snippet:key|bytes(2)]] |
slug |
URL-freundlich | [[snippet:key|slug]] |
url |
Als klickbarer Link | [[snippet:key|url]] |
email |
Als klickbare E-Mail | [[snippet:key|email]] |
widont |
Keine Einzel-Wörter am Ende | [[snippet:key|widont]] |
json |
Als JSON ausgeben | [[snippet:key|json]] |
base64 |
Base64-kodiert | [[snippet:key|base64]] |
<!-- Überschrift in Großbuchstaben -->
[[snippet:headline|upper]]
<!-- Teaser: max 150 Zeichen, ohne HTML -->
[[snippet:description|strip_tags|truncate(150,...)]]
<!-- Markdown-Content sicher ausgeben -->
[[snippet:content|markdown|sanitize]]
<!-- Preis formatieren -->
[[snippet:price|number(2,",",".")]] €
<!-- E-Mail als Link -->
[[snippet:contact_email|email]]
<!-- Filter + Parameter kombiniert -->
[[snippet:teaser|upper|max_length=100|truncate(100)]]Die zentrale API-Klasse für den Zugriff auf Snippets.
use FriendsOfREDAXO\Snippets\Snippets;
// Snippet abrufen
echo Snippets::get('footer_text');
echo Snippets::get('greeting', ['name' => 'Max']);
// Mit Filtern
echo Snippets::filtered('headline', [], 'upper');
echo Snippets::filtered('content', [], 'markdown|sanitize');
// Platzhalter in Text ersetzen
$html = '<h1>[[snippet:headline]]</h1>';
echo Snippets::apply($html);
// Existenz prüfen
if (Snippets::exists('special_offer')) {
echo Snippets::get('special_offer');
}
// Mit Fallback
echo Snippets::getOr('headline', 'Willkommen');
// Beliebigen Text filtern
echo Snippets::filter($content, 'escape|truncate(100)');| Methode | Beschreibung |
|---|---|
Snippets::get($key, $params, $clangId) |
Snippet abrufen |
Snippets::filtered($key, $params, $filters, $clangId) |
Snippet mit Filtern |
Snippets::apply($text, $clangId, $context) |
Platzhalter ersetzen |
Snippets::exists($key) |
Existenz prüfen |
Snippets::getOr($key, $fallback, $params, $clangId) |
Mit Fallback |
Snippets::filter($content, $filters) |
Text filtern |
Automatische Manipulation des HTML-Outputs über CSS-Selektoren, Regex oder PHP-Callbacks.
| Typ | Beschreibung |
|---|---|
css |
CSS-Selektoren zum Finden und Manipulieren von Elementen |
regex |
Reguläre Ausdrücke für Pattern-basierte Ersetzung |
callback |
PHP-Funktion für komplexe Logik |
Regel erstellen:
- Typ: CSS-Selektor
- Suchwert:
a[href^="http"]:not([href*="meine-domain.de"]) - Position: Am Ende einfügen
- Ersetzung:
<i class="fa fa-external-link"></i>
Vorher:
<a href="https://example.com">Mehr Info</a>Nachher:
<a href="https://example.com">Mehr Info <i class="fa fa-external-link"></i></a>Regel erstellen:
- Typ: CSS-Selektor
- Suchwert:
img:not([loading]) - Position: Attribut setzen
- Attribut:
loading - Wert:
lazy
Vorher:
<img src="bild.jpg" alt="Beispiel">Nachher:
<img src="bild.jpg" alt="Beispiel" loading="lazy">Regel erstellen:
- Typ: CSS-Selektor
- Suchwert:
table:not(.no-wrap) - Position: Umschließen
- Ersetzung:
<div class="table-responsive">|</div>
Vorher:
<table>...</table>Nachher:
<div class="table-responsive"><table>...</table></div>Regel erstellen:
- Typ: Regex
- Pattern:
/(\+49[\d\s\-]+)/ - Ersetzung:
<a href="tel:$1">$1</a>
Vorher:
<p>Rufen Sie uns an: +49 123 456789</p>Nachher:
<p>Rufen Sie uns an: <a href="tel:+49 123 456789">+49 123 456789</a></p>Regel erstellen:
- Typ: PHP Callback
- Suchwert:
{{YEAR}} - Ersetzung:
FriendsOfREDAXO\MeinAddon\Replacer::currentYear
Callback-Klasse:
<?php
namespace FriendsOfREDAXO\MeinAddon;
use FriendsOfREDAXO\Snippets\Domain\HtmlReplacement;
class Replacer
{
public static function currentYear(string $search, string $content, HtmlReplacement $replacement): string
{
return str_replace($search, date('Y'), $content);
}
}| Position | Beschreibung |
|---|---|
| Ersetzen | Ersetzt das gesamte Element |
| Davor einfügen | Fügt vor dem Element ein |
| Danach einfügen | Fügt nach dem Element ein |
| Am Anfang einfügen | Fügt innerhalb am Anfang ein (prepend) |
| Am Ende einfügen | Fügt innerhalb am Ende ein (append) |
Jede HTML-Ersetzung kann eingeschränkt werden auf:
- Context: Frontend, Backend oder beides
- Templates: Nur bestimmte Templates (Frontend)
- Kategorien: Nur bestimmte Kategorien mit/ohne Unterkategorien (Frontend)
- URL-Pattern: Regex für URL-Matching (Frontend)
- Backend-Seiten: Nur bestimmte Backend-Seiten
- Backend-Request-Pattern: Optionaler Filter auf konkrete Backend-Requests inkl. Query-Parameter
Mit diesem Feld lässt sich eine Regel sehr gezielt auf einzelne Backend-Requests begrenzen.
- UND innerhalb einer Zeile: Parameter mit
&verknüpfen - ODER zwischen mehreren Varianten: Jede Zeile ist ein eigenes Pattern
- Alternativ ODER mit
||in einer Zeile - Ohne
=: Teilstring-Match auf die komplette Request-URL - Mit
key=value: Teilstring-Match auf den Parameterwert (nicht nur exakte Gleichheit)
Beispiele:
page=content/edit&function=add
page=content/edit&function=edit
page=content/edit
func=delete
page=mediapool/media
oder in einer Zeile:
page=content/edit&function=add || page=content/edit&function=edit
Hinweis: Die klassische Backend-Seiten-Auswahl und das Backend-Request-Pattern wirken zusammen. Wenn beide gesetzt sind, reicht ein Treffer in einer der beiden Bedingungen.
Standardmäßig werden Snippet-Platzhalter im Feld Ersetzungs-Inhalt nicht aufgelöst. Wenn gewünscht, kann dies in den Einstellungen aktiviert werden:
- Snippets → Einstellungen → „Snippets in HTML-Ersetzungen erlauben“
Dann werden Platzhalter wie [[snippet:mein_key]] im Ersetzungs-Inhalt vor dem Einfügen verarbeitet.
<?php
use FriendsOfREDAXO\Snippets\Service\SnippetService;
// Snippet rendern
echo SnippetService::render(
'kontakt', // Snippet-Key
'frontend', // Context
rex_clang::getCurrentId(), // Sprach-ID
['name' => 'Max'] // Parameter
);<?php
use FriendsOfREDAXO\Snippets\Service\ReplacementService;
$content = 'Hallo [[snippet:kontakt|name=Max]]';
$service = new ReplacementService();
$ersetzt = $service->replace($content, [
'context' => 'frontend',
'clang_id' => rex_clang::getCurrentId()
]);
echo $ersetzt;<?php
use FriendsOfREDAXO\Snippets\Service\HtmlReplacementService;
$content = '<h1>Überschrift</h1><p>Text</p>';
$processed = HtmlReplacementService::process($content, 'frontend');
echo $processed;<?php
use FriendsOfREDAXO\Snippets\Service\FilterService;
$text = 'Mein langer Text hier...';
$filtered = FilterService::apply($text, [
['name' => 'truncate', 'args' => ['50', '...']],
['name' => 'upper', 'args' => []]
]);
echo $filtered;Das Snippets-AddOn bietet eine Installer-API, mit der andere AddOns eigene Übersetzungen, Snippets und HTML-Ersetzungen programmatisch installieren, aktualisieren und entfernen können.
<?php
use FriendsOfREDAXO\Snippets\Service\SnippetsInstaller;
// In eurer install.php oder update.php:
if (rex_addon::get('snippets')->isAvailable()) {
SnippetsInstaller::installTranslations([
'my_addon.greeting' => ['de' => 'Hallo Welt', 'en' => 'Hello World'],
'my_addon.farewell' => ['de' => 'Auf Wiedersehen', 'en' => 'Goodbye'],
]);
}Jede install*-Methode akzeptiert einen $conflictMode-Parameter:
| Modus | Konstante | Beschreibung |
|---|---|---|
| Skip | SnippetsInstaller::SKIP |
Bestehende Einträge überspringen (Standard) |
| Overwrite | SnippetsInstaller::OVERWRITE |
Bestehende Einträge komplett überschreiben |
| Fill Empty | SnippetsInstaller::FILL_EMPTY |
Nur leere Sprachwerte füllen, vorhandene Werte behalten (nur Translations) |
FILL_EMPTY ist ideal für AddOn-Updates: Neue Sprachen werden ergänzt, ohne vom Benutzer angepasste Texte zu überschreiben.
<?php
use FriendsOfREDAXO\Snippets\Service\SnippetsInstaller;
// Einfach: Key => [Sprach-Code => Wert]
$result = SnippetsInstaller::installTranslations([
'shop.cart.empty' => ['de' => 'Warenkorb ist leer', 'en' => 'Cart is empty'],
'shop.cart.add' => ['de' => 'In den Warenkorb', 'en' => 'Add to cart'],
'shop.cart.total' => ['de' => 'Gesamtsumme', 'en' => 'Total'],
], SnippetsInstaller::FILL_EMPTY);
// $result = ['imported' => 3, 'skipped' => 0, 'updated' => 0]
// Mit Kategorie und Icon
SnippetsInstaller::installTranslations(
[
'shop.nav.home' => ['de' => 'Startseite', 'en' => 'Home'],
'shop.nav.about' => ['de' => 'Über uns', 'en' => 'About'],
],
SnippetsInstaller::SKIP,
'Shop', // Kategoriename (wird erstellt falls nötig)
'fa-shopping-cart', // Icon für neue Kategorie
);Wichtig: Sprachen werden per Code (
de,en,fr, …) angegeben – nicht per ID. Dadurch funktioniert der Code in jeder REDAXO-Installation unabhängig von der Sprach-Konfiguration.
<?php
use FriendsOfREDAXO\Snippets\Service\SnippetsInstaller;
$result = SnippetsInstaller::installSnippets([
'my_addon.footer' => [
'content' => '<div class="footer">© {{ year }}</div>',
'title' => 'Footer',
'content_type' => 'html', // html, text, php
'context' => 'frontend', // frontend, backend, both
],
'my_addon.copyright' => [
'content' => '© 2025 Meine Firma',
'title' => 'Copyright',
],
], SnippetsInstaller::SKIP);<?php
use FriendsOfREDAXO\Snippets\Service\SnippetsInstaller;
$result = SnippetsInstaller::installHtmlReplacements([
'my_addon.lazy_images' => [
'type' => 'css_selector',
'search_value' => 'img:not([loading])',
'replacement' => 'loading="lazy"',
'position' => 'add_attribute',
'scope_context' => 'frontend',
'description' => 'Lazy Loading für alle Bilder',
'priority' => 10,
],
], SnippetsInstaller::SKIP);<?php
use FriendsOfREDAXO\Snippets\Service\SnippetsInstaller;
// Lädt eine zuvor exportierte JSON-Datei
$result = SnippetsInstaller::installFromFile(
rex_path::addon('my_addon', 'data/translations.json'),
SnippetsInstaller::FILL_EMPTY,
);<?php
// In eurer uninstall.php:
use FriendsOfREDAXO\Snippets\Service\SnippetsInstaller;
if (rex_addon::get('snippets')->isAvailable()) {
// Per Prefix: Entfernt alle Einträge die mit 'my_addon.' beginnen
SnippetsInstaller::removeTranslationsByPrefix('my_addon.');
SnippetsInstaller::removeSnippetsByPrefix('my_addon.');
SnippetsInstaller::removeHtmlReplacementsByPrefix('my_addon.');
// Oder einzelne Keys entfernen
SnippetsInstaller::removeTranslationsByKeys([
'my_addon.greeting',
'my_addon.farewell',
]);
}<?php
use FriendsOfREDAXO\Snippets\Service\SnippetsInstaller;
if (SnippetsInstaller::translationExists('my_addon.greeting')) {
// Key existiert bereits
}
if (SnippetsInstaller::snippetExists('my_addon.footer')) {
// Snippet existiert bereits
}- Keys mit AddOn-Name prefixen:
my_addon.section.key– vermeidet Konflikte mit anderen AddOns FILL_EMPTYinupdate.phpverwenden – ergänzt neue Sprachen ohne Benutzer-Anpassungen zu überschreibenSKIPininstall.phpverwenden – überschreibt keine vorhandenen Daten bei Neuinstallationsnippets-Verfügbarkeit prüfen vor dem Aufruf:if (rex_addon::get('snippets')->isAvailable())- Aufräumen in
uninstall.phpmitremoveByPrefix()– hinterlässt keine verwaisten Daten - Sprach-Codes statt IDs verwenden – macht den Code portabel
| Rolle | Rechte |
|---|---|
snippets[admin] |
Vollzugriff, PHP-Snippets bearbeiten, Einstellungen |
snippets[editor] |
HTML/Text-Snippets erstellen und bearbeiten |
snippets[viewer] |
Nur lesen |
- Snippet-Ersetzung aktiv: Frontend/Backend aktivieren
- HTML-Ersetzungen aktiv: Frontend/Backend aktivieren
- Debug-Modus: Erweiterte Fehlerausgabe
Das AddOn stellt zwei Plugins für den TinyMCE-Editor (tinymce ab Version 5) bereit.
Hierbei handelt es sich um das Standard-Plugin, das Snippets aus der rex_snippets-Tabelle einfügt.
Installation:
- Gehe in das TinyMCE AddOn -> Profile.
- Füge im Feld Plugins den Eintrag
redaxo_snippetshinzu. - Füge im Feld Toolbar den Eintrag
redaxo_snippetshinzu (Tool-Icon: Code-Symbol).
Dieses Plugin erlaubt die Auswahl von mehrsprachigen String-Übersetzungen (Sprog-Alternative) direkt im Editor. Es unterstützt die Filterung nach Kategorien und ermöglicht eine sehr gezielte Auswahl.
Installation & Konfiguration:
- Die Plugin-Datei befindet sich unter
assets/addons/snippets/js/tinymce_plugin.js. Diese muss im REDAXO-Backend (z.B. über dasbeaver-AddOn oder ein Theme) eingebunden werden. - In der TinyMCE-Konfiguration muss
snippets_rexzu denextra_pluginshinzugefügt undsnippets_rexin die Toolbar aufgenommen werden. - Optional: Filterung nach Kategorien (nur Keys dieser Kategorien werden angezeigt):
{ "extra_plugins": "snippets_rex", "toolbar": "snippets_rex ...", "snippets_rex": { "categories": "Header,Footer" } }
Funktionsweise:
- Im Editor erscheint ein Snippet-Icon (Sprechblasen-Symbol) in der Toolbar.
- Klick darauf öffnet ein Menü mit allen verfügbaren Übersetzungs-Keys.
- Eingefügt wird der Platzhalter
[[ key ]].
Praxis-Tipp: Nutzen Sie die Kategorien, um Redakteuren in Inhalts-Blöcken nur relevante Keys (z.B. Kategorie
Content) anzubieten, während Admin-Bereiche die volle Auswahl haben.
Das Snippets-AddOn ist vollständig mit Sprog kombinierbar. Beide AddOns ergänzen sich:
- Sprog für mehrsprachige Platzhalter und Übersetzungen
- Snippets für wiederverwendbare Code-Fragmente mit Parametern
Falls Sprog installiert ist, können Sprog-Wildcards direkt im Content verwendet werden:
<!-- Sprog für Übersetzungen -->
{{ firmenname }}
{{ kontakt_email }}
<!-- Snippets für Komponenten -->
[[snippet:kontaktbox|name={{ ansprechpartner }}|tel={{ telefon }}]]Snippets werden nicht ersetzt in:
- Struktur-Edit-Modus
- YForm Table Manager Edit
- Module-Edit / Template-Edit
- AJAX Edit-Requests
- Snippets-AddOn Backend-Seiten
- Nur für
snippets[admin]-Benutzer - Alle Ausführungen werden protokolliert
- Fehler werden im Debug-Modus sichtbar
- PHP-Callbacks nur aus erlaubten Namespaces (
FriendsOfREDAXO\,rex_)
- Status prüfen: Snippet muss aktiv sein
- Context prüfen: Frontend-Snippet nicht im Backend sichtbar
- Key prüfen: Groß-/Kleinschreibung beachten
- Edit-Modus: Snippets werden beim Bearbeiten nicht ersetzt
- Status prüfen: Regel muss aktiv sein
- Scope prüfen: Template/Kategorie/URL stimmen?
- Selektor testen: CSS-Selektor korrekt?
- Debug aktivieren: In Einstellungen aktivieren
- Backend-Seite prüfen: Bei Unterseiten ggf. den übergeordneten Key oder die konkrete Unterseite wählen
- Request-Pattern prüfen: Parameternamen müssen stimmen, z. B.
function=addvs.func=add(Werte dürfen Teilstrings sein) - Mehrere URLs: Je URL eine eigene Zeile oder mit
||trennen - Kombinationslogik beachten: Bei gesetzten Backend-Seiten und Request-Pattern reicht ein Treffer in einer Bedingung
Debug-Modus aktivieren → Fehler erscheinen als HTML-Kommentare:
<!-- PHP Snippet Error (mein_snippet): Undefined variable $test -->| Tabelle | Beschreibung |
|---|---|
rex_snippets_snippet |
Snippets |
rex_snippets_translation |
Übersetzungen (Snippet-Werte pro Sprache) |
rex_snippets_category |
Kategorien |
rex_snippets_html_replacement |
HTML-Ersetzungen |
rex_snippets_log |
Audit-Log |
rex_snippets_string |
String-Übersetzungen (Keys, Kategorie, Status) |
rex_snippets_string_value |
Übersetzungswerte pro Key und Sprache |
MIT License
Entwickelt von der REDAXO-Community
Basiert auf Ideen vom AddOn XOutputFilter, Danke an: Andreas Eberhard / aesoft.de und Peter Bickel / polarpixel.de