Transform a stored field value before display
Custom fields store data in whatever shape is convenient to save: a date as YYYY-MM-DD, a price in whole cents, a related record as a bare post ID. None of those are what a person wants to look at.
benecaster_field_value lets you present the value differently without changing what is stored. The stored data stays exactly as it is — you are changing the answer, not the record — so the formatting is reversible and cannot corrupt anything. It applies everywhere the value is read, including the episode editor and the REST API, so the whole product sees the same friendly version.
When to Use This
Use benecaster_field_value to transform values when:
-
A date field stores
YYYY-MM-DDand you want a localized format in the editor -
A number field stores a price in cents and you want it displayed as
$12.99 -
A text field stores an ID that you want resolved to a human-readable label
-
You need to apply consistent sanitization that you didn’t want to bake into the stored data
This filter fires on every read — from benecaster_get_field(), benecaster_get_fields(), and the REST endpoint that loads values for the editor. That means the transformation is transparent: the stored value is unchanged, but every consumer sees the formatted version.
How It Works
The filter hands you the stored value plus enough context to know what you are looking at — which field, which record, and which post type. Return whatever you want callers to see. The recipe covers the two common shapes:
-
Formatting a date. Dates are stored in a fixed machine-readable form and rendered using the site’s own date format, so the editor matches the rest of WordPress. The field-type lookup is cached for the duration of the request, because the filter runs on every read and an uncached query here is a slow editor.
-
Turning an ID into a name. When a field stores a reference to another record — a guest, a product — swap the ID for that record’s title before it reaches the screen, and fall back to the raw value if the record has since been deleted.
Notes
This filter fires on every read — keep it fast. The episode editor may trigger several reads per load. Avoid unmemoised database queries inside the callback; cache lookups in a static variable so they run once per PHP request regardless of how many times the filter fires.
The stored value is never modified. This changes the answer, not the record — remove your filter and the original value is still there, intact. That also means it is the wrong tool for cleaning up data: a value normalised only on display is still messy everywhere the filter does not reach. Use benecaster_field_value_saved to clean values as they are written instead.
Returning null clears the field in the editor. If your transformation produces null, the editor treats the field as empty. Return the original value unchanged when the transformation doesn’t apply.
The CPT slug parameter lets you scope to a specific post type. If you only want to transform values on guest records, check it for benecaster_guest at the top of your callback and return early otherwise.
Related
- Custom Fields — overview of the Field Groups system for podcasters
Code
<?php
add_filter( 'benecaster_field_value', function ( mixed $value, int $field_id, int $object_id, string $cpt_slug ): mixed {
if ( null === $value ) {
return $value;
}
// Example: format date fields as localized date strings.
static $type_cache = [];
if ( ! array_key_exists( $field_id, $type_cache ) ) {
$definition = $GLOBALS['benecaster_container']
->make( \Benecaster\Fields\FieldRegistry::class )
->get_field( $field_id );
$type_cache[ $field_id ] = $definition['field_type'] ?? null;
}
if ( 'date' === $type_cache[ $field_id ] ) {
$timestamp = strtotime( (string) $value );
return $timestamp ? date_i18n( get_option( 'date_format' ), $timestamp ) : $value;
}
return $value;
}, 10, 4 );
Hooks Used
Need this built rather than just documented? See our services →