Skip to content
wp-skills
Register
tools/rest-field-generator

WordPress REST API Field Generator

Add a field to an existing REST API response with register_rest_field(): a schema, a get_callback that reads the prepared array, and an update_callback that receives the real object.

Comma separated. Several types share one registration — register_rest_field() takes an array.

The key this appears under, at the top level of the response rather than inside 'meta'.

Runs on rest_api_init. A field registered on init is registered too early to reach the response.

A field that only reads one meta key is usually better served by register_post_meta() with show_in_rest, which brings a type, a sanitizer and an auth rule with it.

Read with get_post_meta() and written with update_post_meta(). Defaults to the field name.

'view' is the public response; 'edit' is what the block editor reads.

Drops the update_callback. WordPress then accepts a write to the field without applying one, rather than rejecting the request.

Receives the prepared response array, not a WP_Post — reading $post->ID there fails at request time.

Receives the real object, which is the asymmetry with the getter above. That is core's choice, not ours.

snippet.php
/**
 * Adds 'reading_time' to the 'post' REST response.
 *
 * The hook is 'rest_api_init'. A field registered on 'init' is registered too
 * early to reach the response.
 *
 * Worth knowing before using this: a field that only reads one meta key is
 * usually better registered with register_post_meta( ..., 'show_in_rest' =>
 * true ), which exposes it under 'meta' and brings a type, a sanitizer and an
 * auth rule with it. register_rest_field() is the right tool when the value is
 * computed, when it joins several sources, or when it has to appear at the top
 * level of the response rather than inside 'meta'.
 */
function wps_register_rest_fields() {
	register_rest_field(
		'post',
		'reading_time',
		array(
			'get_callback'    => 'wps_get_reading_time',
			'update_callback' => 'wps_update_reading_time',
			'schema'          => array(
				'type'        => 'integer',
				'context'     => array( 'view', 'edit' ),
				'description' => 'Estimated reading time in minutes.',
			),
		)
	);
}
add_action( 'rest_api_init', 'wps_register_rest_fields' );

/**
 * Reads the value for a response.
 *
 * The parameter is the *prepared response array*, not a WP_Post — that is
 * core's choice, and it is why this reads $prepared['id'] rather than
 * $post->ID. The latter fails at request time with "Attempt to read property
 * ID on array".
 */
function wps_get_reading_time( $prepared ) {
	return get_post_meta( $prepared['id'], 'reading_time', true );
}

/**
 * Writes a value sent for this field.
 *
 * Note the asymmetry with the getter above, which is core's: update_callback
 * receives the real object — a WP_Post for a post type — while get_callback
 * receives an array.
 */
function wps_update_reading_time( $value, $post ) {
	$updated = update_post_meta( $post->ID, 'reading_time', $value );

	if ( false === $updated ) {
		return new WP_Error(
			'rest_field_not_updated',
			__( 'Could not update the field.', 'text-domain' ),
			array( 'status' => 500 )
		);
	}

	return true;
}