Skip to content

Config Structure

Configs use a flat structure with promoted common keys at the field level. Type-specific settings go in args.

return [
'title' => 'Page Title', // Optional. Shown in the header.
'subtitle' => 'A short description', // Optional. Shown below the title.
'header_actions' => [ /* … */ ], // Optional. Buttons beside Save / Reset.
'tabs' => [
[
'id' => 'tab_id',
'title' => 'Tab Label',
'sections' => [
[
'id' => 'section_id',
'title' => 'Section Title',
'description' => 'Helpful description text.',
'fields' => [
[
'id' => 'field_id',
'type' => 'text',
'label' => 'Field Label',
'description' => 'Help text below the field.',
'default' => '',
'required' => false,
'validation' => 'min:3|max:100',
'columns' => 6,
'conditions' => [
'all' => [
['field' => 'other_field', 'operator' => 'truthy'],
],
],
'args' => [
'placeholder' => 'Enter text',
],
],
],
],
],
],
],
];

These are common to every field type:

KeyTypeDefaultDescription
idstringRequiredUnique field identifier within the page.
typestring'text'One of the registered field types.
labelstring''Display label. Pass '' explicitly to render no label (the field will still align with labelled siblings).
descriptionstring''Help text below the field. Supports {field_id} tokens that interpolate live form values, e.g. 'URL: https://example.com/{slug}'.
defaultmixednullDefault value, used when no saved value exists.
requiredboolfalseWhether the field must have a value at save time.
validationstring''Pipe-separated validation rules — e.g. 'min:3|max:100'.
columnsint (1..12)12Grid width. 12 = full row; 6 = half; 4 = third; etc.
new_rowboolfalseStart the field at column 1 of a new grid row, even when the current row has room. No effect on small screens, where fields stack.
conditionsarraynullConditional visibility rules evaluated against current values.
accessstring|arraynullRole / capability gating. Strictly opt-in.
argsarray[]Type-specific settings — placeholder, rows, options, multiple, mode, etc.

new_row also applies to repeater subfields. For example, the third field below starts a new row instead of filling the space left by the first two:

['id' => 'a', 'type' => 'text', 'columns' => 4],
['id' => 'b', 'type' => 'text', 'columns' => 4],
['id' => 'c', 'type' => 'text', 'columns' => 4, 'new_row' => true],

Everything that varies between field types lives under args. Some examples:

// Text field
['type' => 'text', 'args' => ['placeholder' => 'Optional placeholder', 'copyable' => true]]
// Textarea
['type' => 'textarea', 'args' => ['rows' => 5, 'placeholder' => '…']]
// Select
['type' => 'select', 'args' => ['options' => ['draft' => 'Draft', 'published' => 'Published']]]
// Repeater
['type' => 'repeater', 'args' => ['subfields' => [ /* … */ ], 'add_label' => 'Add row']]

See each field type’s page in Field Types for the full set.

Flexible structure — tabs and sections are optional

Section titled “Flexible structure — tabs and sections are optional”

The full nested shape (tabs → sections → fields) is the maximum. You can collapse it when you don’t need every level.

return [
'fields' => [
['id' => 'name', 'type' => 'text', 'label' => 'Name'],
['id' => 'email', 'type' => 'email', 'label' => 'Email'],
],
];

No tabs are rendered. Fields render in a single card.

return [
'sections' => [
[
'id' => 'main',
'title' => 'Main Settings',
'fields' => [
['id' => 'name', 'type' => 'text', 'label' => 'Name'],
],
],
],
];

The tab bar is suppressed; section cards stack vertically.

A JSON Schema for the config structure ships at schema/config.schema.json. It covers all three input formats, the common field keys, the conditions DSL, the access shapes, and per-type args constraints (e.g. choice fields require args.options, repeaters require args.subfields). Point your editor at it to get autocomplete and inline validation while authoring JSON configs.

In VS Code, map it in .vscode/settings.json:

{
"json.schemas": [
{
"fileMatch": ["**/config/*.json", "**/wireframe.config.json"],
"url": "./vendor/wp-wireframe/schema/config.schema.json"
}
]
}

Or reference it inline from a JSON config with "$schema": "./vendor/wp-wireframe/schema/config.schema.json".

When WP_DEBUG is enabled, every booted config is linted and structural problems — unknown field types, choice fields missing options, duplicate IDs, out-of-range columns, and so on — are written to the PHP error log. Users with manage_options also see them in a warning notice on other admin screens; Wireframe pages themselves suppress admin notices, so check the log there.

It’s a focused sanity check against the live field registry; the JSON Schema remains the full contract. Nothing runs when WP_DEBUG is off, so production is unaffected.