PHPackages                             kaiseki/wp-meta - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Utility &amp; Helpers](/categories/utility)
4. /
5. kaiseki/wp-meta

ActiveLibrary[Utility &amp; Helpers](/categories/utility)

kaiseki/wp-meta
===============

Fluent, type-safe DSL for registering WordPress meta.

1.0.0(1mo ago)12MITPHPPHP ^8.2CI passing

Since Jun 1Pushed 3w ago2 watchersCompare

[ Source](https://github.com/kaisekidev/kaiseki-wp-meta)[ Packagist](https://packagist.org/packages/kaiseki/wp-meta)[ Docs](https://github.com/kaisekidev/kaiseki-wp-meta)[ RSS](/packages/kaiseki-wp-meta/feed)WikiDiscussions master Synced 3w ago

READMEChangelog (1)Dependencies (31)Versions (3)Used By (0)

kaiseki/wp-meta
===============

[](#kaisekiwp-meta)

Type-safe WordPress meta registration through a fluent field DSL.

You describe each meta field with a typed builder (`StringField`, `IntegerField`, `ObjectField`, …). From that description the package builds the `register_meta()`arguments and the REST `show_in_rest` JSON schema, so WordPress validates REST requests against the field's type and constraints. The library stays intentionally minimal — write-time sanitization is opt-in via `withSanitizeCallback()`.

Installation
------------

[](#installation)

```
composer require kaiseki/wp-meta
```

Requires PHP 8.2 or newer.

Usage
-----

[](#usage)

Implement `MetaDataBuilderInterface` and return your `MetaData` definitions from `buildMetaData()`:

```
use Kaiseki\WordPress\Meta\Field\IntegerField;
use Kaiseki\WordPress\Meta\Field\StringField;
use Kaiseki\WordPress\Meta\MetaData;
use Kaiseki\WordPress\Meta\MetaDataBuilderInterface;

final class ProductMeta implements MetaDataBuilderInterface
{
    /**
     * @return list
     */
    public function buildMetaData(): array
    {
        return [
            MetaData::post(
                'product',
                'sku',
                StringField::create()->withMaxLength(32),
            )->withShowInRest(),
            MetaData::post(
                'product',
                'stock',
                IntegerField::create(0)->withMinimum(0),
            )->withShowInRest(),
        ];
    }
}
```

### Scalar fields

[](#scalar-fields)

```
use Kaiseki\WordPress\Meta\Field\StringField;
use Kaiseki\WordPress\Meta\Field\StringFormat;
use Kaiseki\WordPress\Meta\MetaData;

MetaData::post(
    'page',
    'contact_email',
    StringField::create()
        ->withFormat(StringFormat::Email)
        ->withMaxLength(254),
)->withShowInRest();
```

### Nullable fields

[](#nullable-fields)

Nullability is opt-in and independent of the default. A field is non-nullable unless you call `->nullable()`, which makes `null` a valid value and emits a `['', 'null']` schema type:

```
use Kaiseki\WordPress\Meta\Field\StringField;
use Kaiseki\WordPress\Meta\MetaData;

MetaData::post(
    'page',
    'subtitle',
    StringField::create()->nullable(),
)->withShowInRest();
```

### Numeric fields

[](#numeric-fields)

```
use Kaiseki\WordPress\Meta\Field\NumberField;
use Kaiseki\WordPress\Meta\MetaData;

MetaData::post(
    'product',
    'rating',
    NumberField::create(0.0)
        ->withMinimum(0)
        ->withMaximum(5),
)->withShowInRest();
```

### Object fields

[](#object-fields)

`ObjectField` composes other fields as properties. Mark properties as required and decide whether extra keys are allowed with `withAdditionalProperties()`:

```
use Kaiseki\WordPress\Meta\Field\IntegerField;
use Kaiseki\WordPress\Meta\Field\ObjectField;
use Kaiseki\WordPress\Meta\Field\StringField;
use Kaiseki\WordPress\Meta\MetaData;

MetaData::post(
    'page',
    'address',
    ObjectField::create()
        ->withProperty('street', StringField::create(), required: true)
        ->withProperty('zip', StringField::create())
        ->withProperty('floor', IntegerField::create())
        ->withAdditionalProperties(false),
)->withShowInRest();
```

### Array fields

[](#array-fields)

```
use Kaiseki\WordPress\Meta\Field\ArrayField;
use Kaiseki\WordPress\Meta\Field\StringField;
use Kaiseki\WordPress\Meta\MetaData;

MetaData::post(
    'post',
    'keywords',
    ArrayField::create(StringField::create())
        ->withMaxItems(10)
        ->withUniqueItems(),
)->withShowInRest();
```

### Non-post object types

[](#non-post-object-types)

`MetaData` also targets terms, users, and comments. Terms take a taxonomy; users and comments take only a meta key:

```
use Kaiseki\WordPress\Meta\Field\StringField;
use Kaiseki\WordPress\Meta\MetaData;

MetaData::term('category', 'color', StringField::create())
    ->withShowInRest();

MetaData::user('bio', StringField::create())
    ->withDescription('The user biography.')
    ->withShowInRest();
```

### Registering the builder

[](#registering-the-builder)

The package ships a `ConfigProvider` that registers `MetaDataRegistry` as a hook provider (via `kaiseki/wp-hook`) and wires its factory. List your builders under the `meta.data_builder` config key — entries are container service ids the registry resolves:

```
use Kaiseki\WordPress\Meta\ConfigProvider;

return [
    'meta' => [
        'data_builder' => [
            ProductMeta::class,
        ],
    ],
    ...(new ConfigProvider())(),
];
```

On the `init` hook the registry builds every definition and calls `register_meta()` with the generated arguments.

### Validation model

[](#validation-model)

By design the library does as little as possible at runtime. From each field it builds the `register_meta()` arguments and, when you call `withShowInRest()`, a JSON schema. WordPress validates incoming **REST** requests against that schema before they are written.

Writes that bypass REST (for example a direct `update_post_meta()` call) are **not** sanitized by default — the value is stored as given. If you want write-time coercion, opt in per definition with `withSanitizeCallback()`, which maps onto `register_meta()`'s native `sanitize_callback`:

```
use Kaiseki\WordPress\Meta\Field\IntegerField;
use Kaiseki\WordPress\Meta\MetaData;

MetaData::post('product', 'stock', IntegerField::create(0))
    ->withShowInRest()
    ->withSanitizeCallback(static fn(mixed $value): int => (int) $value);
```

Development
-----------

[](#development)

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

License
-------

[](#license)

MIT — see [LICENSE](LICENSE).

###  Health Score

40

—

FairBetter than 86% of packages

Maintenance95

Actively maintained with recent releases

Popularity4

Limited adoption so far

Community8

Small or concentrated contributor base

Maturity47

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 100% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~1549 days

Total

2

Last Release

31d ago

PHP version history (2 changes)1.0.x-devPHP ^7.4

1.0.0PHP ^8.2

### Community

Maintainers

![](https://www.gravatar.com/avatar/1c3a6b11aea9668c9e9ca0c0f8515ef114d344acb552c695d715d35d5b388ea4?d=identicon)[woda](/maintainers/woda)

---

Top Contributors

[![wolfgangschaefer](https://avatars.githubusercontent.com/u/26325205?v=4)](https://github.com/wolfgangschaefer "wolfgangschaefer (7 commits)")

---

Tags

wordpressmodule

###  Code Quality

TestsPHPUnit

Static AnalysisPHPStan

Type Coverage Yes

### Embed Badge

![Health badge](/badges/kaiseki-wp-meta/health.svg)

```
[![Health](https://phpackages.com/badges/kaiseki-wp-meta/health.svg)](https://phpackages.com/packages/kaiseki-wp-meta)
```

###  Alternatives

[symfony/dependency-injection

Allows you to standardize and centralize the way objects are constructed in your application

4.2k455.6M9.5k](/packages/symfony-dependency-injection)[illuminate/contracts

The Illuminate Contracts package.

706130.3M13.2k](/packages/illuminate-contracts)[illuminate/container

The Illuminate Container package.

31182.0M2.4k](/packages/illuminate-container)[ecotone/ecotone

Enterprise architecture layer for Laravel and Symfony — CQRS, Event Sourcing, Durable Workflows (Sagas, Orchestrators), Projections, and Outbox messaging via PHP attributes.

564576.7k49](/packages/ecotone-ecotone)[civicrm/civicrm-core

Open source constituent relationship management for non-profits, NGOs and advocacy organizations.

751291.4k41](/packages/civicrm-civicrm-core)[symfony/object-mapper

Provides a way to map an object to another object

361.5M54](/packages/symfony-object-mapper)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
