Skip to content

PHP Blueprints ​

Register objects on the vxframework/register action, which runs once during WordPress's init. Objects defined this way are read-only in the dashboard until someone overrides them.

php
use VxFramework\Config\Blueprint\Blueprint;
use VxFramework\Config\Blueprint\Field;

add_action( 'vxframework/register', function ( \VxFramework\Config\Code_Registry $vx ) {
    $vx->define(
        Blueprint::post_type( 'book' )
            ->name( 'Book', 'Books' )
            ->show_in_rest( true )
            ->has_archive( true )
            ->permalink_base( 'books' )
    );

    $vx->define(
        Blueprint::taxonomy( 'genre' )
            ->name( 'Genre', 'Genres' )
            ->hierarchical()
            ->show_admin_column()
    );

    $vx->define(
        Blueprint::fieldset( 'book_details' )
            ->label( 'Book details' )
            ->on_post_type( 'book' )
            ->fields( [
                Field::text( 'tagline' )->label( 'Tagline' ),
                Field::text( 'author_name' )->label( 'Author name' ),
                Field::image( 'author_picture' )->label( 'Author picture' ),
                Field::select( 'price_range' )->label( 'Price range' )->choices( [
                    'low'  => '$',
                    'mid'  => '$$',
                    'high' => '$$$',
                ] ),
                Field::repeater( 'opening_hours' )->label( 'Opening hours' )->fields( [
                    Field::text( 'day' )->label( 'Day' ),
                    Field::make( 'time', 'opens' )->label( 'Opens' ),
                    Field::make( 'time', 'closes' )->label( 'Closes' ),
                ] ),
            ] )
    );
} );

Option pages and dictionaries ​

php
$vx->define(
    Blueprint::option_page( 'site_settings' )
        ->label( 'Site settings' )
        ->submenu( 'options-general.php' )
        ->capability( 'edit_others_posts' )
);

$vx->define(
    Blueprint::dictionary( 'formats' )
        ->label( 'Formats' )
        ->entries( [ 'hardcover' => 'Hardcover', 'paperback' => 'Paperback' ] )
);

Link a choice field to a dictionary with Field::select( 'format' )->dictionary( 'formats' ). Option pages are top-level by default; submenu() without an argument nests the page under VX, and hidden() makes it reachable by URL only.

Field types without a shortcut ​

Field has shortcuts for common types (text(), number(), select(), repeater(), image() and more). For any other type, use Field::make( 'type', 'key' ). Any setting without its own method can be set with ->prop() or ->props():

php
Field::make( 'range_slider', 'price_band' )
    ->label( 'Price band' )
    ->props( [ 'min' => 0, 'max' => 200, 'step' => 5 ] );

You can also register a raw config array, the same shape the dashboard stores:

php
$vx->fieldset( 'book_details', [
    'label'    => 'Book details',
    'fields'   => [ [ 'type' => 'text', 'key' => 'tagline', 'label' => 'Tagline' ] ],
    'location' => [ 'groups' => [ [ 'object' => 'post_type', 'targets' => [ 'book' ] ] ] ],
] );

Gotchas ​

  • Always name targets. on_post_type() and on_taxonomy() without an argument create a Location with nothing selected, which matches nothing.
  • on_user() applies to every user. It takes no arguments. To limit a fieldset to certain roles, add a User role condition to the Location in the raw config.
  • required() is accepted, but VX doesn't enforce required fields.
  • PHP wins over JSON. If a JSON file defines the same key, it's ignored, and Direct mode isn't available.
Technical details for LLMs
  • Registry: vxframework/register (action, init priority 0) receives \VxFramework\Config\Code_Registry with define( Blueprint ) and raw post_type(), taxonomy(), fieldset() methods. A registration, blueprint or method for an object type nothing registers is skipped without an error; the registration is reported as an unknown config type alongside the ones that failed validation.
  • Post type: name( $singular, $plural ), singular(), plural(), description(), icon(), accent_color(), hierarchical(), block_editor(), show_in_rest(), rest_base(), has_archive(), permalink_base(), menu_position(), labels().
  • Taxonomy: name(), singular(), plural(), icon(), accent_color(), hierarchical(), is_public(), show_in_rest(), rest_base(), show_admin_column(), permalink_base(), labels().
  • Fieldset: label(), description(), description_display(), order(), active(), icon(), accent_color(), fields(), add_field(), on_post_type(), on_taxonomy(), on_user(), on( $object, $targets ) for any Location object.
  • Field factories: Field::{type}( $key ) builds a field of any type by name; the type is checked when the fieldset is validated. Shortcuts: make, text, textarea, number, email, url, phone, switcher, color, rich_text, code, date, datetime, time, select, radio, checkboxes, multiselect, button_group, image, gallery, taxonomy, repeater, group, section (ui_section), tabs (ui_tabs, whose fields() are sections). Modifiers: label, description, required, default, placeholder, prop, props, min, max, step, choices, fields. Any object key: ->set() / ->props().
  • Option page: label(), description(), icon(), accent_color(), top_level(), submenu( $parent = 'vx-framework' ), hidden(), menu_title(), menu_position(), capability(), autoload(), active(). Dictionary: label(), icon(), accent_color(), entries() (map, {value,label} list, or strings).
  • Also on a fieldset: rest_expose(), on_option_page(). More field factories: markdown, file (→ files), post_relation, user_relation, location, table, content_sections. More modifiers: rest_expose( $tier ) (sets rest.access), dictionary, layouts.
  • permalink_base() is normalized to a slug (UTF-8 kept, percent-encoding decoded); a value with nothing usable fails validation and is reported on the Source tab.

Documentation for the VX Framework.