Ein REDAXO-Addon zur Verwaltung von domain- und sprachspezifischen Template-Einstellungen über DocBlock-Konfiguration.
- 📝 DocBlock-basierte Konfiguration - Template-Settings direkt im Template-Code definieren
- 🌍 Multi-Domain Support - Unterschiedliche Einstellungen pro YRewrite-Domain
- 🌐 Mehrsprachigkeit - Separate Einstellungen für jede Sprache mit Fallback
- 🎨 20+ Feldtypen - text, textarea, cke5, number, email, tel, date, time, color, colorselect, media, medialist, select, checkbox, link, linklist u.v.m.
- 🔧 Native REDAXO Widgets - Volle Integration von Linkmap, Medienpicker und Bootstrap Selectpicker
- 🎨 Visuelle Farbauswahl - Colorselect mit farbigen Badges
- 🚀 Einfache Frontend-API - Statische Klassen-Methoden mit optionalen Domain/Sprach-Parametern
- 🔌 Erweiterbar - Extension Point System für eigene Feldtypen durch externe Addons
Ab Version 1.x können externe Addons eigene Feldtypen registrieren:
// In boot.php des externen Addons
rex_extension::register('TEMPLATE_MANAGER_FIELD_RENDERERS', function($ep) {
$renderers = $ep->getSubject();
$renderers[] = new \MeinAddon\TemplateManagerFieldRenderer();
return $renderers;
});Siehe EXTERNAL_FIELD_RENDERER_EXAMPLE.md für vollständige Beispiele.
- Addon im REDAXO-Backend installieren
- Optional: Demo-Template über Template Manager → Setup importieren
- Eigene Templates mit DOMAIN_SETTINGS erstellen
Das Addon enthält ein vorkonfiguriertes Demo-Template:
- Name: Modern Business (Demo)
- Features:
- Dark/Light Mode Support (automatisch basierend auf System-Einstellungen)
- 16+ konfigurierbare Einstellungen
- Modernes, responsives Design ohne Framework-Abhängigkeiten
- CSS Custom Properties für einfaches Theming
- Barrierefrei (WCAG 2.1 AA)
- Font Awesome 6 Integration
- Demo-Content wenn noch kein Content vorhanden
Enthaltene Feldtypen:
text- Firmenname, Slogancolorselect- Akzentfarbe (8 vordefinierte Brand-Farben)email- Kontakt E-Mailtel- Telefonnummernumber- Mitarbeiteranzahl, Gründungsjahrmedia- Logomedialist- Header-Bilderlink- Startseitelinklist- Footer-Linkscategory- Hauptkategoriecategorylist- Service-Kategoriencheckbox- Breadcrumbs anzeigen, Kontaktinfo im Headersocial_links- Social Media Links (Repeater mit Sortierung)opening_hours- Strukturierte Öffnungszeiten (Google-Style)
Import über: Template Manager → Setup → Demo-Template jetzt importieren
Füge einen PHP-DocBlock-Kommentar am Anfang deines Templates ein mit einem DOMAIN_SETTINGS Abschnitt:
<?php
/**
* Mein Template
*
* Beschreibung des Templates
*
* DOMAIN_SETTINGS
* tm_logo: media|Logo||Firmenlogo
* tm_company_name: text|Firmenname|Muster GmbH|Offizieller Firmenname
* tm_primary_color: colorselect|Akzentfarbe|#005d40:#005d40 Grün,#7D192C:#7D192C Rot,#1e87f0:#1e87f0 Blau|Hauptfarbe
* tm_contact_email: email|E-Mail|[email protected]|Kontakt E-Mail-Adresse
* tm_contact_phone: tel|Telefon|+49 123 456789|Kontakt-Telefonnummer
* tm_footer_links: linklist|Footer-Links||Artikel-IDs für Footer-Navigation
* tm_header_images: medialist|Header-Bilder||Bilder für Header-Slideshow
* tm_show_breadcrumbs: checkbox|Breadcrumbs anzeigen||Breadcrumb-Navigation aktivieren
*/
?>
<!DOCTYPE html>
<html>
<!-- Template-Code hier -->
</html>Wichtig:
- Der DocBlock muss in
<?php ... ?>eingebettet sein, damit er nicht als HTML ausgegeben wird - Alle Feldnamen müssen mit
tm_beginnen (Template Manager Prefix) - Nur Templates mit
tm_Prefix in den Settings werden als konfigurierbar erkannt
Jede Setting-Zeile folgt diesem Format:
tm_feldname: typ|Label|DefaultWert|Beschreibung
Wichtig: Alle Feldnamen müssen mit tm_ beginnen (Template Manager Prefix)!
Ab Version 1.3.0 können Einstellungen in thematische Gruppen organisiert werden:
Syntax:
--- Gruppenname ---
Optional mit Font Awesome 6 Icon:
--- Gruppenname [fa-solid fa-icon] ---
Optional mit Rechteverwaltung (nur für bestimmte Benutzergruppen sichtbar):
--- Gruppenname [admin,developer] ---
Beides kombiniert:
--- Gruppenname [fa-solid fa-icon] [admin,developer] ---
Beispiel:
/**
* DOMAIN_SETTINGS
*
* --- Branding & Design [fa-solid fa-palette] ---
* tm_company_name: text|Firmenname|Muster GmbH|Offizieller Firmenname
* tm_logo: media|Logo||Firmenlogo (Header)
* tm_primary_color: colorselect|Akzentfarbe|#005d40|Hauptfarbe
*
* --- Kontaktinformationen [fa-solid fa-address-book] ---
* tm_contact_email: email|E-Mail|[email protected]|Kontakt E-Mail
* tm_contact_phone: tel|Telefon|+49 123 456789|Telefonnummer
*
* --- Navigation & Links [fa-solid fa-bars] [admin,developer] ---
* tm_footer_links: linklist|Footer-Links||Artikel-IDs für Footer
* tm_show_breadcrumbs: checkbox|Breadcrumbs anzeigen||Navigation aktivieren
*/Features:
- Icons: Font Awesome 6 Icons (solid, brands, regular) werden automatisch vor dem Gruppennamen angezeigt
- Rechte: Admin sieht immer alles, andere Benutzer nur Gruppen ohne Rechte oder mit passender Rolle
- Accordion: Gruppen werden als Bootstrap-Akkordeons dargestellt, erste Gruppe standardmäßig geöffnet
- Ohne Gruppen: Alte Darstellung ohne Akkordeons bleibt erhalten
| Typ | Beschreibung | Beispiel Default |
|---|---|---|
| Text-Felder | ||
text |
Einzeiliges Textfeld | Beispieltext |
textarea |
Mehrzeiliges Textfeld | Längerer Text |
cke5 |
WYSIWYG Editor (CKE5) | <p>HTML Content</p> |
email |
E-Mail-Adresse mit Validierung | [email protected] |
url |
URL/Link (extern) | https://beispiel.de |
tel |
Telefonnummer | +49 123 456789 |
| Numerische Felder | ||
number |
Zahleneingabe (inkl. Dezimal) | 42 oder 3.14 |
| Datum/Zeit | ||
date |
Datum (YYYY-MM-DD) | 2024-01-15 |
datetime-local |
Datum + Zeit | 2024-01-15T10:30 |
time |
Uhrzeit | 14:30 |
| Farben | ||
color |
HTML5 Color Picker | #005d40 |
colorselect |
Vordefinierte Farben (Selectpicker mit Badges) | #005d40:Brand-Grün,#7D192C:Brand-Rot |
| Medien | ||
media |
Einzelne Mediendatei (natives Widget) | logo.png |
medialist |
Liste von Mediendateien (natives Widget) | bild1.jpg,bild2.jpg |
| Auswahl | ||
select |
Dropdown-Auswahl | wert1:Label 1,wert2:Label 2 |
checkbox |
Ja/Nein Checkbox | `` (leer = nicht aktiviert) |
| Links | ||
link |
Interner REDAXO-Link (natives Widget) | 5 (Artikel-ID) |
linklist |
Liste interner Links (natives Widget) | 1,5,8 (Artikel-IDs) |
external_linklist |
Externe Link-Liste mit Live-Vorschau | Name|URL|Beschreibung (ein Link pro Zeile) |
| Struktur | ||
category |
Kategorie-Auswahl (hierarchische Struktur) | 5 (Kategorie-ID) |
categorylist |
Mehrere Kategorien auswählen | 1,5,8 (Kategorie-IDs) |
| Spezial-Felder | ||
social_links |
Social Media Links Repeater | JSON (Icon + URL + Label) |
opening_hours |
Strukturierte Öffnungszeiten | JSON (Wochentage + Sonderzeiten) |
Der Feldtyp external_linklist ermöglicht die Verwaltung mehrerer externer Links mit Live-Vorschau im Backend:
Format: Ein Link pro Zeile im Format Name|URL|Beschreibung (Beschreibung optional)
Beispiel:
tm_footer_partners: external_linklist|Partner-Links||Externe Partner verlinken
Backend-Features:
- ✅ Live-Vorschau mit Validierung (zeigt Fehler sofort an)
- ✅ URL-Validierung (muss mit http:// oder https:// beginnen)
- ✅ Format-Hilfe direkt im Feld
- ✅ Kommentare möglich (Zeilen mit # oder // am Anfang)
- ✅ Monospace-Font für bessere Lesbarkeit
Eingabe-Beispiel:
WDFV|https://wdfv.de|Westdeutscher Fußballverband
FVN|https://fvn.de|Fußballverband Niederrhein
FVM|https://fvm.de|Fußballverband Mittelrhein
# Kommentare sind möglich
FLVW|https://flvw.de|Fußball- und Leichtathletik-Verband Westfalen
Frontend-Nutzung:
<?php
use FriendsOfRedaxo\TemplateManager\TemplateManager;
use FriendsOfRedaxo\TemplateManager\ExternalLinklistWidget;
// Variante 1: Direkt als HTML rendern
echo '<ul>';
echo ExternalLinklistWidget::renderHtml(
TemplateManager::get('tm_footer_partners'),
true // true = Links in neuem Tab öffnen
);
echo '</ul>';
// Variante 2: Als Array parsen für individuelle Verarbeitung
$links = ExternalLinklistWidget::parse(
TemplateManager::get('tm_footer_partners')
);
foreach ($links as $link) {
echo '<div class="partner-card">';
echo '<h3>' . rex_escape($link['name']) . '</h3>';
echo '<p>' . rex_escape($link['description']) . '</p>';
echo '<a href="' . rex_escape($link['url']) . '" target="_blank">';
echo 'Zur Website <i class="icon-external"></i>';
echo '</a>';
echo '</div>';
}
?>Rückgabe-Format der parse()-Methode:
[
[
'name' => 'WDFV',
'url' => 'https://wdfv.de',
'description' => 'Westdeutscher Fußballverband'
],
// ...
]Typische Verwendung:
- Footer-Links zu Verbänden/Partnern
- Social Media Links
- Externe Ressourcen
- Sponsor-Listen
- Tool/Service-Verzeichnisse
Bei select und colorselect Feldern werden die Optionen im Default-Wert definiert:
Select:
tm_header_style: select|Header-Stil|standard|standard:Standard,modern:Modern,minimal:Minimal|Auswahl des Header-Designs
Colorselect (mit visuellen Farb-Badges):
tm_primary_color: colorselect|Akzentfarbe|#005d40:#005d40 Brand-Grün,#7D192C:#7D192C Brand-Rot,#1e87f0:#1e87f0 Blau|Hauptfarbe
Format: wert:Label,wert2:Label2 oder einfach wert1,wert2,wert3
Hinweis: colorselect zeigt farbige Badges im Bootstrap Selectpicker an - ideal für vordefinierte Farbpaletten!
Der Feldtyp cke5 bietet einen vollwertigen WYSIWYG-Editor:
Beispiel mit Default-Profil:
tm_welcome_text: cke5|Willkommenstext||Editor-Inhalt mit HTML-Formatierung
Mit eigenem Profil (Profil im Default-Wert angeben):
tm_footer_text: cke5|Footer-Text|simple|Editor mit 'simple' Profil
tm_description: cke5|Beschreibung|full|Editor mit 'full' Profil
Features:
- Profil-Angabe im Default-Wert (leer = 'default')
- Automatische Sprach-Erkennung (User + Content)
- Fallback zu Textarea wenn CKE5 nicht verfügbar
- Unterstützt alle CKE5-Profile aus dem Backend
Frontend-Ausgabe:
<!-- Direktausgabe (HTML ist bereits formatiert) -->
<?= TemplateManager::get('tm_welcome_text') ?>
<!-- Mit Fallback -->
<?= TemplateManager::get('tm_welcome_text', '<p>Standard-Text</p>') ?>Wichtig: CKE5-Inhalte sind bereits HTML-formatiert und sollten nicht mit rex_escape() ausgegeben werden!
Der Feldtyp category bietet eine hierarchische Kategorie-Auswahl mit korrekter Struktur-Darstellung:
Beispiel:
tm_news_category: category|News-Kategorie|5|Kategorie für News-Artikel
tm_main_category: category|Hauptkategorie||Root-Kategorie auswählen
Features:
- Hierarchische Darstellung mit Einrückung
- Kategorie-IDs werden angezeigt: "Name [ID]"
- Berechtigungs-Prüfung (nur Kategorien mit Zugriff)
- "Homepage" Option für Root-Level (ID: 0)
- Berücksichtigt aktuelle Sprache
- Bootstrap Selectpicker mit Live-Search
Frontend-Nutzung:
<?php
use FriendsOfRedaxo\TemplateManager\TemplateManager;
// Kategorie-ID abrufen
$categoryId = TemplateManager::get('tm_news_category');
if ($categoryId) {
// Kategorie-Objekt laden
$category = rex_category::get($categoryId);
if ($category) {
echo '<h2>' . rex_escape($category->getName()) . '</h2>';
// Artikel der Kategorie auflisten
$articles = $category->getArticles();
foreach ($articles as $article) {
if (!$article->isStartArticle()) {
echo '<a href="' . $article->getUrl() . '">';
echo rex_escape($article->getName());
echo '</a><br>';
}
}
}
}
?>Typische Verwendung:
- News-Kategorie für Artikel-Listen
- Landingpage-Kategorie
- Produkt-Kategorie
- Filterkategorien
Der Feldtyp categorylist bietet Mehrfachauswahl von Kategorien mit hierarchischer Darstellung:
Beispiel:
tm_news_categories: categorylist|News-Kategorien||Mehrere Kategorien für News-Filter
tm_product_categories: categorylist|Produkt-Kategorien|5,8|Standard-Produkt-Kategorien
Features:
- Mehrfachauswahl mit Checkboxen
- Hierarchische Darstellung mit Einrückung
- Kategorie-IDs werden angezeigt: "Name [ID]"
- "Alle auswählen / Keine" Buttons
- Berechtigungs-Prüfung
- Bootstrap Selectpicker mit Live-Search
Frontend-Nutzung:
<?php
use FriendsOfRedaxo\TemplateManager\TemplateManager;
// Kategorie-IDs abrufen (komma-separiert)
$categoryIds = TemplateManager::get('tm_news_categories');
if ($categoryIds) {
$categoryIds = array_filter(array_map('intval', explode(',', $categoryIds)));
echo '<div class="category-filter">';
foreach ($categoryIds as $catId) {
$category = rex_category::get($catId);
if ($category) {
echo '<a href="' . $category->getUrl() . '" class="btn">';
echo rex_escape($category->getName());
echo '</a> ';
}
}
echo '</div>';
// Oder: Artikel aus allen ausgewählten Kategorien
$articles = [];
foreach ($categoryIds as $catId) {
$category = rex_category::get($catId);
if ($category) {
$articles = array_merge($articles, $category->getArticles());
}
}
// Artikel ausgeben...
}
?>Typische Verwendung:
- Mehrere News-Kategorien
- Produkt-Filtergruppen
- Content-Aggregation aus verschiedenen Bereichen
- Multi-Category Landing Pages
Der Feldtyp social_links bietet eine komfortable Verwaltung von Social Media Links mit Drag & Drop Sortierung:
Beispiel:
tm_social_links: social_links|Social Media Links||Verlinkte Social-Media-Profile
tm_social_links: social_links|Social Media Links|fa|Nur Font Awesome Icons
tm_social_links: social_links|Social Media Links|uk|Nur UIKit Icons
tm_social_links: social_links|Social Media Links|both|Beide Icon-Sets (Standard)
Icon-Modus (im Default-Wert):
fa- Nur Font Awesome Iconsuk- Nur UIKit Iconsbothoder leer - Beide Icon-Sets (Standard)
Backend-Features:
- ✅ 30+ vordefinierte Social Icons (Font Awesome + UIKit)
- ✅ Drag & Drop Sortierung mit Handle
- ✅ Pfeil-Buttons zum manuellen Sortieren
- ✅ Live Icon-Vorschau bei der Auswahl
- ✅ Optionales Label pro Link
- ✅ Icon-Set wählbar (fa, uk, both)
Enthaltene Icons:
- Facebook, Twitter/X, Instagram, LinkedIn, Xing, YouTube
- TikTok, Pinterest, WhatsApp, Telegram, GitHub, GitLab
- Discord, Slack, Mastodon, Threads, Bluesky, Reddit
- Snapchat, Vimeo, Dribbble, Behance, Flickr, Spotify
- SoundCloud, Twitch, RSS, E-Mail, Telefon, Webseite
Frontend-Nutzung:
<?php
use FriendsOfRedaxo\TemplateManager\TemplateManager;
$socialLinksJson = TemplateManager::get('tm_social_links');
$socialLinks = $socialLinksJson ? json_decode($socialLinksJson, true) : [];
if (!empty($socialLinks)): ?>
<div class="social-links">
<?php foreach ($socialLinks as $link):
if (empty($link['url'])) continue;
$icon = $link['icon'] ?? '';
$url = $link['url'];
$label = $link['label'] ?? '';
// Icon-Klasse ermitteln
if (str_starts_with($icon, 'uk-icon-')) {
// UIKit Icon
$ukIcon = str_replace('uk-icon-', '', $icon);
$iconHtml = '<span uk-icon="icon: ' . rex_escape($ukIcon) . '"></span>';
} else {
// Font Awesome (für FA6 CDN)
$brandIcons = ['fa-facebook', 'fa-twitter', 'fa-instagram', /* ... */];
$faClass = in_array($icon, $brandIcons, true)
? 'fa-brands ' . $icon
: 'fa-solid ' . $icon;
$iconHtml = '<i class="' . rex_escape($faClass) . '"></i>';
}
?>
<a href="<?= rex_escape($url) ?>"
target="_blank"
rel="noopener noreferrer"
<?= $label ? 'title="' . rex_escape($label) . '"' : '' ?>>
<?= $iconHtml ?>
</a>
<?php endforeach; ?>
</div>
<?php endif; ?>JSON-Datenstruktur:
[
{ "icon": "fa-facebook", "url": "https://facebook.com/firma", "label": "Facebook" },
{ "icon": "fa-instagram", "url": "https://instagram.com/firma", "label": "Instagram" },
{ "icon": "uk-icon-github", "url": "https://github.com/firma", "label": "" }
]Der Feldtyp opening_hours bietet eine professionelle Verwaltung von Öffnungszeiten wie bei Google My Business:
Beispiel:
tm_opening_hours: opening_hours|Öffnungszeiten||Geschäftszeiten inkl. Feiertage
Backend-Features:
- ✅ Reguläre Zeiten pro Wochentag (Mo-So)
- ✅ Mehrere Zeitfenster pro Tag (z.B. für Mittagspausen: 9-12 + 14-18 Uhr)
- ✅ Status-Optionen: Geöffnet / Geschlossen / 24h geöffnet
- ✅ Schnellaktionen: "Mo → Werktage", "Alle geschlossen", "Zurücksetzen"
- ✅ Kopier-Funktion: Zeiten auf andere Tage/Gruppen übertragen
- ✅ Sonderzeiten/Feiertage mit 15 vordefinierten deutschen Feiertagen
- ✅ Bewegliche Feiertage: Ostern, Pfingsten, Christi Himmelfahrt etc.
- ✅ Live-Vorschau mit Tabelle und "heute"-Markierung
- ✅ 3 Tabs: Reguläre Zeiten | Sonderzeiten | Vorschau
- ✅ Freitext/Notiz-Feld für zusätzliche Hinweise (z.B. "Termine nach Vereinbarung")
- ✅ Auto-Repair: Feiertage werden automatisch erkannt und repariert
Vordefinierte Feiertage:
- Neujahr, Karfreitag, Ostersonntag, Ostermontag
- Tag der Arbeit, Christi Himmelfahrt, Pfingstsonntag, Pfingstmontag
- Fronleichnam, Tag der Deutschen Einheit, Allerheiligen
- Heiligabend, 1. + 2. Weihnachtstag, Silvester
Frontend-Nutzung mit OpeningHoursHelper (empfohlen):
Die OpeningHoursHelper-Klasse bietet eine komfortable API mit Übersetzungen und vorformatierten Daten:
<?php
use FriendsOfRedaxo\TemplateManager\TemplateManager;
use FriendsOfRedaxo\TemplateManager\OpeningHoursHelper;
// Helper instanziieren (Sprache wird automatisch erkannt)
$helper = new OpeningHoursHelper(
TemplateManager::get('tm_opening_hours'),
rex_clang::getCurrent()->getCode() // 'de', 'en' etc.
);
if ($helper->hasData()):
$regularHours = $helper->getRegular(); // Alle Wochentage einzeln
$groupedHours = $helper->getRegularGrouped(); // Tage mit gleichen Zeiten zusammengefasst
$specialHours = $helper->getSpecial(5, true); // Max 5, nur zukünftige
$currentStatus = $helper->getCurrentStatus(); // Jetzt geöffnet?
?>
<!-- Status-Badge -->
<?php if ($currentStatus['is_open']): ?>
<span class="badge badge-success"><?= rex_escape($currentStatus['label']) ?></span>
<?php if ($currentStatus['next_change_label']): ?>
<small><?= rex_escape($currentStatus['next_change_label']) ?></small>
<?php endif; ?>
<?php else: ?>
<span class="badge badge-danger"><?= rex_escape($currentStatus['label']) ?></span>
<?php endif; ?>
<!-- Gruppierte Öffnungszeiten (empfohlen für kompakte Darstellung) -->
<h3><?= rex_escape($helper->translate('labels.opening_hours')) ?></h3>
<table>
<?php foreach ($groupedHours as $group): ?>
<tr<?= $group['contains_today'] ? ' class="today"' : '' ?>>
<td><?= rex_escape($group['label']) ?></td> <!-- z.B. "Mo - Fr" oder "Sa, So" -->
<td class="<?= $group['is_closed'] ? 'closed' : '' ?>">
<?= rex_escape($group['formatted']) ?>
</td>
</tr>
<?php endforeach; ?>
</table>
<!-- Freitext/Notiz anzeigen -->
<?php if ($helper->hasNote()): ?>
<p class="note"><em><?= rex_escape($helper->getNote()) ?></em></p>
<?php endif; ?>
<!-- Alternative: Alle Tage einzeln -->
<!--
<table>
<?php foreach ($regularHours as $day): ?>
<tr<?= $day['is_today'] ? ' class="today"' : '' ?>>
<td>
<?= rex_escape($day['label']) ?>
<?= $day['is_today'] ? ' <small>(' . rex_escape($helper->translate('labels.today')) . ')</small>' : '' ?>
</td>
<td class="<?= $day['is_closed'] ? 'closed' : '' ?>">
<?= rex_escape($day['formatted']) ?>
</td>
</tr>
<?php endforeach; ?>
</table>
-->
<!-- Sonderöffnungszeiten -->
<?php if (!empty($specialHours)): ?>
<h4><?= rex_escape($helper->translate('labels.special_hours')) ?></h4>
<ul>
<?php foreach ($specialHours as $special): ?>
<li>
<strong><?= rex_escape($special['display_name']) ?>:</strong>
<?= rex_escape($special['formatted']) ?>
</li>
<?php endforeach; ?>
</ul>
<?php endif; ?>
<?php endif; ?>OpeningHoursHelper - Verfügbare Methoden:
| Methode | Beschreibung |
|---|---|
hasData() |
Prüft ob Daten vorhanden sind |
getRegular(bool $shortLabels = false) |
Reguläre Zeiten als Array (jeden Tag einzeln) |
getRegularGrouped(bool $shortLabels = true) |
Aufeinanderfolgende Tage mit gleichen Zeiten zusammengefasst |
getSpecial(?int $limit, bool $futureOnly) |
Sonderzeiten als Array |
getToday() |
Heutigen Tag mit Status |
isOpenNow() |
Prüft ob aktuell geöffnet |
getCurrentStatus() |
Status-Array für "Jetzt geöffnet"-Anzeige |
getNote() |
Freitext/Notiz abrufen (z.B. "Termine nach Vereinbarung") |
hasNote() |
Prüft ob eine Notiz vorhanden ist |
translate(string $key) |
Übersetzung abrufen |
setLocale(string $locale) |
Sprache ändern |
setTranslations(string $locale, array $translations) |
Eigene Übersetzungen setzen |
Eigene Übersetzungen hinzufügen:
$helper = new OpeningHoursHelper($json);
// Französisch hinzufügen
$helper->setTranslations('fr', [
'weekdays' => [
'monday' => 'Lundi',
'tuesday' => 'Mardi',
// ...
],
'status' => [
'closed' => 'Fermé',
'open_24h' => 'Ouvert 24h/24',
'open' => 'Ouvert',
],
'labels' => [
'today' => "aujourd'hui",
'opening_hours' => "Heures d'ouverture",
'special_hours' => 'Horaires spéciaux',
'we_are_open' => 'Nous sommes ouverts',
'we_are_closed' => 'Nous sommes fermés',
'time_suffix' => 'h',
],
]);Datenstruktur der Arrays:
// getRegular() gibt zurück (jeden Tag einzeln):
[
'monday' => [
'key' => 'monday',
'label' => 'Montag', // Übersetzt
'label_short' => 'Mo', // Kurz
'label_full' => 'Montag', // Lang
'status' => 'open', // open, closed, 24h
'status_label' => 'Geöffnet', // Übersetzt
'is_today' => true, // Bool
'is_open' => true, // Bool
'is_closed' => false, // Bool
'is_24h' => false, // Bool
'times' => [ // Rohdaten
['open' => '09:00', 'close' => '12:00'],
['open' => '14:00', 'close' => '18:00'],
],
'times_formatted' => '09:00–12:00, 14:00–18:00 Uhr', // Formatiert
'formatted' => '09:00–12:00, 14:00–18:00 Uhr', // Status oder Zeiten
],
// ...
]
// getRegularGrouped() gibt zurück (aufeinanderfolgende Tage mit gleichen Zeiten zusammengefasst):
[
[
'label' => 'Mo - Fr', // Kurzform-Bereich
'label_full' => 'Montag - Freitag', // Langform-Bereich
'days' => ['monday', 'tuesday', 'wednesday', 'thursday', 'friday'],
'day_count' => 5,
'status' => 'open',
'status_label' => 'Geöffnet',
'is_open' => true,
'is_closed' => false,
'is_24h' => false,
'times' => [...],
'times_formatted' => '09:00–18:00 Uhr',
'formatted' => '09:00–18:00 Uhr',
'contains_today' => true, // Ist der aktuelle Tag in dieser Gruppe?
],
[
'label' => 'Sa, So', // Zwei aufeinanderfolgende Tage
'label_full' => 'Samstag, Sonntag',
'day_count' => 2,
'is_closed' => true,
'formatted' => 'Geschlossen',
'contains_today' => false,
],
]
// getSpecial() gibt zurück:
[
[
'date' => '12-24', // Originaldatum
'date_resolved' => '2026-12-24', // Aufgelöstes Datum
'date_formatted' => '24.12.', // Formatiert
'name' => 'Heiligabend', // Name
'display_name' => 'Heiligabend', // Name oder formatiertes Datum
'status' => 'open',
'status_label' => 'Geöffnet',
'is_holiday' => true, // Vordefinierter Feiertag
'is_open' => true,
'is_closed' => false,
'times' => [...],
'times_formatted' => '09:00–14:00 Uhr',
'formatted' => '09:00–14:00 Uhr',
],
// ...
]
// getCurrentStatus() gibt zurück:
[
'is_open' => true,
'label' => 'Wir haben geöffnet',
'today' => [...], // getToday() Daten
'next_change' => '18:00', // Nächste Statusänderung
'next_change_label' => 'Schließt um 18:00 Uhr',
]JSON-Datenstruktur:
{
"regular": {
"monday": {
"status": "open",
"times": [
{ "open": "09:00", "close": "12:00" },
{ "open": "14:00", "close": "18:00" }
]
},
"saturday": { "status": "closed", "times": [] },
"sunday": { "status": "closed", "times": [] }
},
"special": [
{
"date": "12-24",
"name": "Heiligabend",
"status": "open",
"times": [{ "open": "09:00", "close": "14:00" }],
"holiday": true
},
{
"date": "2026-01-02",
"name": "Betriebsferien",
"status": "closed",
"times": [],
"holiday": false
}
],
"note": "Termine nach Vereinbarung unter 0123-456789"
}Typische Verwendung:
- Geschäfts-/Ladenöffnungszeiten
- Praxis-/Kanzlei-Sprechstunden
- Restaurant-Öffnungszeiten mit Mittagspause
- Service-Hotline Erreichbarkeit
Die Settings werden über statische Methoden der TemplateManager Klasse abgerufen:
<?php
use FriendsOfRedaxo\TemplateManager\TemplateManager;
// Einfacher Zugriff (aktuelle Domain + Sprache)
$companyName = TemplateManager::get('tm_company_name');
$logo = TemplateManager::get('tm_logo');
// Mit Fallback-Wert
$primaryColor = TemplateManager::get('tm_primary_color', '#005d40');
// Bestimmte Sprache abrufen (z.B. Sprach-ID 2)
$companyNameEN = TemplateManager::get('tm_company_name', null, null, 2);
// Bestimmte Domain abrufen (z.B. Domain-ID 1)
$companyDomain1 = TemplateManager::get('tm_company_name', null, 1, null);
// Bestimmte Domain UND Sprache
$companyDomain1EN = TemplateManager::get('tm_company_name', null, 1, 2);
// Alle Settings als Array
$allSettings = TemplateManager::getAll();
?><!-- Logo anzeigen -->
<?php if (TemplateManager::get('tm_logo')): ?>
<img src="<?= rex_url::media(TemplateManager::get('tm_logo')) ?>" alt="Logo">
<?php endif; ?>
<!-- Firmenname mit Fallback -->
<h1><?= rex_escape(TemplateManager::get('tm_company_name', 'Muster GmbH')) ?></h1>
<!-- CKE5 WYSIWYG Inhalt (kein rex_escape!) -->
<?= TemplateManager::get('tm_welcome_text', '<p>Willkommen!</p>') ?>
<!-- E-Mail -->
<?php if (TemplateManager::get('tm_contact_email')): ?>
<a href="mailto:<?= rex_escape(TemplateManager::get('tm_contact_email')) ?>">
<?= rex_escape(TemplateManager::get('tm_contact_email')) ?>
</a>
<?php endif; ?>
<!-- Telefon -->
<?php if (TemplateManager::get('tm_contact_phone')): ?>
<a href="tel:<?= rex_escape(TemplateManager::get('tm_contact_phone')) ?>">
<?= rex_escape(TemplateManager::get('tm_contact_phone')) ?>
</a>
<?php endif; ?>
<!-- Linklist verarbeiten -->
<?php if (TemplateManager::get('tm_footer_links')): ?>
<ul>
<?php
$links = explode(',', TemplateManager::get('tm_footer_links'));
foreach ($links as $articleId) {
$article = rex_article::get(trim($articleId));
if ($article) {
echo '<li><a href="' . $article->getUrl() . '">' .
rex_escape($article->getName()) . '</a></li>';
}
}
?>
</ul>
<?php endif; ?>
<!-- Medialist verarbeiten -->
<?php if (TemplateManager::get('tm_header_images')): ?>
<div class="slideshow">
<?php
$images = explode(',', TemplateManager::get('tm_header_images'));
foreach ($images as $image) {
$image = trim($image);
if ($image) {
echo '<img src="' . rex_url::media($image) . '" alt="">';
}
}
?>
</div>
<?php endif; ?>
<!-- Checkbox prüfen -->
<?php if (TemplateManager::get('tm_show_breadcrumbs')): ?>
<!-- Breadcrumb-Code hier -->
<?php endif; ?>
<!-- CSS Custom Properties mit Colorselect -->
<style>
:root {
--primary-color: <?= TemplateManager::get('tm_primary_color', '#005d40') ?>;
--primary-dark: color-mix(in srgb, var(--primary-color) 80%, black);
}
</style>- Template Manager → Template Einstellungen öffnen
- Template aus Liste auswählen → Konfigurieren klicken
- Domain und Sprache wählen
- Einstellungen in den Sprach-Tabs eingeben
- Speichern klicken (speichert alle Sprachen gleichzeitig)
- Jede Sprache hat einen eigenen Tab
- Die erste Sprache dient als Fallback für andere Sprachen
- Leere Felder in Sprache 2+ werden automatisch durch Sprache 1 ersetzt
- Alle Sprachen werden gemeinsam gespeichert
- Jede YRewrite-Domain kann eigene Einstellungen haben
- Domain-Auswahl über Dropdown oben
- Default-Domain (ID 0) wird immer als letzte angezeigt
- Settings werden getrennt pro Domain + Sprache gespeichert
Template Manager → Setup → Demo-Template jetzt importieren
Importiert das vorkonfigurierte Modern Business Template mit 5 Einstellungen und modernem Design.
Template Manager → Setup → Verwaiste Settings entfernen
Entfernt Settings von gelöschten Templates aus der Datenbank. Nützlich wenn Templates gelöscht wurden und deren Settings verblieben sind.
Das Addon erstellt die Tabelle rex_template_settings:
| Spalte | Typ | Beschreibung |
|---|---|---|
| id | int | Primary Key |
| template_id | int | REDAXO Template-ID |
| domain_id | int | YRewrite Domain-ID |
| clang_id | int | Sprach-ID |
| setting_key | varchar(191) | Setting-Name (mit tm_ Prefix) |
| setting_value | text | Gespeicherter Wert |
| created_date | datetime | Erstellungsdatum |
| updated_date | datetime | Änderungsdatum |
UNIQUE KEY: (template_id, domain_id, clang_id, setting_key)
- Immer
tm_Prefix verwenden - Sprechende Namen:
tm_contact_emailstatttm_email1 - Gruppierung durch Prefix:
tm_footer_col1_title,tm_footer_col2_title
Gib immer sinnvolle Default-Werte an:
tm_company_name: text|Firmenname|Muster GmbH|Offizieller Firmenname
So funktioniert die Website auch ohne Konfiguration.
Im Template immer mit Fallback-Werten arbeiten:
<?= rex_escape(TemplateManager::get('tm_company_name', 'Meine Firma')) ?>Die Methode gibt den Default-Wert zurück, wenn das Setting nicht existiert.
Nutze das Beschreibungs-Feld für Hinweise:
tm_google_analytics: text|Google Analytics ID||GA4 Tracking-ID (Format: G-XXXXXXXXXX)
<?php
/**
* Simple Business Template
*
* DOMAIN_SETTINGS
* tm_logo: media|Logo||Firmenlogo
* tm_company_name: text|Firmenname|Muster GmbH|Firmenname
* tm_contact_email: email|E-Mail|[email protected]|Kontakt E-Mail
* tm_primary_color: text|Akzentfarbe|#005d40|Akzentfarbe (Hex)
* tm_footer_text: textarea|Footer-Text|© 2024 Muster GmbH|Copyright-Text
*/
use FriendsOfRedaxo\TemplateManager\TemplateManager;
?>
<!DOCTYPE html>
<html>
<head>
<title><?= $this->getValue('name') ?> | <?= TemplateManager::get('tm_company_name') ?></title>
<style>
:root { --primary: <?= TemplateManager::get('tm_primary_color', '#005d40') ?>; }
body { font-family: sans-serif; }
header { background: var(--primary); color: white; padding: 1rem; }
</style>
</head>
<body>
<header>
<?php if (TemplateManager::get('tm_logo')): ?>
<img src="<?= rex_url::media(TemplateManager::get('tm_logo')) ?>" alt="Logo">
<?php endif; ?>
<h1><?= TemplateManager::get('tm_company_name') ?></h1>
</header>
<main><?= $this->getArticle() ?></main>
<footer>
<p><?= nl2br(rex_escape(TemplateManager::get('tm_footer_text'))) ?></p>
<a href="mailto:<?= TemplateManager::get('tm_contact_email') ?>">Kontakt</a>
</footer>
</body>
</html>use FriendsOfRedaxo\TemplateManager\TemplateParser;
use FriendsOfRedaxo\TemplateManager\TemplateManager;Der Parser sucht nach diesem Pattern:
#\*\s+(tm_\w+):\s*([^|]+)\|([^|]*)\|([^|]*)\|(.*)$#mNur Zeilen mit tm_ Prefix werden erfasst!
1 Bei jedem Frontend-Request:
- TemplateManager::get() wird aufgerufen
- Beim ersten Aufruf: Cache wird geladen
- Aktuelle Domain + Sprache werden automatisch ermittelt
- Settings aus DB geladen mit Fallback-Logik
- Ergebnis wird pro Request gecacht (nach Domain/Sprach-Kombination)
TemplateManager::get(
string $key, // Setting-Key (z.B. 'tm_company_name')
mixed $default = null, // Fallback wenn nicht vorhanden
?int $domainId = null, // Optional: Domain-ID (null = aktuelle)
?int $clangId = null // Optional: Sprach-ID (null = aktuelle)
): mixed
TemplateManager::getAll(
?int $domainId = null, // Optional: Domain-ID (null = aktuelle)
?int $clangId = null // Optional: Sprach-ID (null = aktuelle)
): array- REDAXO: >= 5.17
- YRewrite: >= 2.0 (für Multi-Domain Support)
- PHP: >= 8.0
- Optional: UIKit Theme Builder (für
uikit_theme_selectFeldtyp)
MIT License
- ✨ Neuer Feldtyp:
external_linklistfür externe Link-Listen mit Live-Vorschau - 🎨 Repeater-Funktionalität: Strukturierte externe Links (Name|URL|Beschreibung)
- 🔍 Live-Validierung: URL-Prüfung und Format-Feedback im Backend
- 📝 Kommentar-Support: Zeilen mit # oder // werden ignoriert
- 🎯 ExternalLinklistWidget: Neue Helper-Klasse mit parse() und renderHtml() Methoden
- 🏗️ Architektur: Eigener FieldRenderer statt textarea-Missbrauch
- 📚 Dokumentation: Umfassende Beispiele für external_linklist Nutzung
- ✨ Neue Feldtypen:
banner_selectfür UIKit Banner Design Integration - 🎨 Footer Design: Professionelle rechtliche Gestaltung mit kompakten Link-Abständen
- 📱 Mobile Optimierung: Verbesserte Navigation mit größerem Hamburger-Icon
- 🌐 Multi-Column Footer: Unterstützung für flexible Grid-Layouts
- ♿ Accessibility: Responsive Legal-Navigation mit verbesserter Mobile-Darstellung
- 🎉 Erste öffentliche Version
- 📝 DocBlock-basierte Konfiguration
- 🌍 Multi-Domain Support mit YRewrite
- 🌐 Mehrsprachigkeit mit Fallback-Logik
- 🎨 20+ Feldtypen
- 🔧 Native REDAXO Widgets
- 🚀 Statische Frontend-API
- 📦 Demo-Template
- GitHub Issues: https://github.com/FriendsOfREDAXO/template_manager/issues
- GitHub Repository: https://github.com/FriendsOfREDAXO/template_manager
Entwickelt von Friends Of REDAXO