WordPress REST API – Modifying responses


The WordPress REST API provides an interface for applications to interact with your WordPress site by sending and receiving data as JSON (JavaScript Object Notation) objects. By default, it provides REST endpoints (URLs) representing the posts, pages, taxonomies, and other built-in WordPress data types. Your application can send and receive JSON data to these endpoints to query, modify and create content on your site. However, it is also possible to extend the WP REST API, in order to perform specific actions that are outside of the scope of the default routes and endpoints. In this session, you will learn about one of the ways you can extend the WP REST API, by modifying REST responses.

Learning outcomes

  1. Learn the different ways to add custom fields to the WP REST API
  2. Add custom top-level fields to the Posts route using register_rest_field
  3. Post custom data to the Posts route
  4. Enable custom meta fields for the WP REST API using register_meta
  5. Post meta data to the Posts route

Comprehension questions

  1. Which method of modifying REST API responses is considered less risky?
  2. What is the correct action to hook into when registering custom fields on a REST API endpoint
  3. What are two good reasons for defining a REST API custom field schema
View the video transcript

Hey there, and welcome to Learn WordPress.

In this tutorial, you’re going to learn how to modify WordPress REST API responses. You will learn about two methods of adding fields to your REST API requests, either by enabling custom fields in the REST API route, or by making custom fields available as top level fields. You’ll also learn about the pros and cons to both approaches.

For the purposes of this tutorial, you’ll be using the postman API testing tool to test your modified API requests. If you haven’t done it already, download and instal the postman app for your operating system.

Before we get started, it’s important to note that modifying WordPress REST API responses can have unexpected consequences. Changing or removing data from core REST API endpoint responses can break plugins or WordPress Core behaviour, and should be avoided whenever possible. If you need to retrieve a subset of data from a REST API request, the recommended method is rather to use the fields global parameter to limit the fields returned in the response. For example, you can use the fields parameter to limit the fields returned to just ID title and excerpt if those are the only fields you need for your application.

So for example, here we have a standard GET request to the post endpoint. And you can see in the response, it returns all the fields. However, we just need a few fields. So we can use the fields parameter, and specify ID, title, and excerpt. And when we process that request, only those fields will be returned.

Adding fields to a REST API response is considered less risky. And so this tutorial only covers adding fields.

In the custom fields and authentication tutorial, you learned how to take custom fields, also known as post meta added using the register meta function to enable them for the WordPress REST API. To do this, you use the show in rest argument in the arguments array passed to the register meta function and set it to true. This will enable the custom fields to be added to the REST API response, and will also allow you to post data to the custom field using the REST API. This is handled by passing the custom field as a key value pair in the meta object of the request body.

So for example, if we had a post request configured to the posts route, with the authorization already set to the application password, we could pass in a JSON body that looks like this. So it has a title. It has some content, it has a status, and then it has the meta object. And inside of the meta object, there is a URL property with a value. If we submit this request, the post is created. And the URL custom field is stored in the meta object. And we can verify this by looking at the post and seeing the custom fields stored on the post.

This is also the most common way to enable custom fields on your WordPress REST API routes, as it allows you to make use of custom fields you may have already registered using the register meta function. Prior to WordPress four point 9.8 Custom Fields set to show in rest using register meta were registered for all objects of a given type. For example, if you added a custom field to the posts type, and then created a Custom Post Type, the custom field will automatically be available on the Custom Post Type. As of WordPress four point 9.8 It’s possible to use register meta with the object subtype argument that allows one to reduce the usage of the meta key to a particular post type. For example, let’s say in your plugin you have a URL custom field registered to the default post type. You then decide to register a new Custom Post Type called Book.

By default, the URL custom field will be available on both posts and books. You then decide you want the URL custom fields to only be available on the book Custom Post Type. You can do this by passing the object subtype arguments of existing reg submitter function.

So here we can say object sub type, and set it to book.

If you queried posts via the REST API, the URL meta field would no longer be visible, it would now only appear if you query the box. You can register additional custom fields on a Custom Post Type using the objects of type argument. For example, if you wanted to register a custom field called ISBN on the book Custom Post Type.

So for that, let’s grab the register meta code. And it’s generally better to register your post meta after the post. And then we can use it again, to do an ISBN, and assign it to the sub object subject book.

You would now have both URL and ISBN custom fields available on the book Custom Post Type. You can test this by adding a book via the REST API. So let’s create a new request.

