Registering field types#
ACF Chef ships verbs for the field classes included with extended-acf.
It does not ship plugin-specific field classes. A field type from ACF Extended, another plugin or your own project becomes an ACF Chef verb by defining an extended-acf field class and registering it.
Define the field class#
The smallest custom type extends Extended\ACF\Fields\Field and declares the ACF field type:
use Extended\ACF\Fields\Field;
final class AcfeColumn extends Field
{
protected ?string $type = 'acfe_column';
}
Register the class under the verb you want to use:
use AcfChef\Chef;
Chef::register('acfeColumn', AcfeColumn::class);
The field is then declared like a built-in type:
$group->acfeColumn('start')->config([
'columns' => '1/2',
]);
It compiles through the same field pipeline as the types ACF Chef registers by default.
Chef::register()#
The registration method takes three arguments:
Chef::register(
string $verb,
string $class,
bool $container = false,
);
The verb becomes the fluent method name. The class supplies the extended-acf field implementation.
Set container: true when the type can hold child fields.
Verb names are normalised#
Registration and lookup both normalise verb names to camel case.
These therefore identify the same registered verb:
Chef::register('acfe_column', AcfeColumn::class);
$group->acfeColumn('start');
$group->acfe_column('end');
Registering a verb that already exists replaces its class mapping.
The container flag is replaced as well. Passing container: false explicitly removes a container flag set by an earlier registration:
Chef::register('panel', AcfePanel::class, container: true);
Chef::register('panel', AcfePanel::class, container: false);
After the second call, panel is no longer treated as a container.
Registration is validated immediately#
Chef::register() validates its arguments in a fixed order.
An empty verb raises InvalidArgumentException:
A field verb cannot be empty.
A verb that cannot be called as a PHP method raises:
Cannot register [2fa]: a verb is called as a method, so it must be a valid PHP identifier.
A missing class raises:
Cannot register [x]: the class [Foo] does not exist.
A class that does not extend the extended-acf field base raises:
Cannot register [x]: [Foo] must extend Extended\ACF\Fields\Field.
These are ordinary InvalidArgumentException instances rather than ACF Chef definition exceptions.
Register container fields#
Pass container: true for a type that holds children:
final class AcfePanel extends Extended\ACF\Fields\Group
{
protected ?string $type = 'acfe_panel';
}
Chef::register(
'panel',
AcfePanel::class,
container: true,
);
You can then nest fields through the usual closure:
$group->panel('advanced', fn ($panel) => $panel
->text('note')
->trueFalse('featured'));
At compile time, ACF Chef builds the children and hands them to the custom class.
If the field object has a layouts() method, ACF Chef uses it. Otherwise it looks for fields().
Extending an existing extended-acf container such as Group, Repeater or FlexibleContent therefore gives you the corresponding child attachment behaviour without another adapter.
A bad container registration fails at compile time#
container: true says that ACF Chef may attach children to the field. Registration itself does not verify that the class actually has a compatible container method.
If the class has neither layouts() nor fields(), the registration succeeds and the failure appears when the definition compiles:
Your\Class is registered as a container but cannot hold fields.
The exception is a BadMethodCallException.
This distinction matters when diagnosing bootstrap code: a bad class mapping can remain quiet until a group using it reaches compilation.
Registered verbs are first-class#
A registered field type participates in the same system as a built-in verb.
Once registered, it works with:
- Fluent field chains
add()find(),modify()andremove()paths- Field-key generation
- Conditional target resolution
Chef::registry()->verbs()- The
verbsCLI command - Generated field-verb stubs
It can also opt into a marker-style name suffix:
Chef::registry()->nameSuffix(
'divider',
'_divider',
);
The registry is the source of truth for field verbs throughout the package rather than only for dynamic method calls.
There is no generic field passthrough#
ACF Chef deliberately does not provide an API such as:
$group->field(
'title',
'some_custom_type',
['required' => true],
);
A field type outside extended-acf’s built-ins needs a Field subclass and a registration.
That costs one class even when the project uses the type only once, but it keeps the type first-class: its settings methods are real PHP methods, its container behaviour is explicit, and the rest of ACF Chef can treat it exactly like a built-in type.
This is a design decision rather than a missing escape hatch.
Register extensions before groups compile#
The registry is consulted at compile time, not when the group is first declared.
Register custom field types during application loading, not inside acf/init.
A group may be declared before the registration code runs as long as the verb is registered before that group compiles.
See Getting started for the registration-order rule and why the register() call is the boundary that matters.
Editor and static-analysis support#
Dynamic verbs are valid at run time as soon as they are registered, but editors and PHPStan need generated type information to know about them.
That tooling is covered separately in IDE and static analysis.