Skip to content

widget_menu — field types

widget_menu inside the widget JSON defines the form editors fill in via the Pagebuilder properties panel. Each entry describes exactly one field — from a single-line text to sub-item repeaters. This page lists every field type with its schema and real examples.

Base structure

Every field is a JSON object with at least row and type:

json
{
  "row":         "title",
  "type":        "text",
  "placeholder": "Title"
}
FieldRequiredPurpose
rowyes (except items)DB column in page_row_col_widget — see Available DB columns
typeyesField type — see the types below
placeholdernoLabel in the properties panel
select_valuefor select (DB){table, value, title, options: []}
optionsfor select (static)[{id, title}, ...]
menufor itemsSub-menu definition for repeater items

Field type overview

TypeRenders asData target
textSingle-line inputpage_row_col_widget.{row}
textareaMulti-line inputpage_row_col_widget.{row}
filemanagerMedia picker buttonpage_row_col_widget.{row} (JSON with media ID)
select (static)Dropdown with inline optionspage_row_col_widget.{row}
select (DB)Dropdown from a DB tablepage_row_col_widget.{row}
itemsSub-items repeaterpage_widget_item table

On save, form values are written to this widget's page_row_col_widget row. Items land in a separate table (see Widget items / repeater).

text — single-line input

For titles, links, slugs, short labels.

json
{"row": "title", "type": "text", "placeholder": "Title"}

Access in the Vue template: widget.data?.title. Access in getWidgetContent($widget_array): $widget_array['widget_title'].

row: "text" uses the key widget_html

When a field has "row": "text" (e.g. for an HTML block), the key in $widget_array is widget_html, not widget_text. The remap happens in PageService.php (the key name makes the HTML-content semantic of the column explicit). Details: getWidgetContent() › widget_array keys.

textarea — multi-line input

For longer texts, simple HTML blocks, short descriptions.

json
{"row": "text", "type": "textarea", "placeholder": "Text / HTML"}

Access: widget.data?.text in the Vue template, $widget_array['widget_html'] in PHP.

textarea does not ship a rich-text editor. For CKEditor fields inside a Pagebuilder widget form, there is currently no official field-type mapping — widgets either use textarea with HTML freedom, or load CKEditor per page, not per field.

filemanager — image/media

Opens the Media Manager as a modal. The editor picks a file; the widget value is stored as the JSON [{"id":"123"}].

json
{"row": "image", "type": "filemanager", "placeholder": "Image"}

Resolution to the full URL happens in getWidgetContent() via files::loadURL():

php
$current_item['image'] = files::loadURL($dsatz_news['image']);

The Vue template then receives a ready-to-use URL at widget.content.items[0].image. If you want to render images directly from widget.data.image, you have to parse it yourself.

select (static)

Dropdown with hard-coded options. Example from the Title widget (widgetsBase/bootstrap.php):

json
{
  "row":         "subtitle",
  "type":        "select",
  "placeholder": "Type",
  "value":       "id",
  "title":       "title",
  "options": [
    {"id": "0", "title": "H1"},
    {"id": "1", "title": "H2"},
    {"id": "2", "title": "H3"}
  ]
}
FieldPurpose
optionsInline array with options
valueKey of the options object that gets stored
titleKey shown in the dropdown

Legacy format

The static select variant uses value/title fields directly at the field level — without a select_value wrapper. That's the legacy format, but the widget form still supports it and it's convenient for inline options. For DB selects, use the new variant (see below).

select (DB-backed)

Dropdown with options from a DB table. The editor sees the title values and the value key (e.g. id) gets stored.

json
{
  "row":         "subtitle",
  "type":        "select",
  "placeholder": "Product",
  "select_value": {
    "table":   "s_products",
    "value":   "id",
    "title":   "title",
    "options": []
  }
}
select_value fieldPurpose
tableDB table to read from
valueColumn stored as the value
titleColumn shown in the dropdown
optionsMust be empty ([]) — populated by the backend at render time

select_value is required for DB selects

The old format with table/value/title directly at the field level (without a select_value wrapper) is still supported for backwards compatibility but is deprecated. For new widgets, always use select_value.

Inside getWidgetContent(), the selected value arrives as an ID:

php
$productId = (int) $widget_array['widget_subtitle'];
$q = query("SELECT title, price FROM s_products WHERE id = $productId LIMIT 1");

items — repeater

For lists of similar sub-elements (FAQ entries, USP icons, testimonials, gallery images). Items live in the separate page_widget_item table with the base_id/language_short pattern.

json
{
  "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 fieldPurpose
typeAlways "items"
placeholderLabel of the sub-list in the properties panel
menuArray of field types — describes the fields per item

items has no row — items go into page_widget_item, not into a column of page_row_col_widget. Details: Widget items / repeater.

Available DB columns

row must match the name of a column in page_row_col_widget exactly. The full list:

rowTypeCommonly used for
titletinytextWidget title, main text
subtitletinytextSubtitle, select value, type
textmediumtextHTML/text content (PHP key: widget_html!)
linktinytextURL, link
imagetinytextImage (filemanager JSON)
gallerytinytextGallery data
logotinytextLogo image
colortinytextColor
pricetinytextPrice
sale_statustinytextSale status
locationtinytextLocation
vcardtinytextvCard data
videotinytextVideo URL
short_texttinytextShort text
maptinytextMap data
accordiontinytextAccordion data
sliderrevolutiontinytextSlider-Revolution ID
pagebuildertinytextPagebuilder page ID
formtinytextForm ID

row with an unknown column

If you write "row": "myCustomField", the value is discarded on save — the column does not exist in page_row_col_widget. The editor sees the field in the properties panel, but the entered value vanishes on the next page load. Never add new columns to page_row_col_widget — for structured extra data, repurpose one of the existing slots semantically (e.g. subtitle for a second text block) or use an items repeater.

image2, pname, dateStart, dateEnd exist only in page_widget_item

These columns exist only in the items table, not in page_row_col_widget. Using them in the top-level widget menu leads to the same silent drop behavior as above.

Complete widget menu — example

From the titleBanner widget or similarly structured banners:

json
{
  "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"}
  ]
}

Five fields, no items, no DB selects — a standard content block. More complex widgets (shop listing, e-learning, menu editor widget) add items plus getWidgetContent().

Common issues

Fields without row (except items)

Every field type except items needs a row. Without it, the form stores the value nowhere — the editor types, the field appears to work, and on reload the value is gone.

Mixing select_value with inline options

  • Static options → put options: [...] with value + title at the field level (legacy format, still fine).
  • DB options → put select_value: {table, value, title, options: []} as a wrapper. Combining both in parallel, or using a DB select without select_value, will fail.

items.menu instead of items.widget_menu

The sub-field on items is called menu, not widget_menu. Confusing the two leads to an empty repeater.

type is case-sensitive

"type": "Text" is not recognized as text — field types are lowercase. Same for every other type.

See also