That will post to the book endpoint. And we can copy out the URL. Change the method to a post use the basic authentication, which has already been saved from previous requests. And then set the body to pass in some JSON. And the object can look like this. So title, new book content, new book content, status of publish, and then pass in the URL, an ISBN in the meta object. And let’s send that request. And the book has been created with the URL and ISBN custom fields.

The other way to add custom fields to the REST API is to add them as top level fields on REST API responses. In the earlier example, the ISBN was registered as a meta field, and is therefore available in the meta objects of the REST API response for the book. But what if you prefer to have it as a top level field alongside things like title, content and excerpt. This can be achieved using the register rest field function. Let’s look at how this would be implemented. First, you need to register your rest fields in the REST API and knit action hook. This is to ensure that the field is only registered on the REST API.

So right at the top here, let’s say add action. So REST API init as the hook. And the function we’ll use is WP learn REST API init. And let’s create that function and set it up to start registering fields.

You can then use the register rest field function to register the field. The first parameter is the object type the field should be registered on. This can be a string for a single object or an array for more than one object. In this case, just register the field on the book Custom Post Type. The second argument is the name of the field. In this case, just make it the same as the custom field ISBN.

The third parameter is an array of arguments that determines how the field functions, you need to pass at least the following three arguments to this array.

So the first is the get callback.

This is a function that returns the value of the field.

The second is the update callback.

This is a function that updates the value of the field when a post request is made.

And lastly, the schema

This is an array containing the schema for the field. For now you can leave the schema argument of the rest field as null, but you will need to specify the get callback and update callback functions. These are the functions that will be triggered when an API request is made, either to fetch the data, or to create or update the data.

So for these two, we can just go something as simple as wp_learn_rest_get_isbn. And wp_learn_rest_update isbn. We need to create these functions. So get ISBN and update ISBN.

By default, an array of the post type’s prepared data is passed to the get callback function as the first argument.

An implementation of this function could be as straightforward as returning the value of the custom field.

So we can specify a book variable here to receive that prepared data. And then do something as simple as return, get post meta. And then book ID as the ID of the book, average return the ISBN meta property. And we need to pass in true for the third parameter because this is a single response.

The value sent for the field from a REST API create or update request is passed to the update callback function as the first argument and the model objects ie the post as the second argument.

So when we’re working with the update function, we can pass in, or at least set up a value variable to receive the new value. In this case, we can set up book to receive Custom Post Type.

An implementation of this function could be as simple as updating the value of the custom field.

So we could do something like this, we could say return update post meta book. And because this is an object, we need to reference the ID using the objects index. Specify the custom field that we’re updating and pass in the new value.

You can test this out by creating a new book and passing a value for the ISBN field, you’ll see the data being saved to the database in the post meta table, but being displayed as a top level field and the REST API response.

So let’s have a look at that. So here is our book request. So let’s create. Let’s use that to create a new book with some additional fields, and pass in a slightly different set of data there and hit send. So the book has been created, you’ll notice that it contains the meta object, which contains the URL and the ISBN. But the ISBN field is also duplicated in the top level field.

If we requested the books, and we removed meta and specified ISBN then we will receive the ISBN field because it is available as a registered field on the box.

The schema argument of register rest field is an array that describes the schema for the field. While it’s not a requirement, including a schema is encouraged, if nothing else, it helps future developers understand what the field is for. It can also be used to validate the data being sent when creating automated API tests.

So your schema could be as simple as saying something like creating an array and then passing in a description. The say something like the isbn a number of the book. And then we would also want to give it a type and we’ll make it a string.

You can read more about how to define the schema for REST API resources and fields in the WP REST API handbook at developer.wordpress.org.

The main advantage of using the register meta routes is that you do not need to add any further code to enable storing or retrieving data from the custom fields. As long as you remember to fetch and save the data using the meta object in your application code. You enable the field to show it to The REST API and you can use it straight away. This is also the more performant option, as it does not add any additional code that needs to be executed.

On the other hand, the main advantage of using the register rest field route is that the field appears as a top level field in your REST API routes. The other advantage is that you can perform additional processing on the data before it is returned, or before it is saved. For example, you could perform some validation on the data before it is saved to the database. You could also add hooks to the get callback and update callback functions to either perform additional processing on the data or to allow other developers to extend your custom fields. The downside is that you’re adding a slight overhead to the API requests as it as more code that needs to be executed.

Ultimately, the route you choose should be decided on a case by case basis.

