WordPress Utilities

kaiseki/wp-acf-dto

Easily create DTOs from ACF fields.

Maps Advanced Custom Fields (ACF) data onto typed, immutable spatie/laravel-data objects. Define a DTO once, then hydrate it from a post’s ACF fields — with casts that turn raw field values into WP_Post/WP_Term/WP_User objects, DateTimeImmutables, validated e-mails/URLs, and nested DTOs.

Installation

composer require kaiseki/wp-acf-dto

Requires PHP 8.2 or newer.

Usage

Define a DTO

Extend the package’s Data base class (a spatie/laravel-data data object with a safe-construction helper) and annotate properties with the bundled casts. Property names map to ACF field names via spatie’s name mappers.

use DateTimeImmutable;
use Kaiseki\WordPress\ACF\Dto\Casts\DateTimeCast;
use Kaiseki\WordPress\ACF\Dto\Casts\WpPostCast;
use Kaiseki\WordPress\ACF\Dto\Castables\Link;
use Kaiseki\WordPress\ACF\Dto\Data;
use Spatie\LaravelData\Attributes\MapName;
use Spatie\LaravelData\Attributes\WithCast;
use Spatie\LaravelData\Mappers\SnakeCaseMapper;
use WP_Post;

#[MapName(SnakeCaseMapper::class)]
class EventData extends Data
{
    public function __construct(
        public readonly ?string $headline,
        #[WithCast(DateTimeCast::class)]
        public readonly ?DateTimeImmutable $startsAt,
        // Resolves an ACF post-object field to a lazy WP_Post wrapper.
        #[WithCast(WpPostCast::class, postType: 'page')]
        public readonly ?WP_Post $relatedPage,
        // Nested DTO: an ACF link field becomes a Link data object.
        public readonly ?Link $cta,
    ) {
    }
}

Build a DTO from a post’s ACF fields

AcfDataBuilder reads every field for a post (via ACF’s get_fields()), merges in any defaults, and constructs the DTO:

use Kaiseki\WordPress\ACF\Dto\AcfDataBuilder;
use Kaiseki\WordPress\ACF\Dto\AcfGetFields;

$builder = new AcfDataBuilder(new AcfGetFields());

$event = $builder->create(
    EventData::class,
    postId: get_the_ID(),
    defaults: ['headline' => 'Untitled'],
);

To swallow construction errors (e.g. validation failures) and get null instead of an exception, use the trait’s safeFrom():

$event = EventData::safeFrom(get_fields());

Read single fields with type safety

AcfFieldValue wraps get_field() with a typed accessor per return type, narrowing ACF’s loose return values to the declared PHP type (or null):

use Kaiseki\WordPress\ACF\Dto\AcfFieldValue;

$field = new AcfFieldValue();

$title    = $field->string('headline');           // ?string
$count    = $field->int('seats');                 // ?int
$starts   = $field->dateTime('starts_at');        // ?DateTimeImmutable
$ids      = $field->idList('related_posts');      // list<int>
$author   = $field->wpUser('author');             // ?WpUser
$link     = $field->link('cta');                  // ?Link

Register the spatie/laravel-data config

ConfigProvider returns the package’s spatie/laravel-data configuration (date format, casts, transformers, normalizers) for laminas-style config aggregators:

use Kaiseki\WordPress\ACF\Dto\ConfigProvider;

$config = (new ConfigProvider())();

Development

composer install
composer check   # check-deps, cs-check, phpstan

License

MIT — see LICENSE.

Previous
kaiseki/wp-acf