Skip to content

Group Field

A collapsible container for nesting related fields together under a single heading.

A container for nesting related fields together under a single heading.

Overview

The Group field renders a set of sub-fields inside a card container under a shared label. It returns a single associative array of all sub-field values keyed by sub-field ID — one row, always. Use it to organise tightly related fields — all settings for a single UI component, an SEO block, a CTA, or a hero section — into one logical unit without creating a separate navigation section.

For repeatable rows of the same structure, use the Repeater field. For a visual divider between fields, use the Section field.

Field Registration

[
    'id'       => 'seo_settings',
    'type'     => 'group',
    'title'    => __( 'SEO Settings', 'your-textdomain' ),
    'subtitle' => __( 'Meta title, description, and indexing preference', 'your-textdomain' ),
    'fields'   => [
        [
            'id'    => 'meta_title',
            'type'  => 'text',
            'title' => __( 'Meta Title', 'your-textdomain' ),
        ],
        [
            'id'    => 'meta_description',
            'type'  => 'textarea',
            'title' => __( 'Meta Description', 'your-textdomain' ),
            'rows'  => 2,
        ],
        [
            'id'      => 'noindex',
            'type'    => 'toggle',
            'title'   => __( 'Discourage Search Engines', 'your-textdomain' ),
            'default' => false,
        ],
    ],
]

Field Options

OptionTypeRequiredDescription
idstringUnique field identifier — used as the option key
typestringMust be group
titlestringLabel shown above the group container
subtitlestringDescriptive text shown below the label
descstringAlternative to subtitle — shown in the same position
fieldsarrayArray of sub-field definitions — same structure as regular fields
requiredarrayConditional logic rules — see Conditional Logic

Supported Sub-field Types

Group passes each sub-field through FieldRenderer with no exclusion list. All registered field types work as sub-fields except:

  • group — nesting a group inside a group is not supported
  • repeater — nesting a repeater inside a group is not supported

Everything else is supported: texttextareanumberspinnersliderselectbutton_setradiocheckboxselect_imagetoggleswitchcolorgradient_pickerimagegalleryicontypographydimensionsspacingborderbackgroundlinkdate_pickersocial_mediacode_editor

Note: Sub-fields that return structured arrays — imagegallerylinkbackgroundtypographyspacingborderdimensions — return their full documented shapes inside the group value, exactly as they would as standalone fields.

Return Value

Type: array

Returns an associative array of sub-field values keyed by sub-field ID, or an empty array {} if nothing has been saved yet.

$seo = themeplus_get_option( 'seo_settings', [] );
// Returns:
// [
//     'meta_title'       => 'My Page Title',
//     'meta_description' => 'A short description of the page.',
//     'noindex'          => false,
// ]

Usage Examples

Reading group sub-field values

$seo         = themeplus_get_option( 'seo_settings', [] );
$meta_title  = $seo['meta_title']       ?? '';
$meta_desc   = $seo['meta_description'] ?? '';
$noindex     = $seo['noindex']          ?? false;

if ( $meta_title ) {
    echo '<meta name="title" content="' . esc_attr( $meta_title ) . '">';
}
if ( $meta_desc ) {
    echo '<meta name="description" content="' . esc_attr( $meta_desc ) . '">';
}
if ( $noindex ) {
    echo '<meta name="robots" content="noindex, nofollow">';
}

Logo settings group

[
    'id'     => 'header_logo',
    'type'   => 'group',
    'title'  => __( 'Logo Settings', 'your-textdomain' ),
    'fields' => [
        [
            'id'    => 'image',
            'type'  => 'image',
            'title' => __( 'Logo Image', 'your-textdomain' ),
            // Returns: { id, url, width, height, alt, title }
        ],
        [
            'id'      => 'width',
            'type'    => 'number',
            'title'   => __( 'Logo Width', 'your-textdomain' ),
            'default' => 160,
            'unit'    => 'px',
        ],
        [
            'id'      => 'link_url',
            'type'    => 'text',
            'title'   => __( 'Logo Link URL', 'your-textdomain' ),
            'default' => '',
        ],
    ],
]
$logo     = themeplus_get_option( 'header_logo', [] );
$image    = $logo['image']    ?? [];    // full image array
$width    = $logo['width']    ?? 160;
$link_url = $logo['link_url'] ?? home_url( '/' );

