Naslag
Veldtypen
De ondersteunde veldtypen en hun instellingen.
Veldtypen
| Type | Beschrijving |
|---|---|
text |
Tekst op één regel |
textarea |
Platte tekst op meerdere regels |
html |
Opgemaakte tekst (bubble-editor en veldbalk, zie Editorknoppen) |
slug |
URL-veilig slugveld, berekend uit de ingestelde bronvelden |
boolean |
Schakelaar waar/onwaar |
date |
Datumkiezer |
email |
E-mailadres |
url |
URL |
password |
Versleuteld wachtwoordveld |
image |
Upload van één afbeelding |
file |
Upload van één bestand |
upload |
Algemene upload |
gallery |
Upload van meerdere afbeeldingen |
select |
Keuzelijst, met vaste opties of uit een resource |
number |
Getalinvoer, met optioneel min en max |
color |
Kleurkiezer |
location-picker |
Interactieve wereldkaart die de breedtegraad in het veld bewaart en de lengtegraad in het bijbehorende veld uit longitude_field |
Namen van veldtypen moeten precies kloppen.
Veldinstellingen
Gangbare opties per veld:
| Sleutel | Type | Beschrijving |
|---|---|---|
name |
string | Label in de admin |
required |
boolean | Validatie; zet dit op alle titel- en naamvelden |
admin_col |
boolean | Tonen in de overzichtstabel van de admin (standaard: true) |
admin_filter |
boolean of object | Voegt een filter toe aan het overzicht van de admin voor een veld select of boolean. Gebruik { "default": <stored-value> } om het aan te zetten met een standaardkeuze, en optioneel "feature": "permission-name" om het alleen te tonen aan gebruikers met dat recht. Los van admin_col. |
multi |
boolean | Meerdere waarden toestaan |
i18n |
boolean | Per taal vertalen |
accept |
string | Beperking van bestandstypen voor image- en file-velden |
HTML-velden gebruiken uitdrukkelijk een van twee instellingen:
Eenvoudig (korte tekstblokken, zoals een intro):
"buttons": "bold,italic",
"admin_col": false
Uitgebreid (volledige content, zoals een body):
"buttons": "h2,h3,h4,bold,italic,orderedlist,unorderedlist,quote,anchor",
"media": true,
"media_sizes": "sm-90,md-70,lg-60,xl-50,xxl-40",
"admin_col": false
Definieer nooit een html-veld zonder een van deze te kiezen. media_sizes is verplicht bij media: true.
Editorknoppen. buttons noemt de opmaakknoppen van een html-veld, in volgorde. Zonder buttons krijgt een veld bold,italic,removeFormat. Ingebouwd:
| Knop | Doet |
|---|---|
bold, italic |
Opmaak in de tekst (Ctrl/Cmd+B, Ctrl/Cmd+I) |
h2, h3, h4, quote, pre |
Blokopmaak; nog een keer maakt er weer een alinea van |
orderedlist, unorderedlist |
Lijsten |
anchor |
Link: toevoegen, bewerken (vooraf ingevuld) of verwijderen; Ctrl/Cmd+K |
removeFormat |
Opmaak wissen |
strikethrough, subscript, superscript, underline |
Optioneel, in geen enkele standaardset |
Dezelfde knoppen staan op twee plekken: de bubble-werkbalk bij geselecteerde tekst, en de veldbalk. In admin-formulieren hoort de veldbalk bij het veld; bij inline bewerken zweeft hij boven het actieve veld en bevat hij ook Media (bij media: true) en Save (Ctrl/Cmd+S). Alt+F10 zet de toetsenbordfocus op de veldbalk. Plakken houdt alleen platte tekst over, tenzij het veld "paste_html": true zet; dat houdt basisopmaak vast en haalt de markup van Word en Google Docs weg.
Eigen editorknoppen. Een project definieert eigen knoppen als JSON in ext/tpl/bubble-editor-buttons/index.tpl (de template mag shortcodes gebruiken, zoals [#text ...#] voor labels), en noemt ze dan net als de ingebouwde in de buttons van een veld:
{
"highlight": { "kind": "wrap", "tag": "mark", "label": "[#text Highlight#]", "icon": "M" },
"h5": { "kind": "block", "tag": "h5", "label": "Heading 5", "icon": "H5" },
"poi": {
"kind": "event", "event": "nb:insert-point", "insert": true, "bubble": true,
"active": "[data-poi-link]", "label": "[#text Point of interest#]", "icon": "<svg ...></svg>"
}
}
| Soort | Doet |
|---|---|
command |
Een opmaakcommando ("command": "bold") |
block |
Blokopmaak ("tag": "h5") |
list |
Lijstcommando |
wrap |
Zet de selectie in een element ("tag", optioneel "class"); nog een keer haalt het weg |
insert |
Voegt vaste HTML in bij de cursor ("html") |
event |
Stuurt een DOM-event op het veld ("event", bubbling, detail: { editor, range }) voor eigen code van het project, bijvoorbeeld om een kiezer te openen |
link |
Vraagt om een URL, zoals anchor |
Opties: "insert": true zet een knop naast Media in de veldbalk in plaats van bij de opmaakknoppen; voeg "bubble": true toe als hij ook op geselecteerde tekst werkt; "active" is een selector die de knop actief toont als de cursor in een match staat. Links zijn a[href]: een project mag <a> zonder href gebruiken voor eigen elementen in de tekst. Code kan ook knoppen registreren met nb.bubble_editor.register(name, { label, icon, run(ctx), is_active(ctx) }).
De bewerktools van een project (de modal en het script achter een event-knop) staan in ext/tpl/edit-extras/index.tpl, die wordt getoond voor gebruikers die inline mogen bewerken, op pagina's van de site en van de admin.
Slugvelden:
Slugs zijn aparte velden. Zet geen "slug": true op een ander veld. Definieer een apart veld met "type": "slug" en een source die wijst naar het veld of de velden waar hij van wordt afgeleid.
Het admin-formulier berekent de slug in de browser uit de bronvelden, voordat het formulier wordt verstuurd. De API verzint bij het opslaan geen ontbrekende slugvelden; hij bewaart de waarde van het slugveld die hij krijgt. Maakt of importeert code records buiten het admin-formulier om, dan moet die code ook de waarde van het slugveld zetten.
Zet "preserve_existing": true op het slugveld om ontbrekende slugs te maken terwijl opgeslagen URL's gelijk blijven als het formulier opent of de brontitel verandert. Redacteuren kunnen een opgeslagen slug nog steeds bewust aanpassen.
"url_slug": {
"name": "URL slug",
"type": "slug",
"source": "title",
"admin_col": false
}
Meerdere bronnen scheid je met komma's; de waarden worden met een spatie samengevoegd voordat er een slug van wordt gemaakt:
"url_slug": {
"name": "URL slug",
"type": "slug",
"source": "title,date",
"admin_col": false
}
Met "source": "title,date", titel "Jazz Night" en datum "2026-04-09" wordt de slug jazz-night-2026-04-09. Zet url_slug altijd in de lijst index van de resource, zodat hij in route.inc kan worden opgezocht.
Is het bronveld i18n, dan wordt het slugveld ook als i18n behandeld. Zo geven title.nl, title.en en title.fr overeenkomende waarden onder title_slug.nl, title_slug.en en title_slug.fr. Vertaal slugs niet met de hand; laat het slugveld ze afleiden uit de bronwaarden per taal.
Selectievelden:
Vaste opties:
"type": "select",
"options": {
"new": "New",
"active": "Active",
"closed": "Closed"
}
Opties uit een andere resource:
"type": "select",
"resource": "categories"
Filters in het overzicht van de admin zet je per veld aan voor select- en boolean-velden:
"status": {
"type": "select",
"options": { "active": "Active", "closed": "Closed" },
"admin_filter": { "default": "active" }
},
"published": {
"type": "boolean",
"admin_col": false,
"admin_filter": true
}
Filters vergelijken de ruwe opgeslagen waarden, terwijl ze de ingestelde opties of labels van de gekoppelde resource tonen. Selecties met meerdere waarden passen als het record de gekozen waarde bevat. Meerdere filters worden met EN gecombineerd en blijven werken met zoeken, sorteren en pagineren. Keuzes blijven in de URL staan als filter[field]=value. Een ontbrekende parameter gebruikt de ingestelde standaard; een lege parameter kiest uitdrukkelijk All. Ongeldige waarden in de URL worden All.
Locatievelden:
Gebruik location-picker als redacteuren coördinaten op een kaart moeten kiezen in plaats van ze te typen. Het kiezerveld bewaart de breedtegraad in zijn eigen veld en werkt een apart numeriek veld voor de lengtegraad bij, genoemd in longitude_field. Verberg het bijbehorende veld met wrapper_class: "hidden", zodat de redacteur één bedieningselement ziet terwijl de resource eenvoudige losse coördinaten bewaart:
"location_lat": {
"name": "Location",
"type": "location-picker",
"longitude_field": "location_lng",
"required": true,
"admin_col": false
},
"location_lng": {
"name": "Longitude",
"type": "number",
"required": true,
"min": -180,
"max": 180,
"wrapper_class": "hidden",
"admin_col": false
}
Hoe formuliervelden worden opgebouwd
Deze sectie beschrijft de hele weg van een velddefinitie in een resource tot een getoond formulierveld. Lees dit voordat je een nieuw veldtype bouwt.
Overzicht
.meta field definition
↓
render_field() - PHP (core/modules/forms/lib/render-field.php)
↓
_f.* template variables
↓
[#field-{type}#] template (core/modules/forms/tpl/field-{type}/index.tpl)
↓
Alpine.js form_data.{field} ← x-model binding
↓
API POST/PUT on submit
render_field() en de context _f.*
render_field() is de ingang. Het:
- Neemt een array met de velddefinitie, de sleutel van het veld, en optionele parameters voor waarde, opslag en bron
- Verspreidt de hele velddefinitie over
_f.*viaset_variable_dot('_f', $def); elk attribuut uit de.metais automatisch beschikbaar in de template - Zet daar berekende variabelen bovenop:
_f.key,_f.title,_f.value,_f.model,_f.required,_f.ai,_f.bg - Geeft door aan
[#field-{type}#], de template voor dat veldtype
_f.model is de Alpine.js-expressie voor x-model, berekend als {store}.{field}. De standaardopslag is form_data. Bij i18n-velden wordt het form_data.{field}[{lang}].
Standaardvariabelen _f.* die in elke veldtemplate beschikbaar zijn:
| Variabele | Inhoud |
|---|---|
_f.key |
Veldnaam / HTML-attribuut name |
_f.title |
Label (uit name in .meta) |
_f.value |
Vooraf ingevulde waarde |
_f.model |
Alpine-expressie voor x-model, bijvoorbeeld form_data.email |
_f.required |
Of het veld verplicht is |
_f.bg |
Class voor de achtergrondkleur van het zwevende label |
_f.* (elke) |
Alle andere sleutels van de velddefinitie: _f.accept, _f.options, _f.resource, enzovoort |
form_data: de Alpine.js-store
form_data is het reactieve Alpine.js-object met alle huidige veldwaarden. Het wordt op het element <form> gedeclareerd. Elk veld schrijft zijn waarde hierin via x-model="[#_f.model#]".
Bij het versturen wordt form_data in de API-payload gezet en met POST naar /api/v1/{resource} gestuurd. Velden met een rijke editor (HTML, gallery, image) schrijven hun waarden via een apart mechanisme (nb.edit.get_field_values()), dat automatisch wordt samengevoegd; veldtemplates hoeven dat niet zelf te regelen.
De eenvoudigste veldtemplate
field-default/index.tpl is de basis voor tekstachtige velden:
<div class="[#_f.wrapper_class#]">
<input type="[#_f.type#]" value="[#_f.value#]" name="[#_f.key#]"
x-init="[#_f.model#]=`[#_f.value#]`"
x-model="[#_f.model#]"
[#if _f.required=(not-empty) echo=required#]
class="input input-bordered w-full" />
<label class="pointer-events-none absolute left-3 -top-2.5 px-1
font-bold text-sm leading-tight [#get _f.bg default=bg-neutral-50#]">
[#_f.title#][#if _f.required=(not-empty) echo=" *"#]
</label>
</div>
Een nieuw veldtype toevoegen
-
Maak de template:
core/modules/forms/tpl/field-{type}/index.tpl ← core types ext/tpl/field-{type}/index.tpl ← project-specific types -
In de template:
- Koppel aan Alpine via
x-model="[#_f.model#]" - Zet de beginwaarde met
x-init="[#_f.model#]='[#_f.value#]'" - Gebruik
[#_f.key#]als HTML-attribuutname - Lees opties van het type via
_f.*(bijvoorbeeld[#_f.accept#]voor beperkingen van bestandstypen)
- Koppel aan Alpine via
-
Gebruik de typenaam in
.meta; hij werkt zodra de template bestaat. -
Beheert het veld ingewikkelde status (zoals een bestandskiezer of een knop voor de mediabrowser), nest dan een eigen
x-databinnen dex-datavan het formulier. De buitensteform_datablijft bereikbaar vanuit geneste scopes.
Eigen velden gebruiken de afspraak field-{type} voor templates en de context _f.* (_f.model, _f.key, _f.title, _f.bg, enzovoort). Veldtemplates uit een oudere generatie, met _fmodel, _fid, _ftitle, _fbg, _bf_render_field() of Tailwind Elements-attributen data-te-*, worden in deze vorm opnieuw gebouwd in plaats van overgenomen.
Geneste velden en herhaalvelden moeten de geneste modelpaden van Alpine zelf regelen. Een veld group dat locations bewaart, koppelt de onderliggende velden bijvoorbeeld aan paden zoals form_data.locations[ix].location, of geeft een expliciet model mee bij hergebruik van render_field(). Ga er niet van uit dat de renderer van core geneste arraypaden uit een platte veldsleutel kan afleiden.