For more information on this, check out the modifying responses section of the WP REST API handbook at developer.wordpress.org.

Happy coding

Introduction

Hey there, and welcome to Learn WordPress.

In this tutorial, you’re going to learn how to modify WP REST API responses.

You will learn about two methods of adding fields to your REST API requests, either by enabling custom fields in the REST API route, or by making custom fields available as top level fields.

You’ll also learn about the pros and cons to both approaches.

For the purposes of this tutorial, you’ll be using the Postman API testing tool to test your modified API requests. If you haven’t done it already, download and install the Postman app for your operating system.

Important note about modifying responses

Before we get started, it’s important to note that modifying WP REST API responses can have unexpected consequences. Changing or removing data from core REST API endpoint responses can break plugins or WordPress core behavior, and should be avoided wherever possible.

If you need to retrieve a subset of data from a REST API request, the recommended method is to rather use the _fields global parameter, to limit the fields returned in the response.

For example, you can use the fields parameter to limit the fields returned to just id, title, and expert, if those are the only fields you need for your application.

Adding fields to a REST API response is less risky, and so this tutorial only covers adding fields.

Enabling Custom Fields for the WP REST API

In the [Custom Fields and Authentication tutorial](), you learned how take custom fields, also known as post meta, added using the register_meta function and enable them for the WP REST API.

To do this, you used the show_in_rest argument in the arguments array passed to the register_meta function, and set it to true.

    register_meta(
        'post',
        'url',
        array(
            'single'       => true,
            'type'         => 'string',
            'default'      => '',
            'show_in_rest' => true,
        )
    );

This will enable the custom field to be added to the REST API response, and will also allow you to post data to the custom field using the REST API. This is handled by passing the custom field as a key value pair in the meta object of the request body.

{
    "title": "New Post Title",
    "content": "New Post Content",
    "status": "publish",
    "meta": {
        "url": "https://learn.wordpress.org"
    }
}

This is the most common way to enable custom fields on your WP REST API routes, as it allows you to make use of custom fields you may have already registered using the register_meta function.

Enabling Custom Fields for the specific WP REST API routes

Prior to WordPress 4.9.8, custom fields set to show_in_rest using register_meta were registered for all objects of a given type. For example, if you added a custom field to the posts type, and then created a custom post type, the custom field would automatically be available in the custom post type. As of WordPress 4.9.8 it’s possible to use register_meta with the object_subtype argument that allows one to reduce the usage of the meta key to a particular post type.

For example, let’s say in your plugin you have a url custom field registered on the default post type:

    register_meta(
        'post',
        'url',
        array(
            'single'       => true,
            'type'         => 'string',
            'default'      => '',
            'show_in_rest' => true,
        )
    );

You then decide to register a new custom post type book:

    /**
     * Register a book custom post type
     */
    register_post_type(
        'book',
        array(
            'labels'       => array(
                'name'          => __( 'Books' ),
                'singular_name' => __( 'Book' )
            ),
            'public'       => true,
            'has_archive'  => true,
            'show_in_rest' => true,
            'supports'     => array(
                'title',
                'editor',
                'thumbnail',
                'excerpt',
                'custom-fields',
                'revisions',
            ),
            'taxonomies'   => array(
                'category',
                'post_tag',
            ),
        )
    );

By default, the url custom field will be available on both Posts and Books.

You then decide you want the url custom field to only be available on the book custom post type. You can do this by passing the object_subtype argument to the existing register_meta function.

    register_meta(
        'post',
        'url',
        array(
            'single'         => true,
            'type'           => 'string',
            'default'        => '',
            'show_in_rest'   => true,
            'object_subtype' => 'book',
        )
    );

If you queried Posts via the REST API, the url meta field would no longer be visible. It would now only appear if you queried the Books.

You can register additional custom fields on a custom post type using the object_subtype argument. For example, if you wanted to register a custom field isbn on the book custom post type:

    register_meta(
        'post',
        'url',
        array(
            'single'         => true,
            'type'           => 'string',
            'default'        => '',
            'show_in_rest'   => true,
            'object_subtype' => 'book',
        )
    );

You would now have both url and isbn custom fields available on the book custom post type.

You can test this by adding a book via the REST API.

Create a new POST request to the book route:

https://example.com/wp-json/wp/v2/book

Then post the following in the request body:

