ralfhortt / wp-post-meta
WordPress post meta utilities for admin list tables
Requires (Dev)
- mockery/mockery: ^1.6
- pestphp/pest: ^2.0
- yoast/phpunit-polyfills: ^2.0
This package is auto-updated.
Last update: 2026-08-17 07:41:37 UTC
README
WordPress Post Meta Utilities
Fluent Composer package for registering post meta with the REST API, admin list tables, the block editor, and block bindings — without extending classes or writing boilerplate.
PHP 8.1+ · WordPress 5.0+ (block bindings require 6.5+)
composer require ralfhortt/wp-post-meta
Quick start
Register on init. Chain field definitions with optional admin and editor integrations, then call register():
use RalfHortt\Meta\Meta; add_action('init', function () { Meta::for(objectSubtypes: 'product') ->addString(key: 'sku', description: 'Product SKU') ->addNumber(key: 'price', description: 'Product price') ->addBoolean(key: 'featured', description: 'Is featured') ->addColumn(key: 'sku', label: __('SKU', 'plugin'), sortable: true) ->addColumn( key: 'price', label: __('Price', 'plugin'), render: fn($postId) => '$' . number_format((float) get_post_meta($postId, 'price', true), 2), sortable: true ) ->showInQuickEdit(keys: ['sku', 'price']) ->showInEditor(keys: ['sku', 'price'], title: __('Product Details', 'plugin')) ->asBlockBindingSource(keys: [ 'sku' => fn($value) => "SKU: {$value}", 'price' => fn($value) => '$' . number_format((float) $value, 2), ]) ->needsCapability(capability: 'edit_posts') ->register(); });
REST responses include typed meta under meta:
{ "id": 123, "meta": { "sku": "PROD-123", "price": 99.99, "featured": true } }
Meta class
Meta::for(objectType: 'post', objectSubtypes: 'product') creates a registrar for one or more post types. Every integration below is optional — add only what you need.
Field types
| Method | REST type | Storage / notes |
|---|---|---|
addString() |
string |
Plain text |
addText() |
string |
Multiline (textarea in quick edit / editor) |
addBoolean() |
boolean |
Converts true/false ↔ '1'/'0' |
addInteger() |
integer |
Casts to int |
addNumber() |
number |
Casts to float |
addArray() |
array |
Returns [] when empty; not supported in quick edit, editor, or bindings |
addDate() |
string |
ISO 8601 in API; inputFormat for storage ('Y-m-d' or 'timestamp') |
add() |
any | Low-level; accepts custom getCallback, updateCallback, authCallback |
Authorization
needsCapability(capability: 'edit_posts') applies an auth callback to all fields that do not already have one. For per-field rules, pass authCallback to add():
->needsCapability(capability: 'manage_options') // all fields ->add(key: 'cost', type: 'number', authCallback: fn($allowed, $context, $objectId) => current_user_can('manage_shop') && $objectId > 0 )
updateCallback can return WP_Error to reject invalid writes (e.g. SKU format validation).
Admin & editor integrations
| Method | Purpose |
|---|---|
addColumn(key, label, render?, sortable?) |
Admin list table column |
showInQuickEdit(keys) |
Inline edit on list table (string, number, integer, boolean) |
showInEditor(keys, title, metaBoxId?, context?) |
Gutenberg sidebar panel (context: side or normal) |
asBlockBindingSource(keys, render?) |
Block binding source per field (WP 6.5+) |
Block bindings register sources as wp-post-meta/{key} (underscores → dashes). Bind in block markup:
<!-- wp:paragraph { "metadata": { "bindings": { "content": { "source": "wp-post-meta/sku" } } } } --> <p>Fallback</p> <!-- /wp:paragraph -->
Pass a render callback for prefixes, suffixes, or formatting: fn(mixed $value, int $postId): ?string. Keyed arrays set per-field renderers; the second render argument applies to a single key or a list of keys. Array/object fields are skipped. On WordPress < 6.5, binding registration is skipped automatically.
Call showInEditor() multiple times to create separate panels. Array/object field types are skipped in the editor and bindings.
Columns class
Standalone admin columns without REST meta registration:
use RalfHortt\Meta\Columns; Columns::for(postTypes: 'product') ->add(key: 'sku', label: __('SKU', 'plugin')) ->addCurrency(key: 'price', label: __('Price', 'plugin'), currencySymbol: '$') ->addDate(key: 'event_date', label: __('Date', 'plugin'), format: 'F j, Y') ->addBoolean(key: 'featured', label: __('Featured', 'plugin')) ->addImage(key: 'thumbnail', label: __('Image', 'plugin'), width: 50, height: 50) ->addList(key: 'tags', label: __('Tags', 'plugin'), separator: ', ', limit: 3) ->sortable(keys: ['price', 'event_date']) ->register();
Use add(key, label, render) for custom HTML output. sortable(keys) and priority(value) configure list behavior.
API reference
Meta
| Factory | Meta::for(objectType?, objectSubtypes?) |
| Fields | addString, addText, addBoolean, addInteger, addNumber, addArray, addDate, add |
| Auth | needsCapability(capability) |
| Admin | addColumn, showInQuickEdit, showInEditor, asBlockBindingSource |
| Register | register() |
Columns
| Factory | Columns::for(postTypes) |
| Columns | add, addCurrency, addDate, addBoolean, addImage, addList |
| Config | sortable(keys), priority(value) |
| Register | register() |
All methods return self for chaining. Named arguments are supported throughout.
Development
composer test # Run tests (160 passing) composer test:coverage # Requires Xdebug or PCOV
Changelog
v2.0.0 — Fluent API rewrite, REST meta registration, column integration, type helpers, PHP 8.1+ named arguments.
v1.0.0 — Initial release (abstract class pattern).
License
MIT · Ralf Hortt — mail@ralfhortt.dev