Skip to content

Conditional Visibility

Any tab, section, or field can declare a conditions block. The framework evaluates them against the in-flight form values (not just the saved values), so visibility updates instantly as the user edits.

'conditions' => [
'all' => [ // AND of every rule
['field' => 'debug_mode', 'operator' => 'truthy'],
['field' => 'log_level', 'operator' => 'in', 'value' => ['info', 'debug']],
],
// 'any' => [ ... ], // OR of every rule
],

Both all and any may be declared together — all is required, then any is required, both with their own rule sets.

Worked example — show a select when a toggle is on

Section titled “Worked example — show a select when a toggle is on”
[
'id' => 'debug_mode',
'type' => 'toggle',
'label' => __('Debug mode', 'my-plugin'),
'default' => false,
],
[
'id' => 'log_level',
'type' => 'select',
'label' => __('Log level', 'my-plugin'),
'default' => 'error',
'columns' => 6,
'conditions' => [
'all' => [
['field' => 'debug_mode', 'operator' => 'truthy'],
],
],
'args' => [
'options' => [
'error' => __('Errors only', 'my-plugin'),
'info' => __('Info & above', 'my-plugin'),
'debug' => __('Everything', 'my-plugin'),
],
],
],

When debug_mode is off, log_level collapses out of the form and its value won’t be saved on the next write. Toggle it on and the field reappears.

OperatorComparesExample
equalsstrict equality['field' => 'status', 'operator' => 'equals', 'value' => 'live']
not_equalsstrict inequality['field' => 'status', 'operator' => 'not_equals', 'value' => 'draft']
truthyJS truthiness['field' => 'flag', 'operator' => 'truthy']
falsyJS falsiness['field' => 'flag', 'operator' => 'falsy']
invalue is in value array['field' => 'role', 'operator' => 'in', 'value' => ['admin', 'editor']]
not_invalue is NOT in value array['field' => 'role', 'operator' => 'not_in', 'value' => ['guest']]
containsstring includes substring['field' => 'url', 'operator' => 'contains', 'value' => 'staging']
not_containsstring does NOT include substring['field' => 'url', 'operator' => 'not_contains', 'value' => 'localhost']
starts_withstring starts with['field' => 'slug', 'operator' => 'starts_with', 'value' => 'sale-']
ends_withstring ends with['field' => 'slug', 'operator' => 'ends_with', 'value' => '-2026']
is_emptyempty string / null / []['field' => 'note', 'operator' => 'is_empty']
is_not_emptynot empty['field' => 'note', 'operator' => 'is_not_empty']
gt / gtenumeric greater-than / >=['field' => 'qty', 'operator' => 'gte', 'value' => 1]
lt / ltenumeric less-than / <=['field' => 'qty', 'operator' => 'lt', 'value' => 100]
betweennumeric between (inclusive)['field' => 'qty', 'operator' => 'between', 'value' => [1, 100]]

Conditions work the same way at every level. A tab that evaluates to false hides itself from the tab bar entirely — users can’t see or click into it. Same for sections (entire card disappears) and fields (single input hides).

[
'id' => 'advanced',
'title' => __('Advanced', 'my-plugin'),
'conditions' => [
'all' => [
['field' => 'show_advanced', 'operator' => 'truthy'],
],
],
'sections' => [ /* … */ ],
],

Repeater subfields support conditions too, evaluated per row — see Conditional subfields.