{
    "title": "New Book",
    "content": "New Book Content",
    "status": "publish",
    "meta": {
        "url": "https://book.wordpress.org",
        "isbn": "978-1-4302-6418-2"
    }
}

Adding Custom Fields as top level fields to API Responses

The other way to add custom fields to the WP REST API is to add them as top level fields on the API responses.

In the earlier example, the isbn was registered as a meta field, and is therefore available in the meta object of the REST API response. But what if you’d prefer to have it as a top level field, alongside the title, content, and excerpt?

This can be achieved using the register_rest_field function. Let’s look at how this would be implemented.

First, you need to register your rest fields in the rest_api_init action hook. This is to ensure that the field is only registered on the REST API.

add_action( 'rest_api_init', 'wp_learn_rest_add_fields' );
function wp_learn_rest_add_fields() { 
    // register some REST API functionality
}

You then use the register_rest_field function to register the field. The first parameter is the object type the field should be registered on. This can be a string, for a single object, or an array, for more than one object. In this case, just register the field on the book custom post type. The second argument is the name of the field. In this case, just make it the same as the custom field, isbn.

    register_rest_field(
        'book',
        'isbn',
    );

The third parameter is an array of arguments that determines how the field functions. You need pass at least the following three arguments to the array.

  1. get_callback – a function that returns the value of the field
  2. update_callback – a function that updates the value of the field
  3. schema – an array containing the schema for the field
    register_rest_field(
        'book',
        'isbn',
        array(
            'get_callback'    => null,
            'update_callback' => null,
            'schema'          => null,
        )
    );

For now, you can leave the schema argument of the rest field as null, but you will need to specify the get_callback and update_callback functions. These are the functions that will be triggered when the API request is made, either to fetch the data, or to create or update the data.

    register_rest_field(
        'book',
        'isbn',
        array(
            'get_callback'    => 'wp_learn_rest_get_isbn',
            'update_callback' => 'wp_learn_rest_update_isbn',
            'schema'          => null,
        )
    );

By default, an array of the post type’s prepared data is passed to the get_callback function as the first argument. An implementation of this function could be as straightforward as returning the value of the custom field.

function wp_learn_rest_get_isbn( $book ){
    return  get_post_meta( $book['id'], 'isbn', true );
}

The value sent for the field from a REST API create or update request is passed to the update_callback function as the first argument, and the model object (ie the post) as the second. An implementation of this function could be as simple as updating the value of the custom field.

function wp_learn_rest_update_isbn( $value, $book ){
    return update_post_meta( $book->ID, 'isbn', $value );
}

If you test this out by creating a new book, and passing a value for the isbn field, you’ll see the data being saved to the database in the post_meta table, but is also displayed as a top level field in the REST API response.

Including Schema

The schema argument is an array that describes the schema for the field. While it’s not a requirement, including a schema is encouraged. If nothing else, it helps future developers understand what the field is for. It can also be used to validate the data being sent when creating automated API tests

    register_rest_field(
        'book',
        'isbn',
        array(
            'get_callback'    => 'wp_learn_rest_get_isbn',
            'update_callback' => 'wp_learn_rest_update_isbn',
            'schema'          => array(
                'description' => __( 'The ISBN of the book' ),
                'type'        => 'string',
            ),
        )
    );

You can read more about how to define the schema for REST API resources and fields in the WP REST API Handbook.

Deciding between register_rest_field vs register_meta

The main advantage of using the register_meta route is that you do not need to add any further code to enable storing or retrieving data from the custom fields, as long as you remember to fetch and save the data using the meta object in your application code. You enable the field to show in the REST API, and you can use it straight away. This is also the more performant option, as it does not add any additional code that needs to be executed.

On the other hand, the main advantage of using the register_rest_field route is that the fields appear as top level fields in your REST API routes. The other advantage is that you can perform additional processing on the data before it is returned, or before it is saved. For example, you could perform some validation on the data before it is saved to the database. You could also add hooks to the get_callback and update_callback functions to either perform additional processing on the data, or to allow other developers to extend your custom fields. The downside is that you’re adding a slight overhead to the API requests, as it adds more code that needs to be executed.

Ultimately, the route you choose should be decided on a case by case basis.

For more information on this, check out the Modifying Responses section of the WP REST API Handbook.

Happy coding!

Workshop Details


Presenters

Jonathan Bossenger
@psykro

WordPress Developer Educator at Automattic, full-time sponsored member of the training team creating educational content for developers on Learn WordPress. Husband and father of two energetic boys.