Skip to content

Latest commit

 

History

58 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

itinerisltd/wpc-builder

GitHub License Hire Itineris Twitter Follow @itineris_ltd

A typed, fluent PHP library for registering WordPress Customizer panels, sections, fields and controls.

Write sections and fields against this API, then call Customizer::make()->...->register() once from your theme or plugin's setup code.

Documentation

Requirements

  • PHP ^8.4
  • WordPress >= 7.0

Installation

cd web/app/themes/your-theme
composer require itinerisltd/wpc-builder

The package must end up somewhere under WP_CONTENT_DIR: a theme, child theme, plugin or mu-plugin all qualify. Asset URLs are derived from its filesystem position, so installing outside that tree (e.g. a Bedrock root composer.json) ships no CSS or JS and says so via _doing_it_wrong(). Symlinked installs have sharp edges, covered in installation.

Quick start

examples/ is a working reference.

namespace App;

use Itineris\WpcBuilder\Customizer;

Customizer::make()
    ->addSections([
        Sections\Footer::class,
        Sections\SiteIdentity::class,
    ])
    ->register();

Everything hooks onto customize_register (priority 20) and customize_controls_enqueue_scripts; nothing runs at class-load time.

A section declares $id and $title as property defaults and returns its fields:

namespace App\Sections;

use Itineris\WpcBuilder\Fields\Editor;
use Itineris\WpcBuilder\Fields\Image;
use Itineris\WpcBuilder\Sections\AbstractSection;

final class Footer extends AbstractSection
{
    protected string $id = 'footer';
    protected ?string $title = 'Footer';

    protected function fields(): array
    {
        return [
            Editor::make('footer_logo_text')
                ->setLabel('Footer Logo Text')
                ->setPartialRefresh(
                    '#footer .footer-logo a',
                    static function (): string {
                        $value = get_theme_mod('footer_logo_text', '');

                        return is_string($value) ? $value : '';
                    },
                ),

            Image::make('footer_logo_image')
                ->setLabel('Footer Logo Image'),
        ];
    }
}

To extend a WordPress core section such as Site Identity, set $id to the core section's id (title_tagline). Existing sections are detected and add_section() is skipped.

Fields

24 field classes: Text, Textarea, Editor, Url, Link, Number, Slider, Select, PostSelect, Radio, RadioButtonset, DropdownPages, Multicheck, Checkbox, CheckboxToggle, CheckboxSwitch, Toggle, Image, Color, ColorPalette, Dimensions, Custom, Repeater and Tabs.

Stored value shapes vary per field, so check fields.md before relying on one.

Storage

Settings are theme mods by default. Pass a Config to store them in wp_options instead:

use Itineris\WpcBuilder\Config;
use Itineris\WpcBuilder\Customizer;
use Itineris\WpcBuilder\Enums\OptionType;

Customizer::make()
    ->setConfig(new Config(optionType: OptionType::OPTION, optionName: 'my_prefix'))
    ->register();

Setting ids then become "my_prefix[fieldId]". capability, optionType and optionName are all overridable per field via setCapability(), setOptionType() and setOptionName(), so one section can mix storages.

Conditions

use Itineris\WpcBuilder\Fields\Text;

Text::make('alert_message')
    ->setVisibleWhen([
        ['setting' => 'my_prefix[alert_enabled]', 'operator' => '==', 'value' => true],
    ]);

setRequiredWhen() takes the same condition rows but is independent of setVisibleWhen(): it hides nothing, and instead fails the changeset save with a value_required WP_Error when the conditions pass and the value is blank. The asterisk and required attribute on the control are a hint; server-side validation is the enforcement.

Operators, nesting and the fail-open rule: conditional-visibility.md and conditionally-required.md.

Partial refresh

setPartialRefresh($selector, $renderCallback) registers a selective-refresh partial and forces the field's transport to postMessage, which the partial needs to be reachable. See fields.md.

Migrating from Kirki

Migrating section by section is safe, but Kirki must stay active until every Kirki::get_option() call site is rewritten. Read migrating-from-kirki.md before starting.

Contributing

composer style:check  # PHPCS
composer stan         # PHPStan, level max, zero baseline entries
composer test:unit    # Pest, brain/monkey-mocked WordPress
npm run lint          # stylelint (assets/src/css) + eslint (assets/src/js)
npm test              # Vitest (assets/src/js/**/*.test.js)
npm run build         # Vite: assets/src/{js,css}/ -> dist/{js,css}/
shellcheck scripts/*.sh   # release and packaging scripts
composer test:integration # Pest, real WordPress + database; see docs/testing.md

The first seven commands are the commit gate. dist/ is generated and never committed; sources live in assets/src/.

FAQ

It looks awesome. Where can I find some more goodies like this?

This isn't on wp.org. Where can I give a review?

Thanks! Glad you like it. It's important to let people know somebody is using this project. Consider:

Feedback

Please provide feedback! We want to make this library useful in as many projects as possible. Please submit an issue and point out what you do and don't like, or fork the project and make suggestions. No issue is too small.

Security

If you discover any security related issues, please email hello@itineris.co.uk instead of using the issue tracker.

Changelog

Please see CHANGELOG for more information on what has changed recently.

Credits

wpc-builder is an Itineris Limited project created by Lee Hanbury-Pickett.

Full list of contributors can be found here.

License

wpc-builder is released under the MIT License.

Releases

Used by

Contributors

Languages