Skip to content

Sections & Subsections

How to organise your theme options into a clean hierarchical sidebar navigation.

Organise your theme options into a clean hierarchical sidebar using sections and subsections.

Overview

ThemePlus organises all fields into a sidebar navigation. At the top level are sections — each appears as a clickable item in the sidebar. Sections can contain fields directly, or they can be divided into subsections which appear as nested items below the parent. You can use both at the same time.

Adding a Section

Use themeplus_add_section() on the init hook. Always wrap it in a function_exists() check:

add_action( 'init', function () {

    if ( ! function_exists( 'themeplus_add_section' ) ) {
        return;
    }

    themeplus_add_section([
        'id'       => 'general',
        'title'    => __( 'General Settings', 'your-textdomain' ),
        'icon'     => 'cog',
        'priority' => 10,
        'fields'   => [
            [
                'id'      => 'enable_preloader',
                'type'    => 'toggle',
                'title'   => __( 'Enable Preloader', 'your-textdomain' ),
                'default' => true,
            ],
        ],
    ]);

} );

Section Options

OptionTypeDefaultDescription
idstringRequired. Unique section identifier. Used as the key in the database and in conditional logic.
titlestringRequired. Label shown in the sidebar.
iconstring'cog'FontAwesome icon name — the part after fa-solid fa-. Example: 'palette''code''layer-group'.
priorityint10Controls the order sections appear in the sidebar. Lower numbers appear first.
fieldsarray[]Array of field definition arrays registered directly in this section.
subsectionsarray[]Array of subsection definition arrays nested under this section.

Icon convention: The icon key takes a FontAwesome name only — just the part after fa-solid fa-. For example 'pen''palette''ruler-combined'. Do not pass the full class string here — that format is only used by the Icon fielddefault value.

Adding Subsections

Subsections can be added in two ways — inline when registering the section, or separately via themeplus_add_subsection().

Inline subsections

Pass subsections directly in the subsections key when registering the section:

themeplus_add_section([
    'id'          => 'header',
    'title'       => __( 'Header', 'your-textdomain' ),
    'icon'        => 'rectangle-ad',
    'priority'    => 20,
    'fields'      => [],
    'subsections' => [
        [
            'id'     => 'logo',
            'title'  => __( 'Logo', 'your-textdomain' ),
            'icon'   => 'image',
            'fields' => [
                [
                    'id'    => 'logo_image',
                    'type'  => 'image',
                    'title' => __( 'Logo Image', 'your-textdomain' ),
                ],
                [
                    'id'      => 'logo_width',
                    'type'    => 'number',
                    'title'   => __( 'Logo Width', 'your-textdomain' ),
                    'default' => 160,
                    'unit'    => 'px',
                ],
            ],
        ],
        [
            'id'     => 'navigation',
            'title'  => __( 'Navigation', 'your-textdomain' ),
            'icon'   => 'bars',
            'fields' => [
                // ...
            ],
        ],
    ],
]);

Subsection Options

OptionTypeRequiredDescription
idstringUnique subsection identifier within the parent section.
titlestringLabel shown in the sidebar under the parent section.
iconstringFontAwesome icon name — same format as section icons.
fieldsarrayArray of field definition arrays for this subsection.

Note: Subsections do not have a priority key — they appear in the order they are added.

Attaching a Subsection Separately

Use themeplus_add_subsection() to attach a subsection to an already-registered section from a separate hook. This is the recommended pattern for child themes and extension pluginsthat need to add fields to a parent theme’s panel without modifying its source:

add_action( 'init', function () {

    if ( ! function_exists( 'themeplus_add_subsection' ) ) {
        return;
    }

    themeplus_add_subsection( 'header', [
        'id'     => 'sticky_header',
        'title'  => __( 'Sticky Header', 'your-textdomain' ),
        'icon'   => 'arrow-up',
        'fields' => [
            [
                'id'      => 'enable_sticky',
                'type'    => 'toggle',
                'title'   => __( 'Enable Sticky Header', 'your-textdomain' ),
                'default' => false,
            ],
        ],
    ]);

}, 20 ); // Priority 20 or later — the parent section must exist first

Important: themeplus_add_subsection() silently does nothing if the parent section ID does not exist yet. Always use a hook priority of 20 or later to ensure the parent section is registered before you attach to it.

Sections With Both Fields and Subsections

A section can contain both top-level fields and subsections at the same time. Top-level fields appear when the section heading itself is clicked; subsection fields appear when a subsection is clicked:

themeplus_add_section([
    'id'          => 'typography',
    'title'       => __( 'Typography', 'your-textdomain' ),
    'icon'        => 'font',
    'priority'    => 30,
    'fields'      => [
        // These fields appear at the section level
        [
            'id'      => 'base_font_size',
            'type'    => 'number',
            'title'   => __( 'Base Font Size', 'your-textdomain' ),
            'default' => 16,
            'unit'    => 'px',
        ],
    ],
    'subsections' => [
        [
            'id'     => 'body_typography',
            'title'  => __( 'Body', 'your-textdomain' ),
            'icon'   => 'align-left',
            'fields' => [
                [
                    'id'          => 'body_font',
                    'type'        => 'typography',
                    'title'       => __( 'Body Font', 'your-textdomain' ),
                    'font-size'   => true,
                    'font-weight' => true,
                    'line-height' => true,
                ],
            ],
        ],
        [
            'id'     => 'heading_typography',
            'title'  => __( 'Headings', 'your-textdomain' ),
            'icon'   => 'heading',
            'fields' => [
                [
                    'id'          => 'heading_font',
                    'type'        => 'typography',
                    'title'       => __( 'Heading Font', 'your-textdomain' ),
                    'font-weight' => true,
                ],
            ],
        ],
    ],
]);

Controlling Section Order

Use the priority key to control the order sections appear in the sidebar. Sections are sorted by priority — lower numbers appear first:

themeplus_add_section(['id' => 'general',    'priority' => 10, ...]);
themeplus_add_section(['id' => 'header',     'priority' => 20, ...]);
themeplus_add_section(['id' => 'typography', 'priority' => 30, ...]);
themeplus_add_section(['id' => 'footer',     'priority' => 40, ...]);

Sections with the same priority value appear in the order they were registered.

Helper Functions

FunctionDescription
themeplus_add_section( array $section )Register a new section
themeplus_add_subsection( string $parent_id, array $subsection )Attach a subsection to an existing section
themeplus_get_sections()Get all registered sections as an array
themeplus_get_section( string $id )Get a single section by its ID

Notes

  • Section and subsection id values must be unique across the entire panel — duplicates will silently overwrite the earlier registration.
  • Sections with no fields and no subsections will still appear in the sidebar but will show an empty panel. Always register at least one field or one subsection.
  • The icon key on sections and subsections takes a FontAwesome name only — e.g. 'cog''palette'. The Icon field default takes a full FontAwesome class — e.g. 'fa-solid fa-star'. These are different formats used in different places.
  • Conditional logic (required) references fields by their id — fields must be in the same section as the dependent field. Cross-section conditions are not supported.

On This Page