$img_url = $image['url'] ?? '';
$img_alt = $image['alt'] ?? get_bloginfo( 'name' );

if ( $img_url ) {
    echo '<a href="' . esc_url( $link_url ) . '" class="site-logo">';
    echo '<img src="' . esc_url( $img_url ) . '" alt="' . esc_attr( $img_alt ) . '" width="' . absint( $width ) . '">';
    echo '</a>';
}

Announcement bar group

[
    'id'      => 'enable_announcement_bar',
    'type'    => 'toggle',
    'title'   => __( 'Enable Announcement Bar', 'your-textdomain' ),
    'default' => false,
],
[
    'id'       => 'announcement_bar',
    'type'     => 'group',
    'title'    => __( 'Announcement Bar', 'your-textdomain' ),
    'required' => ['enable_announcement_bar', '==', true],
    'fields'   => [
        [
            'id'      => 'message',
            'type'    => 'text',
            'title'   => __( 'Message', 'your-textdomain' ),
            'default' => __( 'Free shipping on orders over $50', 'your-textdomain' ),
        ],
        [
            'id'      => 'bg_color',
            'type'    => 'color',
            'title'   => __( 'Background Color', 'your-textdomain' ),
            'default' => '#2271b1',
        ],
        [
            'id'      => 'text_color',
            'type'    => 'color',
            'title'   => __( 'Text Color', 'your-textdomain' ),
            'default' => '#ffffff',
        ],
        [
            'id'      => 'cta',
            'type'    => 'link',
            'title'   => __( 'CTA Link (optional)', 'your-textdomain' ),
            'default' => [
                'url'    => '',
                'text'   => '',
                'target' => '_self',
                'rel'    => '',
            ],
        ],
    ],
],
$enabled = themeplus_get_option( 'enable_announcement_bar', false );
$bar     = themeplus_get_option( 'announcement_bar', [] );

if ( $enabled && ! empty( $bar ) ) {
    $message    = $bar['message']    ?? '';
    $bg_color   = $bar['bg_color']   ?? '#2271b1';
    $text_color = $bar['text_color'] ?? '#ffffff';
    $cta        = $bar['cta']        ?? [];

    echo '<div class="announcement-bar" style="background: ' . esc_attr( $bg_color ) . '; color: ' . esc_attr( $text_color ) . ';">';
    echo esc_html( $message );
    if ( ! empty( $cta['url'] ) ) {
        $rel = '_blank' === ( $cta['target'] ?? '_self' ) ? 'noopener noreferrer' : ( $cta['rel'] ?? '' );
        echo ' <a href="' . esc_url( $cta['url'] ) . '" target="' . esc_attr( $cta['target'] ?? '_self' ) . '" rel="' . esc_attr( $rel ) . '">' . esc_html( $cta['text'] ?? '' ) . '</a>';
    }
    echo '</div>';
}

Notes

  • Always use ?? null coalescing when reading sub-keys — a partially saved group may be missing keys added after the user first saved.
  • Sub-fields that return structured arrays (imagegallerylinkbackgroundtypography, etc.) return their full documented shapes inside the group — use the same key access patterns as when using those fields standalone.
  • Group produces exactly one set of values — it cannot be duplicated into multiple rows. For repeatable rows, use the Repeater field.
  • Nesting group or repeater inside a Group is not supported.
  • Group is best for 3–8 tightly related fields that belong together conceptually. For fewer than 3 fields, registering them flat in the section is often cleaner. For more fields or if navigation is needed, create a dedicated section with themeplus_add_section().

On This Page