pollora / block-bindings
WordPress Block Bindings declared with attributes: a #[BlockBinding] class is a source, its methods are fields, and the post meta, term meta, author meta and options Pollora ships are ready to bind. Runs with or without Laravel.
Requires
- php: ^8.3
- pollora/attributes: ^0.1.1 || ^1.0
- pollora/colt: ^10.0.1
- pollora/discovery: ^0.1 || ^1.0
- pollora/hook: ^2.0.1
- pollora/meta: ^0.1
- psr/container: ^2.0
- psr/log: ^3.0
Requires (Dev)
- antecedent/patchwork: ^2.2
- brain/monkey: ^2.7
- laravel/pint: ^1.22.1
- mockery/mockery: ^1.6.12
- pestphp/pest: ^3.8.2
- phpstan/phpstan: ^2.1.16
- szepeviktor/phpstan-wordpress: ^2.0
Suggests
None
Provides
None
Conflicts
None
Replaces
None
README
WordPress Block Bindings declared in code: a class with #[BlockBinding] is a source, each method with #[BindingField] is a field a block attribute can be bound to, and the package registers it with WordPress, resolves the value on the page, previews it in the block editor and lists the fields the editor offers. It also ships four sources ready to bind: the post meta, the term meta and the author meta of pollora/meta, and the options a project lists.
Part of Pollora, the Laravel framework for WordPress, where it is installed and wired for you: see Block Bindings. It runs without Laravel too: in a plugin, a Bedrock site or any PHP project.
Installation
composer require pollora/block-bindings
Requires PHP 8.3+ and WordPress 6.5+. It builds on pollora/meta, pollora/attributes, pollora/discovery and pollora/hook.
Declaring a source
use Pollora\Attributes\BlockBinding; use Pollora\Attributes\BlockBinding\BindingField; use Pollora\BlockBinding\Domain\Models\BindingContext; #[BlockBinding('acme/event', label: 'Event', postTypes: ['event'])] final class EventBinding { #[BindingField(label: 'Remaining seats')] public function remainingSeats(BindingContext $context, SeatCounter $seats): string { return $seats->left($context->postId ?? 0).' seats left'; } #[BindingField(type: 'url')] public function bookingUrl(BindingContext $context): string { return 'https://example.test/book/'.$context->postId; } }
A field returns a string, an int, a float, a bool, a Stringable (an object with a toHtml() method is written as HTML) or null to keep what the block holds. A method receives the BindingContext (the post, term and block of the context, the arguments of the binding, post(), meta()) and the services its other typed parameters name. A class with __invoke is a single-field source.
Wiring it outside Pollora
The sources are made by a PSR-11 container: give the resolver one that knows them (the dependencies of your own sources, and the shipped ones you register). Then register the shipped sources and let discovery find yours:
use Pollora\BlockBinding\Application\Services\BindingResolver; use Pollora\BlockBinding\Application\Services\BindingSourceBuilder; use Pollora\BlockBinding\Application\Services\BindingSourceRegistry; use Pollora\BlockBinding\Infrastructure\Adapters\WordPressBindingRegistry; use Pollora\BlockBinding\Infrastructure\Services\BlockBindingDiscovery; use Pollora\BlockBinding\Infrastructure\Sources\PostMetaSource; use Pollora\Discovery\Domain\Models\DiscoveryLocation; use Pollora\Discovery\Infrastructure\Services\DiscoveryEngine; use Pollora\Hook\Adapter\Out\WordPress\Action; $builder = new BindingSourceBuilder; $sources = new BindingSourceRegistry; $registry = new WordPressBindingRegistry(new Action, new BindingResolver($container, $visibility, $presenter, $metaAccessor)); $shipped = $builder->build(PostMetaSource::class); // likewise TermMetaSource, AuthorMetaSource, OptionSource $sources->add($shipped); $registry->register($shipped); (new DiscoveryEngine) ->addLocation(new DiscoveryLocation('MyPlugin\\', __DIR__.'/src')) ->addDiscovery('block_bindings', new BlockBindingDiscovery($builder, $sources, $registry)) ->run();
$visibility (WordPressContentVisibility) decides whether the visitor may see a post or a term, and $presenter (WordPressValuePresenter) escapes and words a value; both are WordPress adapters of the package. The pollora/option source reads only the options you pass to OptionSource, and the editor learns the fields through BindingEditorData, the ResolveBindingsController (the preview route) and WordPressBindingEditorScript. A method's services are given by ReflectionMethodInvoker (the container's, or a class that needs no argument); give the resolver a MethodInvokerInterface to inject differently.
The Laravel side stays in the framework: the service provider, config/block-bindings.php, pollora:binding:list and pollora:make:binding, the pollora:doctor check, and the injection of method parameters through Laravel's container.
Testing
composer test # unit tests, PHPStan, Pint
License
MIT. See LICENSE.