29. Conditional Logic for Developers | Field Forge - Custom Fields, Built for Speed
Download Log in

29. Conditional Logic for Developers

Developer Guide

Conditional logic controls which fields are visible in the admin based on the values of other fields. This section explains how to set up conditional logic programmatically.

Conditional Logic Structure

Each field can have a conditional_logic property — an array of OR groups, where each group is an array of AND conditions.

php
FIELDFORGE_Field_Groups::instance()->create( [
    'title'  => 'Event Settings',
    'fields' => [
        [
            'key'   => 'field_evt_type',
            'label' => 'Event Type',
            'name'  => 'event_type',
            'type'  => 'select',
            'choices' => [ 'in_person' => 'In Person', 'virtual' => 'Virtual', 'hybrid' => 'Hybrid' ],
        ],
        [
            'key'   => 'field_evt_venue',
            'label' => 'Venue Address',
            'name'  => 'venue_address',
            'type'  => 'text',
            'conditional_logic' => [
                // Show when event_type is 'in_person' OR 'hybrid'
                [ [ 'field' => 'field_evt_type', 'operator' => '==', 'value' => 'in_person' ] ],
                [ [ 'field' => 'field_evt_type', 'operator' => '==', 'value' => 'hybrid' ] ],
            ],
        ],
        [
            'key'   => 'field_evt_url',
            'label' => 'Stream URL',
            'name'  => 'stream_url',
            'type'  => 'url',
            'conditional_logic' => [
                // Show when event_type is 'virtual' OR 'hybrid'
                [ [ 'field' => 'field_evt_type', 'operator' => '==', 'value' => 'virtual' ] ],
                [ [ 'field' => 'field_evt_type', 'operator' => '==', 'value' => 'hybrid' ] ],
            ],
        ],
        [
            'key'   => 'field_evt_capacity',
            'label' => 'Max Capacity',
            'name'  => 'max_capacity',
            'type'  => 'number',
            'conditional_logic' => [
                // Show when in_person AND has a venue address
                [
                    [ 'field' => 'field_evt_type', 'operator' => '==', 'value' => 'in_person' ],
                    [ 'field' => 'field_evt_venue', 'operator' => '!=empty', 'value' => '' ],
                ],
            ],
        ],
    ],
    'location_rules' => [
        [ [ 'param' => 'post_type', 'operator' => '==', 'value' => 'event' ] ],
    ],
] );

Canonical schema shape

The runtime evaluator reads the canonical shape { enabled: true, rules: [...] }. Field Forge also accepts the legacy ACF bare-array shape (just the outer rules array) and normalizes it on save:

php
'conditional_logic' => [
    'enabled' => true,
    'rules' => [           // outer = OR
        [                  // inner = AND
            [ 'field' => 'event_type', 'operator' => '==', 'value' => 'in_person' ],
            [ 'field' => 'venue', 'operator' => '!=empty', 'value' => '' ],
        ],
    ],
]

The field key inside each condition matches by field name (not key). Use the same name you would pass to get_field().

Available Operators

All operators are mirrored between PHP (FIELDFORGE_Conditional_Logic::compare()) and JS (assets/js/conditional-logic.js). Keep both lists in sync if you fork.

OperatorDescriptionExample
==Equals (loose, string-coerced; for arrays, true if expected is in the array)'value' => 'in_person'
!=Not equals'value' => 'draft'
==containsSubstring match'value' => 'admin'
!=containsInverse substring match'value' => 'spam'
==patternRegex match. Auto-wraps with /.../ if no delimiters provided.'value' => '/^vd+/i'
==emptyTrue when value is null, ”, ‘0’, false, or empty array'value' => ''
!=emptyInverse of ==empty'value' => ''
> < >= <=Numeric (floatval both sides)'value' => '50'

Runtime evaluator

  • PHP-side (FIELDFORGE_Field_Renderer::render_field) does an initial server-side evaluation so fields whose rules are false are emitted with style="display:none" — no flash of all-fields on page load.
  • JS-side (assets/js/conditional-logic.js) re-evaluates on every change / input event inside the metabox. Each metabox carries a data-fieldforge-cond-rules JSON map; each conditional target carries data-fieldforge-cond-target="".
  • Hidden trigger short-circuit: if a trigger field is itself hidden (by its own conditional rule), conditions on it count as false. Chains (A controls B controls C) cascade automatically — when A hides B, the JS re-runs until convergence, so C also hides.
  • Required attribute: when a field hides, any descendant [required] attribute is stashed as data-fieldforge-cond-required="1" and required is removed so the browser does not block submit. It is restored when the field becomes visible again.
  • Sub-field scope: v1 only evaluates rules on top-level fields (direct children of the field group). Rules placed on sub-fields inside Repeater / Group / Flexible Content are stored and round-tripped through export/import but the metabox always renders them.

Programmatic evaluation

FIELDFORGE_Conditional_Logic::evaluate( $logic, $values ) is exposed as the same evaluator the renderer uses, so headless callers can ask “would this field show given these values?” without DOM:
php
$logic = $field['conditional_logic']; // { enabled, rules }
$values = [
    'event_type' => 'hybrid',
    'venue'      => '',
];
$visible = FIELDFORGE_Conditional_Logic::evaluate( $logic, $values );

Conditional Logic in Templates

Conditional logic is a UI concern only — it does not affect get_field() output. A hidden field still retains its stored value. Always check for empty values in templates:

php
$venue = get_field( 'venue_address' );
if ( $venue ) {
    echo '<p>Venue: ' . esc_html( $venue ) . '</p>';
}

Forge AI Assistant Online

Hi! I'm the Field Forge AI assistant. Ask me anything about the plugin — setup, features, troubleshooting, or development.

Just now
Powered by Forge AI · Browse docs