Index Logo

Modify WordPress REST routes with register rest field

Have you ever wanted to add fields to any built in endpoint, in order to read and update custom data attached to a post object? WordPress makes this easy with the register_rest_route function.

Getting Started

The register_rest_field function is a PHP function that allows you to add extra fields to any registered endpoint (posts, pages, custom post types, terms, users, etc). The function takes three parameters:

register_rest_field(
	$object_type,
	$attribute,
	$args
);

The $object_type parameter is any data type in WordPress, and can be an array of multiple types, or a string for a single type. Next, the $attribute parameter is the name of the field you want to register and will show up in the rest response as the key name.

Finally, the $args parameter is an array with a getter, setter, and schema definition. All three arguments are optional, so you have a lot of flexibility in how you control your field.

Registering a field

Let’s build a real example. In this case we’re going to register a field for posts that shows how many “slaps” the post has, along with a setter to add slaps whenever the user clicks a “slap this post” button.

First we want to target posts and name our attribute:

add_action('rest_api_init', function() {
	register_rest_field(
		'post',
		'slap_count',
		// ... getters and settings
	);
});

Note: wrap your register_rest_field calls in the rest_api_init action to ensures the rest api is loaded

Getting the value

While the above is the only required code to use the register_rest_field function, the field won’t show up in your REST endpoint without at least a get value. Let’s take care of that now:

add_action('rest_api_init', function() {
	register_rest_field(
		'post',
		'slap_count',
		// NEW CODE
		array(
			'get_callback' => function($object) {
				$slap_count = get_post_meta( $object['id'], 'slap_count', true );

				return $slap_count ? $slap_count : 0;
			}
		)
	);
});

The get_callback argument accepts an $object parameter, which in this case is an individual post (passed as an array). Inside of the callback we can use standard WordPress functions like get_post_meta. In this case, we are grabbing the slap_count meta field and returning either the value or 0.

If you query an single post using the /wp-json/wp/v2/posts/<id> endpoint, you should see this line in the response:

"slap_count": 0 // or whatever the value is

For our example, the field so far is pretty useless but if you just wanted to output a value directly then the above is all you need.

Setting the value

To allow updates to the value, add a update_callback argument to the $args array:

add_action('rest_api_init', function() {
	register_rest_field(
		'post',
		'slap_count',
		array(
			'get_callback' => function($object) {
				$slap_count = get_post_meta( $object['id'], 'slap_count', true );

        			return $slap_count ? $slap_count : 0;
			},
			// NEW CODE
			'update_callback' => function ( $value, $object ) {
          			$slap_count = get_post_meta( $object->ID, 'slap_count', true );

          			update_post_meta( $object->ID, 'slap_count', $slap_count + 1 );
			},
		)
	);
});

The update_callback function takes two parameters: $value and $object. In our case we aren’t using the value variable, but instead just adding 1 to the value whenever the callback is fired.

Note: in this function $object is passed as an object type instead of an array like get_callback.

Triggering an update

To actually fire the update_callback function, simply call the /wp-json/wp/v2/posts/<id> endpoint with the POST method, and pass the field name through the body as JSON:

// Javascript example
fetch('/wp-json/wp/v2/posts/1', {
	// make sure to authenticate or pass the X-WP-Nonce value as a header
	method: 'POST',
	body: JSON.stringify({
		"slap_count": 1 // reminder that the value doesn't matter for our example as we just increment the count by one
  	})
})
.then(response => response.json())
.then(data => {
  	// ... the updated post object is returned here
})
.catch(error => console.log('error', error));

Securing your field

As always, a little security goes a long way. The third parameter in the register_rest_field $args array is a schema array with sanitization and validation options:

add_action('rest_api_init', function() {
	register_rest_field(
		'post',
		'slap_count',
		array(
			// ...get_callback
			// ...update_callback

			// NEW CODE
			'schema' => array(
				'type' => 'string' // the type of value we expect to be passed back
				'sanitize_callback' => function($value) {
					// run sanitization here
       				},
        			'validate_callback' => function ($value) {
            				// run sanitization here
        			},
			)
		)
	);
});

The schema parameter takes three arguments:

  • the type of the value (int, string, boolean, etc)
  • A sanitization callback to sanitize the input
  • A validate callback to make sure it conforms to some set of rules

If you haven’t already, read more on sanitizing and validating values accepted into your rest routes here. The same options can be used in the schema callback functions.

Wrap Up

In just a few lines of code, you can completely customize WordPress’ built-in REST routes with your own data. Or combine and extend existing values to avoid unnecessary work in Javascript and prevent multiple REST calls to grab necessary data.

Receive these articles in your inbox

Get started for free

Try Index free for 14 days and see for yourself why it's the best interface for managing your WordPress content — no credit card required.

Start your free trial