widget_menu — Feldtypen
widget_menu im Widget-JSON definiert das Formular, das Redakteure im Pagebuilder-Properties-Panel ausfuellen. Jeder Eintrag beschreibt genau ein Feld — von einzeiligem Text bis zu Sub-Item-Repeatern. Diese Seite listet alle Feldtypen mit Schema und echten Beispielen.
Grundstruktur
Jedes Feld ist ein JSON-Objekt mit mindestens row und type:
{
"row": "title",
"type": "text",
"placeholder": "Title"
}| Feld | Pflicht | Zweck |
|---|---|---|
row | ja (ausser items) | DB-Spalte in page_row_col_widget — siehe verfuegbare DB-Spalten |
type | ja | Feldtyp — siehe untenstehende Typen |
placeholder | nein | Label im Properties-Panel |
select_value | bei select (DB) | {table, value, title, options: []} |
options | bei select (statisch) | [{id, title}, ...] |
menu | bei items | Sub-Menu-Definition fuer Repeater-Items |
Feldtyp-Uebersicht
| Typ | Rendert als | Daten-Target |
|---|---|---|
text | einzeiliges Input | page_row_col_widget.{row} |
textarea | mehrzeiliges Input | page_row_col_widget.{row} |
filemanager | Media-Picker-Button | page_row_col_widget.{row} (JSON mit Media-ID) |
select (statisch) | Dropdown mit Inline-Options | page_row_col_widget.{row} |
select (DB) | Dropdown aus DB-Tabelle | page_row_col_widget.{row} |
items | Sub-Items-Repeater | page_widget_item-Tabelle |
Formular-Werte werden beim Speichern in die page_row_col_widget-Zeile dieses Widgets geschrieben. Items landen in einer separaten Tabelle (siehe Widget-Items / Repeater).
text — einzeilige Eingabe
Fuer Titel, Links, Slugs, kurze Labels.
{"row": "title", "type": "text", "placeholder": "Title"}Zugriff im Vue-Template: widget.data?.title. Zugriff in getWidgetContent($widget_array): $widget_array['widget_title'].
row: "text" nutzt Key widget_html
Wenn ein Feld "row": "text" hat (z. B. fuer einen HTML-Block), ist der Key in $widget_array widget_html, nicht widget_text. Das Remapping passiert in PageService.php (Key-Name macht die HTML-Content-Semantik der Spalte explizit). Details: getWidgetContent() › Key-Mapping.
textarea — mehrzeilige Eingabe
Fuer laengere Texte, einfache HTML-Blocks, kurze Beschreibungen.
{"row": "text", "type": "textarea", "placeholder": "Text / HTML"}Zugriff: widget.data?.text im Vue-Template, $widget_array['widget_html'] in PHP.
textarea hat keinen Rich-Text-Editor. Fuer CKEditor-Felder im Pagebuilder-Widget-Formular gibt es derzeit kein offizielles Feldtyp-Mapping — Widgets nutzen entweder textarea mit HTML-Freiheit oder laden den CKEditor nicht pro Feld, sondern pro Seite.
filemanager — Bild/Media
Oeffnet den Media Manager als Modal. Der Redakteur waehlt eine Datei, der Widget-Wert wird als JSON [{"id":"123"}] gespeichert.
{"row": "image", "type": "filemanager", "placeholder": "Image"}Aufloesung zur vollen URL passiert in getWidgetContent() via files::loadURL():
$current_item['image'] = files::loadURL($dsatz_news['image']);Im Vue-Template steht dann eine fertige URL unter widget.content.items[0].image. Wer Bilder direkt aus widget.data.image rendern will, muss selbst parsen.
select (statisch)
Dropdown mit fest eincodierten Optionen. Beispiel aus dem Title-Widget (widgetsBase/bootstrap.php):
{
"row": "subtitle",
"type": "select",
"placeholder": "Typ",
"value": "id",
"title": "title",
"options": [
{"id": "0", "title": "H1"},
{"id": "1", "title": "H2"},
{"id": "2", "title": "H3"}
]
}| Feld | Zweck |
|---|---|
options | Inline-Array mit Optionen |
value | Key des Options-Objekts, der gespeichert wird |
title | Key, der im Dropdown angezeigt wird |
Legacy-Format
Die statische select-Variante verwendet direkte value/title-Felder auf der Feld-Ebene — ohne select_value-Wrapper. Das ist das Legacy-Format, wird aber vom Widget-Formular noch unterstuetzt und ist fuer inline-Optionen bequem. Fuer DB-Selects nutzt man die neue Variante (siehe unten).
select (DB-basiert)
Dropdown mit Optionen aus einer DB-Tabelle. Der Redakteur sieht title-Werte und der value-Key (z. B. id) wird gespeichert.
{
"row": "subtitle",
"type": "select",
"placeholder": "Product",
"select_value": {
"table": "s_products",
"value": "id",
"title": "title",
"options": []
}
}select_value-Feld | Zweck |
|---|---|
table | DB-Tabelle, aus der gelesen wird |
value | Spalte, die als Wert gespeichert wird |
title | Spalte, die im Dropdown angezeigt wird |
options | Muss leer sein ([]) — wird beim Rendern vom Backend gefuellt |
select_value ist Pflicht fuer DB-Selects
Das alte Format mit direkten table/value/title auf Feld-Ebene (ohne select_value-Wrapper) bleibt aus Kompatibilitaetsgruenden unterstuetzt, ist aber deprecated. Fuer neue Widgets immer select_value verwenden.
Im getWidgetContent() kommt der gewaehlte Wert direkt als ID:
$productId = (int) $widget_array['widget_subtitle'];
$q = query("SELECT title, price FROM s_products WHERE id = $productId LIMIT 1");items — Repeater
Fuer Listen gleichartiger Sub-Elemente (FAQ-Eintraege, USP-Icons, Testimonials, Galerie-Bilder). Items leben in der separaten Tabelle page_widget_item mit base_id/language_short-Pattern.
{
"type": "items",
"placeholder": "Testimonials",
"menu": [
{"row": "title", "type": "text", "placeholder": "Name"},
{"row": "subtitle", "type": "text", "placeholder": "Position"},
{"row": "text", "type": "textarea", "placeholder": "Quote"},
{"row": "image", "type": "filemanager", "placeholder": "Avatar"}
]
}items-Feld | Zweck |
|---|---|
type | immer "items" |
placeholder | Label der Sub-Liste im Properties-Panel |
menu | Array von Feldtypen — beschreibt die Felder pro Item |
items hat kein row — Items landen in page_widget_item, nicht in einer Spalte von page_row_col_widget. Details: Widget-Items / Repeater.
Verfuegbare DB-Spalten
row muss exakt dem Namen einer Spalte in page_row_col_widget entsprechen. Die komplette Liste:
row | Typ | Haeufig verwendet fuer |
|---|---|---|
title | tinytext | Widget-Titel, Haupttext |
subtitle | tinytext | Untertitel, Select-Wert, Typ |
text | mediumtext | HTML/Text-Inhalt (PHP-Key: widget_html!) |
link | tinytext | URL, Link |
image | tinytext | Bild (Filemanager-JSON) |
gallery | tinytext | Galerie-Daten |
logo | tinytext | Logo-Bild |
color | tinytext | Farbe |
price | tinytext | Preis |
sale_status | tinytext | Verkaufsstatus |
location | tinytext | Ort |
vcard | tinytext | vCard-Daten |
video | tinytext | Video-URL |
short_text | tinytext | Kurztext |
map | tinytext | Karten-Daten |
accordion | tinytext | Akkordeon-Daten |
sliderrevolution | tinytext | Slider-Revolution-ID |
pagebuilder | tinytext | Pagebuilder-Seiten-ID |
form | tinytext | Formular-ID |
row mit unbekannter Spalte
Gibt man "row": "myCustomField" an, wird der Wert beim Speichern verworfen — die Spalte existiert nicht in page_row_col_widget. Der Redakteur sieht das Feld zwar im Properties-Panel, der eingegebene Wert verschwindet aber beim naechsten Page-Load. Keine neuen Spalten zu page_row_col_widget hinzufuegen — fuer strukturierte Zusatzdaten stattdessen einen der vorhandenen Slots semantisch umwidmen (z. B. subtitle fuer einen zweiten Textblock) oder ein items-Repeater nutzen.
image2, pname, dateStart, dateEnd existieren nur in page_widget_item
Diese Spalten gibt es nur in der Items-Tabelle, nicht in page_row_col_widget. Verwendung im Top-Level-Widget-Menu fuehrt zu derselben stillen Daten-Drop-Logik wie oben.
Komplettes Widget-Menu — Beispiel
Aus dem titleBanner-Widget oder aehnlich strukturierten Bannern:
{
"widget_title": "Title Banner",
"widget_icon": "icon.png",
"widget_subtitle": "Banner with title, subtitle and background image",
"widget_template": "titleBanner",
"widget_menu": [
{"row": "title", "type": "text", "placeholder": "Title"},
{"row": "subtitle", "type": "text", "placeholder": "Subtitle"},
{"row": "image", "type": "filemanager", "placeholder": "Background"},
{"row": "link", "type": "text", "placeholder": "Link URL"},
{"row": "short_text", "type": "textarea", "placeholder": "Button label"}
]
}Fuenf Felder, keine Items, keine DB-Selects — ein Standard-Content-Block. Fuer komplexere Widgets (Shop-Listing, E-Learning, Menueditor-Widget) kommt items plus getWidgetContent() dazu.
Haeufige Fehler
Felder ohne row (ausser items)
Jeder Feldtyp ausser items braucht ein row. Fehlt es, speichert das Formular den Wert nirgends — Redakteur tippt, Feld scheint zu funktionieren, beim Reload ist der Wert weg.
select_value vs. Inline-Options verwechseln
- Statische Options → direkt
options: [...]mitvalue+titleauf Feld-Ebene (Legacy-Format, aber ok). - DB-Options →
select_value: {table, value, title, options: []}als Wrapper. Mischform (beide parallel) oder DB-Select ohneselect_valueschlaegt fehl.
items.menu statt items.widget_menu
Das Sub-Feld bei items heisst menu, nicht widget_menu. Verwechslung fuehrt zu leerem Repeater.
type case-sensitive
"type": "Text" wird nicht als text erkannt — Feldtyp ist kleingeschrieben. Analog fuer alle anderen Typen.
Siehe auch
- Widget-Anatomie — wo
widget_menuim JSON lebt - getWidgetContent() — wie Formular-Werte und dynamische Daten in PHP zusammenkommen
- Widget-Items / Repeater —
items-Feldtyp im Detail - Custom-CSS-Konvention —
.widget_{id}-Klasse pro Widget-Instanz - Plugins › Buttons — dieselben Feldtypen im Plugin-Modal-Kontext