TAW FrameworkMetabox and editor tooling

Metabox and editor tooling

Declare structured metaboxes in PHP, use the full field-type library, wire conditional logic, and retrieve saved values in your templates.

What metaboxes are in TAW

TAW Core's metabox engine (TAW\Core\Metabox\Metabox) lets you declare custom admin fields in pure PHP — no plugin required. It handles rendering in the WordPress editor, validation and sanitization on save, and retrieval helpers for templates.

You attach a metabox to a block by calling new Metabox([...]) inside registerMetaboxes() on any MetaBlock.

Minimal example

use TAW\Core\Metabox\Metabox;

new Metabox([
    'id'     => 'taw_hero',
    'title'  => 'Hero Section',
    'screens' => ['page'],
    'fields' => [
        ['id' => 'heading', 'label' => 'Heading', 'type' => 'text', 'required' => true],
        ['id' => 'image',   'label' => 'Image',   'type' => 'image'],
    ],
]);

Common field options

All field types share a base set of options:

OptionTypeDescription
idstringUnique field key (without prefix)
labelstringLabel shown above the field
typestringField type (see below)
descriptionstringHelp text shown below the field
placeholderstringInput placeholder text
defaultmixedDefault value
requiredboolMark field as required — validation runs on save
widthstringColumn width as a percentage, e.g. '50', '33.33'. Default '100'
conditionsarrayConditional logic — show/hide based on other field values

Field types

Conditional fields

Fields can show or hide based on other field values. Conditions are evaluated live in the admin using Alpine.js, and also server-side on save. All conditions in the array use AND logic.

'fields' => [
    ['id' => 'show_cta', 'label' => 'Show CTA', 'type' => 'checkbox'],
    ['id' => 'cta_text', 'label' => 'CTA Text', 'type' => 'text',
     'conditions' => [
         ['field' => 'show_cta', 'operator' => '==', 'value' => '1'],
     ]],
    ['id' => 'cta_url', 'label' => 'CTA URL', 'type' => 'url',
     'conditions' => [
         ['field' => 'show_cta', 'operator' => '==', 'value' => '1'],
     ]],
],

Supported operators: ==, !=, contains, empty, !empty

Tabbed metaboxes

Use the tabs key to group fields into tabs. Each tab references field IDs from the fields array.

new Metabox([
    'id'     => 'taw_hero',
    'title'  => 'Hero Section',
    'screens' => ['page'],
    'fields' => [
        ['id' => 'heading',  'label' => 'Heading',    'type' => 'text'],
        ['id' => 'image',    'label' => 'Image',      'type' => 'image'],
        ['id' => 'bg_color', 'label' => 'Background', 'type' => 'color'],
        ['id' => 'show_cta', 'label' => 'Show CTA',   'type' => 'checkbox'],
        ['id' => 'cta_text', 'label' => 'CTA Text',   'type' => 'text'],
    ],
    'tabs' => [
        ['id' => 'content', 'label' => 'Content', 'fields' => ['heading', 'image']],
        ['id' => 'design',  'label' => 'Design',  'fields' => ['bg_color']],
        ['id' => 'cta',     'label' => 'CTA',     'fields' => ['show_cta', 'cta_text']],
    ],
]);

Metabox config options

OptionDefaultDescription
screens['page']Post types, page slugs, or page template filenames to attach to — accepts a mixed array
context'normal'Position: 'normal', 'side', 'advanced'
priority'high'Order: 'high', 'default', 'low'
prefix'_taw_'Meta key prefix applied to all field IDs
icon(none)SVG string — displayed as the metabox icon
show_on(none)callable(WP_Post): bool — return false to hide the metabox

Field availability in nav menu context

When metabox fields are rendered on the WordPress nav menu editor screen, only a subset of field types are available: text, url, number, textarea, select, and checkbox. Complex fields such as image, wysiwyg, color, files, and repeater are not supported in the nav menu context due to asset availability constraints.

Retrieval API

Use these static helpers inside getData() or anywhere in your templates:

use TAW\Core\Metabox\Metabox;

// Plain text / any scalar value
$heading = Metabox::get($postId, 'hero_heading');

// Checkbox → boolean
$showCta = Metabox::get_bool($postId, 'show_cta');

// Image attachment ID → URL
$imageUrl = Metabox::get_image_url($postId, 'hero_image', 'large');

// Color with fallback
$bgColor = Metabox::get_color($postId, 'bg_color', '#ffffff');

// post_select → array of post IDs
$featuredId = Metabox::get_posts($postId, 'featured_post')[0] ?? null;
$relatedIds = Metabox::get_posts($postId, 'related_posts');

// repeater → array of row arrays
$members = Metabox::get_repeater($postId, 'team_members');
foreach ($members as $member) {
    echo esc_html($member['name'] ?? '');
}

Inside a MetaBlock, the convenience wrappers delegate to the same methods:

protected function getData(int|false $postId): array
{
    return [
        'heading'   => $this->getMeta($postId, 'hero_heading'),
        'image_url' => $this->getImageUrl($postId, 'hero_image', 'large'),
    ];
}