Content Live

Key Concepts

In this page we’ll break down some of the key concepts and terms associated with the REST API: Routes & Endpoints, Requests, Responses, Schema, and Controller Classes. Each of these concepts play a crucial role in understanding, using, and extending the WordPress REST API, and each is explored in greater depth within this handbook.

Routes & Endpoints

In the context of the WordPress REST API a route is a URI which can be mapped to different HTTP methods. The mapping of an individual HTTP method to a route is known as an endpoint.

As an example, if we make a GET request to the URI http://oursite.com/wp-json/ we are returned a JSON response showing what routes are available, and what endpoints are available within each route.

/wp-json/ is a route, and when that route receives a GET request then that request is handled by the endpoint which displays what is known as the index for the WordPress REST API.

The route wp-json/wp/v2/posts by contrast has a GET endpoint which returns a list of posts, but also a POST endpoint which accepts authenticated requests to create new posts.

We will learn how to register our own routes and endpoints in the following sections.

If you are using non-pretty permalinks, you should pass the REST API route as a query string parameter. The route http://oursite.com/wp-json/ in the example above would hence be http://oursite.com/?rest_route=/.

If you get a 404 error when trying to access http://oursite.com/wp-json/, consider enabling pretty permalinks or try using the rest_route parameter instead.

Requests

A REST API request is represented within WordPress by an instance of the WP_REST_Request class, which is used to store and retrieve information for the current request. A WP_REST_Request object is automatically generated when you make an HTTP request to a registered API route.

The data specified in this object (derived from the route URI or the JSON payload sent as a part of the request) determines what response you will get back out of the API.

Requests are usually submitted remotely via HTTP but may also be made internally from PHP within WordPress plugin or theme code. There are a lot of neat things you can do using this class, detailed further elsewhere in the handbook.

Responses

Responses are the data you get back from the API. The WP_REST_Response class provides a way to interact with the response data returned by endpoints. Responses return the requested data, or can also be used to return errors if something goes wrong while fulfilling the request.

Schema

Each endpoint requires a particular structure of input data, and returns data using a defined and predictable structure. Those data structures are defined in the API Schema.

The schema structures API data and provides a comprehensive list of all of the properties the API can return and which input parameters it can accept.

Well-defined schema also provides one layer of security within the API, as it enables us to validate and sanitize the requests being made to the API. The Schema section explores this large topic further.

Controller Classes

Controller classes unify and coordinate all these various moving parts within a REST API response cycle. With a controller class you can manage the registration of routes & endpoints, handle requests, utilize schema, and generate API responses.

A single class usually contains all of the logic for a given route, and a given route usually represents a specific type of data object within your WordPress site (like a custom post type or taxonomy).

REST API Handbook

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. It is the foundation of the WordPress Block Editor, and can likewise enable your theme, plugin or custom application to present new, powerful interfaces for managing and publishing your site content.

Using the WordPress REST API you can create a plugin to provide an entirely new admin experience for WordPress, build a brand new interactive front-end experience, or bring your WordPress content into completely separate applications.

The REST API is a developer-oriented feature of WordPress. It provides data access to the content of your site, and implements the same authentication restrictions — content that is public on your site is generally publicly accessible via the REST API, while private content, password-protected content, internal users, custom post types, and metadata is only available with authentication or if you specifically set it to be so. If you are not a developer, the most important thing to understand about the API is that it enables the block editor and modern plugin interfaces without compromising the security or privacy of your site.

What Is A REST API?

An API is an Application Programming Interface. REST, standing for “REpresentational State Transfer,” is a set of concepts for modeling and accessing your application’s data as interrelated objects and collections. The WordPress REST API 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. JSON is an open standard data format that is lightweight and human-readable, and looks like Objects do in JavaScript. When you request content from or send content to the API, the response will also be returned in JSON. Because JSON is widely supported in many programming languages, developers can build WordPress applications in client-side JavaScript (like the block editor), as mobile apps, or as desktop or command line tools.

The REST API is just one of many APIs provided by WordPress. You can find the documentation on these additional APIs here.

Using the WordPress REST API

WordPress already provides a rich set of tools and interfaces for building sites, and you should not feel pressured to use the REST API if your site is already working the way you expect. You do not need to use the REST API to build a WordPress theme or plugin.

However, if you do wish to write your theme, plugin, or external application as a client-side JavaScript application, or a standalone program in a language other than PHP, then your application will need a structured way to access content within your WordPress site. Any programming language which can make HTTP requests and interpret JSON can use the REST API to interact with WordPress, from PHP, Node.js, Go, and Java, to Swift, Kotlin, and beyond.

Even if you’re using vanilla JavaScript or jQuery within a theme or plugin the REST API provides a more predictable and structured way to interact with your site’s content than admin-ajax, enabling you to spend less time accessing the data you need and more time creating better user experiences.

If you want a structured, extensible, and simple way to get data in and out of WordPress, you probably want to use the REST API.

For all of its simplicity the REST API can feel quite complex at first, so in this handbook we will attempt to break it down into smaller components to explain each part of the full puzzle.

Next Steps

Familiarize yourself with the key technical concepts behind how the REST API functions.

Learn more about how to interact with API resources and query for specific data in the Using the REST API section.

Once you’re comfortable with the default workings of the default routes and methods, discover how to add new data to the API or enhance and manipulate existing response objects in the Extending the REST API section.

For a comprehensive overview of the resources and routes available by default, review the API reference.

Requests

Overview

While the WordPress REST API may be called internally within other WordPress code via PHP, the REST API is designed to be used remotely over HTTP. HTTP is the foundation for communication of data over the internet, and any application capable of HTTP requests may make use of the WordPress REST API, whether that application is a client-side JavaScript interface or an application on a remote server running in Python or Java.

The data structure of a request is conveniently handled by the WP_REST_Request class.

WP_REST_Request

This class is one of the three main infrastructure classes introduced in WordPress 4.4. When an HTTP request is made to an endpoint of the API, the API will automatically create an instance of the WP_REST_Request class, matching the provided data. The response object is auto-generated in WP_REST_Server‘s serve_request() method. Once the request is created and authentication is checked, the request is dispatched and our endpoint callbacks begin to be fired. All of the data stored up in the WP_REST_Request object is passed into our callbacks for our registered endpoints. So both our permission_callback and callback are called with the request object being passed in. This enables us to access the various request properties in our callbacks, so that we can tailor our responses to match the desired output.

Request Properties

Request objects have many different properties, each of which can be used in various ways. The main properties are the request method, route, headers, parameters and attributes. Let’s break each of these down into their role in a request. If you were to create a request object yourself it would look like this:

$request = new WP_REST_Request( 'GET', '/my-namespace/v1/examples' );

In the above code sample we are only specifying that the request object method is GET and we should be matching the route /my-namespace/v1/examples which in the context of an entire URL would look like this: https://ourawesomesite.com/wp-json/my-namespace/v1/examples`. The method and route arguments for theWP_REST_Request` constructor are used to map the request to the desired endpoint. If the request is made to an endpoint that is not registered then a helpful 404 error message is returned in the response. Let’s look at the various properties in more depth.

Method

The method property of a request object by default matches the HTTP Request method. The method in most cases will be one of GET, POST, PUT, DELETE, OPTIONS, or HEAD. These methods will be used to match the various endpoints registered to a route. When the API finds a match for the method and route it will fire the callbacks for that endpoint.

The following convention is a best practice for matching HTTP methods: GET for read only tasks, POST for creation, PUT for updating, and DELETE for deleting. The request method acts as an indicator for the expected functionality of your endpoints. When you make a GET request to a route, you should expect to be returned read only data.

Route

The route for a request, by default, will match the server environment variable for path info; $_SERVER['PATH_INFO']. When you make an HTTP request to a route of the WordPress REST API, the generated WP_REST_Request object will be made to match that path, which will hopefully then be matched to a valid endpoint. In short the route for a request is where you want to target your request in the API.

If we had registered a books endpoint, using GET, it might live at `https://ourawesomesite.com/wp-json/my-namespace/v1/books`. If we went to that URL in our browser, we would see our collection of books represented in JSON. WordPress will automatically generate the request object for us and handle all of the routing to match endpoints. So since we don’t really have to worry about the routing ourselves understanding how to pass extra data we want in our requests is a much more important thing to understand.

Headers

HTTP Request headers are simply just extra data about our HTTP request. Request headers can specify caching policy, what our request content is, where the request is coming from and many other things. Request headers do not necessarily interact with our endpoints directly, but the information in the headers helps WordPress know what to do. To pass in data that we want our endpoints to interact with we want to use parameters.

Parameters

When making requests to the WordPress REST API, most of the additional data passed in will take on the form of parameters. What are parameters? There are four different types in the context of the API. There are route parameters, query parameters, body parameters, and file parameters. Let’s take a look at each one a bit more in depth.

URL Params

URL parameters are automatically generated in a WP_REST_Request from the path variables in the requested route. What does that mean? Let’s look at this route, which grabs individual books by id: /my-namespace/v1/books/(?P<id>\d+). The odd looking (?P<id>\d+) is a path variable. The name of the path variable is ‘id‘.

If we were to make a request like GET https://ourawesomesite.com/wp-json/my-namespace/v1/books/5`,5will become the value for ouridpath variable. TheWP_REST_Request` object will automatically take that path variable and store it as a URL parameter. Now inside of our endpoint callbacks we can interact with that URL parameter really easily. Let’s look at an example.

// Register our individual books endpoint.
function prefix_register_book_route() {
    register_rest_route( 'my-namespace/v1', '/books/(?P<id>\d+)', array(
        // Supported methods for this endpoint. WP_REST_Server::READABLE translates to GET.
        'methods' => WP_REST_Server::READABLE,
        // Register the callback for the endpoint.
        'callback' => 'prefix_get_book',
    ) );
}

add_action( 'rest_api_init', 'prefix_register_book_route' );

/**
 * Our registered endpoint callback. Notice how we are passing in $request as an argument.
 * By default, the WP_REST_Server will pass in the matched request object to our callback.
 *
 * @param WP_REST_Request $request The current matched request object.
 */
function prefix_get_book( $request ) {
    // Here we are accessing the path variable 'id' from the $request.
    $book = prefix_get_the_book( $request['id'] );
    return rest_ensure_response( $book );
}

// A simple function that grabs a book title from our books by ID.
function prefix_get_the_book( $id ) {
    $books = array(
        'Design Patterns',
        'Clean Code',
        'Refactoring',
        'Structure and Interpretation of Computer Programs',
    );

    $book = '';
    if ( isset( $books[ $id ] ) ) {
        // Grab the matching book.
        $book = $books[ $id ];
    } else {
        // Error handling.
        return new WP_Error( 'rest_not_found', esc_html__( 'The book does not exist', 'my-text-domain' ), array( 'status' => 404 ) );
    }

    return $book;
}

In the example above we see how path variables are stored as URL parameters in the request object. We can then access those parameters in our endpoint callbacks. The above example is a pretty common use case for using URL params. Adding too many path variables to a route can slow down the matching of routes and it can also over complicate registering endpoints, it is advised to use URL parameters sparingly. If we aren’t supposed to use parameters directly in our URL path, then we need another way to pass in extra information to our request. This is where query and body parameters come in, they will typically do most of the heavy lifting in your API.

Query Params

Query parameters exist in the query string portion of a URI. The query string portion of a URI in https://ourawesomesite.com/wp-json/my-namespace/v1/books?per_page=2&genre=fiction` is?per_page=2&genre=fiction. The query string is started by the '?' character, the different values within the query string are separated by the '&' character. We specified two parameters in our query string;per_pageandgenre. In our endpoint we would want to grab only two books from the fiction genre. We could access those values in a callback like this:$request[‘per_page’], and$request[‘genre’]` ( assuming $request is the name of the argument we are using ). If you are familiar with PHP you have probably used query parameters in your web applications.

In PHP, the query parameters get stored in the superglobal $_GET. It is important to note that you should never directly access any superglobals or server variables in your endpoints. It is always best to work with what is provided by the WP_REST_Request class. Another common method for passing in variables to an endpoint is to use body parameters.

Body Params

Body parameters are key value pairs that are stored in the request body. If you have ever sent a POST request via a <form>, through cURL, or some other method, then you have used body parameters. With body parameters you can pass them as different content types as well. The default Content-Type header for a POST request is x-www-form-urlencoded. When using x-www-form-urlencoded, the parameters are sent like a query string; per_page=2&amp;genre=fiction. An HTML form, by default, will bundle up the various inputs and send a POST request matching the x-www-form-urlencoded pattern.

It is important to note that although the HTTP specification does not prohibit the use of sending body parameters in GET requests, it is encouraged that you do not use body parameters in a GET request. Body parameters can and should be used for POST, PUT, and DELETE requests.

File Params

File parameters in a WP_REST_Request object are stored when the request uses a special content type header; multipart/form-data. The file data can then be accessed from the request object using $request->get_file_params(). The file parameters are equivalent to the PHP superglobal: $_FILES. Remember, do not access the superglobals directly only use what the WP_REST_Request object provides.

In the endpoint callback we could use wp_handle_upload() to then add in the desired files to WordPress’s media uploads directory. The file parameters are only useful for dealing with file data and you should never use them for any other purpose.

Attributes

WP_REST_Request also supports request attributes. The attributes of a request are the attributes registered to the match route. If we made a GET request to my-namespace/v1/books, and then we called $request->get_attributes() inside of our endpoint callback, we would be returned all of the registration options for the my-namespace/v1/books endpoint. If we made a POST request to the same route and our endpoint callback also returned $request->get_attributes(), we would receive a different set of endpoint options registered to the POST endpoint callback.

In the attributes we will get a response containing supported methods, options, whether to show this endpoint in the index, a list of registered arguments for the endpoint, and our registered callbacks. It might look something like this:

{
  "methods": {
    "GET": true
  },
  "accept_json": false,
  "accept_raw": false,
  "show_in_index": true,
  "args": {
    "context": {
      "description": "Scope under which the request is made; determines fields present in response.",
      "type": "string",
      "sanitize_callback": "sanitize_key",
      "validate_callback": "rest_validate_request_arg",
      "enum": [
        "view",
        "embed",
        "edit"
      ],
      "default": "view"
    },
    "page": {
      "description": "Current page of the collection.",
      "type": "integer",
      "default": 1,
      "sanitize_callback": "absint",
      "validate_callback": "rest_validate_request_arg",
      "minimum": 1
    },
    "per_page": {
      "description": "Maximum number of items to be returned in result set.",
      "type": "integer",
      "default": 10,
      "minimum": 1,
      "maximum": 100,
      "sanitize_callback": "absint",
      "validate_callback": "rest_validate_request_arg"
    },
    "search": {
      "description": "Limit results to those matching a string.",
      "type": "string",
      "sanitize_callback": "sanitize_text_field",
      "validate_callback": "rest_validate_request_arg"
    },
    "after": {
      "description": "Limit response to resources published after a given ISO8601 compliant date.",
      "type": "string",
      "format": "date-time",
      "validate_callback": "rest_validate_request_arg"
    },
    "author": {
      "description": "Limit result set to posts assigned to specific authors.",
      "type": "array",
      "default": [],
      "sanitize_callback": "wp_parse_id_list",
      "validate_callback": "rest_validate_request_arg"
    },
    "author_exclude": {
      "description": "Ensure result set excludes posts assigned to specific authors.",
      "type": "array",
      "default": [],
      "sanitize_callback": "wp_parse_id_list",
      "validate_callback": "rest_validate_request_arg"
    },
    "before": {
      "description": "Limit response to resources published before a given ISO8601 compliant date.",
      "type": "string",
      "format": "date-time",
      "validate_callback": "rest_validate_request_arg"
    },
    "exclude": {
      "description": "Ensure result set excludes specific ids.",
      "type": "array",
      "default": [],
      "sanitize_callback": "wp_parse_id_list"
    },
    "include": {
      "description": "Limit result set to specific ids.",
      "type": "array",
      "default": [],
      "sanitize_callback": "wp_parse_id_list"
    },
    "offset": {
      "description": "Offset the result set by a specific number of items.",
      "type": "integer",
      "sanitize_callback": "absint",
      "validate_callback": "rest_validate_request_arg"
    },
    "order": {
      "description": "Order sort attribute ascending or descending.",
      "type": "string",
      "default": "desc",
      "enum": [
        "asc",
        "desc"
      ],
      "validate_callback": "rest_validate_request_arg"
    },
    "orderby": {
      "description": "Sort collection by object attribute.",
      "type": "string",
      "default": "date",
      "enum": [
        "date",
        "relevance",
        "id",
        "include",
        "title",
        "slug"
      ],
      "validate_callback": "rest_validate_request_arg"
    },
    "slug": {
      "description": "Limit result set to posts with a specific slug.",
      "type": "string",
      "validate_callback": "rest_validate_request_arg"
    },
    "status": {
      "default": "publish",
      "description": "Limit result set to posts assigned a specific status; can be comma-delimited list of status types.",
      "enum": [
        "publish",
        "future",
        "draft",
        "pending",
        "private",
        "trash",
        "auto-draft",
        "inherit",
        "any"
      ],
      "sanitize_callback": "sanitize_key",
      "type": "string",
      "validate_callback": [
        {},
        "validate_user_can_query_private_statuses"
      ]
    },
    "filter": {
      "description": "Use WP Query arguments to modify the response; private query vars require appropriate authorization."
    },
    "categories": {
      "description": "Limit result set to all items that have the specified term assigned in the categories taxonomy.",
      "type": "array",
      "sanitize_callback": "wp_parse_id_list",
      "default": []
    },
    "tags": {
      "description": "Limit result set to all items that have the specified term assigned in the tags taxonomy.",
      "type": "array",
      "sanitize_callback": "wp_parse_id_list",
      "default": []
    }
  },
  "callback": [
    {},
    "get_items"
  ],
  "permission_callback": [
    {},
    "get_items_permissions_check"
  ]
}

As you can see we have all of the information we have registered to our endpoint already there, ready to go! The request attributes are typically used at a lower level and are handled by the WP_REST_Server class, however there are cool things that can be done inside of endpoint callbacks, like restricting accepted parameters to match registered arguments.

The WP REST API is designed for you so that you do not have to mess around with any internals, so some of these more advanced methods of interacting with WP_REST_Request are not going to be commonly practiced. The core of using the WP REST API is linked to registering routes and endpoints. Requests are the tool we use to tell the API which endpoint we want to hit. This is most commonly done over HTTP, however we can also use WP_REST_Requests internally.

Internal Requests

The key to making internal requests is using rest_do_request(). All you need to do is pass in a request object and you will be returned a response. Because the request is never served by the WP_REST_Server, the response data is never encoded into json, meaning we have our response object as a PHP object. This is pretty awesome and enables us to do a lot of interesting things. For one, we can create efficient batch endpoints. From a performance perspective, one of the hurdles is minimizing HTTP requests. We can create batch endpoints that will use rest_do_request() to serve all of our requests internally all in one HTTP request. Here is a very simplistic batch endpoint for read only data, so you can see rest_do_request() in action.

// Register our mock batch endpoint.
function prefix_register_batch_route() {
    register_rest_route( 'my-namespace/v1', '/batch', array(
        // Supported methods for this endpoint. WP_REST_Server::READABLE translates to GET.
        'methods' => WP_REST_Server::READABLE,
        // Register the callback for the endpoint.
        'callback' => 'prefix_do_batch_request',
        // Register args for the batch endpoint.
        'args' => prefix_batch_request_parameters(),
    ) );
}

add_action( 'rest_api_init', 'prefix_register_batch_route' );

/**
 * Our registered endpoint callback. Notice how we are passing in $request as an argument.
 * By default, the WP_REST_Server will pass in the matched request object to our callback.
 *
 * @param WP_REST_Request $request The current matched request object.
 */
function prefix_do_batch_request( $request ) {
    // Here we initialize the array that will hold our response data.
    $data = array();
    $data = prefix_handle_batch_requests( $request['requests'] );
    return $data;
}

/**
 * This handles the building of the response for the batch requests we make.
 *
 * @param array $requests An array of data to build WP_REST_Request objects from.
 * @return WP_REST_Response A collection of response data for batch endpoints.
 */
function prefix_handle_batch_requests( $requests ) {
    $data = array();

    // Foreach request specified in the requests param run the endpoint.
    foreach ( $requests as $request_params ) {
        $response = prefix_handle_request( $request_params );
        $key = $request_params['method'] . ' ' . $request_params['route'];
        $data[ $key ] = prefix_prepare_for_collection( $response );
    }

    return rest_ensure_response( $data );
}

/**
 * This handles the building of the response for the batch requests we make.
 *
 * @param array $request_params Data to build a WP_REST_Request object from.
 * @return WP_REST_Response Response data for the request.
 */
function prefix_handle_request( $request_params ) {
    $request = new WP_REST_Request( $request_params['method'], $request_params['route'] );

    // Add specified request parameters into the request.
    if ( isset( $request_params['params'] ) ) {
        foreach ( $request_params['params'] as $param_name => $param_value ) {
            $request->set_param( $param_name, $param_value );
        }
    }
    $response = rest_do_request( $request );
    return $response;
}

/**
 * Prepare a response for inserting into a collection of responses.
 *
 * This is lifted from WP_REST_Controller class in the WP REST API v2 plugin.
 *
 * @param WP_REST_Response $response Response object.
 * @return array Response data, ready for insertion into collection data.
 */
function prefix_prepare_for_collection( $response ) {
    if ( ! ( $response instanceof WP_REST_Response ) ) {
        return $response;
    }

    $data = (array) $response->get_data();
    $server = rest_get_server();

    if ( method_exists( $server, 'get_compact_response_links' ) ) {
        $links = call_user_func( array( $server, 'get_compact_response_links' ), $response );
    } else {
        $links = call_user_func( array( $server, 'get_response_links' ), $response );
    }

    if ( ! empty( $links ) ) {
        $data['_links'] = $links;
    }

    return $data;
}

/**
 * Returns the JSON schema data for our registered parameters.
 *
 * @return array $params A PHP representation of JSON Schema data.
 */
function prefix_batch_request_parameters() {
    $params = array();

    $params['requests'] = array(
        'description'        => esc_html__( 'An array of request objects arguments that can be built into WP_REST_Request instances.', 'my-text-domain' ),
        'type'               => 'array',
        'required'           => true,
        'validate_callback'  => 'prefix_validate_requests',
        'items'              => array(
            array(
                'type' => 'object',
                'properties' => array(
                    'method' => array(
                        'description' => esc_html__( 'HTTP Method of the desired request.', 'my-text-domain' ),
                        'type'        => 'string',
                        'required'    => true,
                        'enum'        => array(
                            'GET',
                            'POST',
                            'PUT',
                            'DELETE',
                            'OPTIONS',
                        ),
                    ),
                    'route' => array(
                        'description' => esc_html__( 'Desired route for the request.', 'my-text-domain' ),
                        'required'    => true,
                        'type'        => 'string',
                        'format'      => 'uri',
                    ),
                    'params' => array(
                        'description' => esc_html__( 'Key value pairs of desired request parameters.', 'my-text-domain' ),
                        'type' => 'object',
                    ),
                ),
            ),
        ),
    );

    return $params;
}

function prefix_validate_requests( $requests, $request, $param_key ) {
    // If requests isn't an array of requests then we don't process the batch.
    if ( ! is_array( $requests ) ) {
        return new WP_Error( 'rest_invald_param', esc_html__( 'The requests parameter must be an array of requests.' ), array( 'status' => 400 ) );
    }

    foreach ( $requests as $request ) {
        // If the method or route is not set then we do not run the requests.
        if ( ! isset( $request['method'] ) || ! isset( $request['route'] ) ) {
            return new WP_Error( 'rest_invald_param', esc_html__( 'You must specify the method and route for each request.' ), array( 'status' => 400 ) );
        }

        if ( isset( $request['params'] ) && ! is_array( $request['params'] ) ) {
            return new WP_Error( 'rest_invald_param', esc_html__( 'You must specify the params for each request as an array of named key value pairs.' ), array( 'status' => 400 ) );
        }
    }

    // This is a black listing approach to data validation.
    return true;
}

That is quite a decent chunk of code that covers a number of topics, but everything centers around what happens in prefix_handle_request(). Here we are passing in an array that tells us a HTTP method, a route, and a set of parameters we want to turn into a request. We then build the request object for the method and route. If any parameters were specified we use the WP_REST_Request::set_param() method to add in the desired parameters. Once our WP_REST_Request is ready to go we use rest_do_request to internally match that endpoint and the response is returned to our batch endpoint response collection. Using a batch endpoint like this can net you huge performance gains, as you will only make one HTTP request to get a response for multiple endpoints. The implementation of this is not necessarily the best and serves as an example; not the only way to do this.

Reference

The WordPress REST API is organized around REST, and is designed to have predictable, resource-oriented URLs and to use HTTP response codes to indicate API errors. The API uses built-in HTTP features, like HTTP authentication and HTTP verbs, which can be understood by off-the-shelf HTTP clients, and supports cross-origin resource sharing to allow you to interact securely with the API from a client-side web application.

The REST API uses JSON exclusively as the request and response format, including error responses. While the REST API does not completely conform to the HAL standard, it does implement HAL’s ._links and ._embedded properties for linking API resources, and is fully discoverable via hyperlinks in the responses.

The REST API provides public data accessible to any client anonymously, as well as private data only available after authentication. Once authenticated the REST API supports most content management actions, allowing you to build alternative dashboards for a site, enhance your plugins with more responsive management tools, or build complex single-page applications.

This API reference provides information on the specific endpoints available through the API, their parameters, and their response data format.

REST API Developer Endpoint Reference

Resource Base Route
Posts /wp/v2/posts
Post Revisions /wp/v2/posts/<id>/revisions
Categories /wp/v2/categories
Tags /wp/v2/tags
Pages /wp/v2/pages
Page Revisions /wp/v2/pages/<id>/revisions
Comments /wp/v2/comments
Taxonomies /wp/v2/taxonomies
Media /wp/v2/media
Users /wp/v2/users
Post Types /wp/v2/types
Post Statuses /wp/v2/statuses
Settings /wp/v2/settings
Themes /wp/v2/themes
Search /wp/v2/search
Block Types /wp/v2/block-types
Blocks /wp/v2/blocks
Block Revisions /wp/v2/blocks/<id>/autosaves/
Block Renderer /wp/v2/block-renderer
Block Directory Items /wp/v2/block-directory/search
Plugins /wp/v2/plugins

A Distributed API

Unlike many other REST APIs, the WordPress REST API is distributed and available individually on each site that supports it. This means there is no singular API root or base to contact; instead, we have a discovery process that allows interacting with sites without prior contact. The API also exposes self-documentation at the index endpoint, or via an OPTIONS request to any endpoint, allowing human- or machine-discovery of endpoint capabilities.

Glossary

New to REST APIs? Get up to speed with phrases used throughout our documentation.

Controller

Model-View-Controller is a standard pattern in software development. If you aren’t already familiar with it, you should do a bit of reading to get up to speed.

Within WP-API, we’ve adopted the controller concept to have a standard pattern for the classes representing our resource endpoints. All resource endpoints extend WP_REST_Controller to ensure they implement common methods.

HEAD, GET, POST, PUT, and DELETE Requests

These “HTTP verbs” represent the type of action a HTTP client might perform against a resource. For instance, GET requests are used to fetch a Post’s data, whereas DELETE requests are used to delete a Post. They’re collectively called “HTTP verbs” because they’re standardized across the web.

If you’re familiar with WordPress functions, a GET request is the equivalent of wp_remote_get(), and a POST request is the same as wp_remote_post().

HTTP Client

The phrase “HTTP Client” refers to the tool you use to interact with WP-API. You might use Postman (Chrome) or REST Easy (Firefox) to test requests in your browser, or httpie to test requests at the commandline.

WordPress itself provides a HTTP Client in the WP_HTTP class and related functions (e.g. wp_remote_get()). This can be used to access one WordPress site from another.

Resource

A “Resource” is a discrete entity within WordPress. You may know these resources already as Posts, Pages, Comments, Users, Terms, and so on. WP-API permits HTTP clients to perform CRUD operations against resources (CRUD stands for Create, Read, Update, and Delete).

Pragmatically, here’s how you’d typically interact with WP-API resources:

Routes / Endpoints

Endpoints are functions available through the API. This can be things like retrieving the API index, updating a post, or deleting a comment. Endpoints perform a specific function, taking some number of parameters and return data to the client.

A route is the “name” you use to access endpoints, used in the URL. A route can have multiple endpoints associated with it, and which is used depends on the HTTP verb.

For example, with the URL `http://example.com/wp-json/wp/v2/posts/123`:

Note: On sites without pretty permalinks, the route is instead added to the URL as the rest_route parameter. For the above example, the full URL would then be `http://example.com/?rest_route=wp/v2/posts/123`

Schema

A “schema” is a representation of the format for WP-API’s response data. For instance, the Post schema communicates that a request to get a Post will return id, title, content, author, and other fields. Our schemas also indicate the type each field is, provide a human-readable description, and show which contexts the field will be returned in.

Using the REST API

These articles explore the basic structure of the WordPress REST API.

Global Parameters: learn about the global REST API query parameters that apply to every endpoint

Pagination: work with large collections of resources & control how many records you receive from the REST API

Linking & Embedding: understand how to read and modify connections between different objects, and embed related resources such as author and media data in the REST API’s responses

Discovery: determine what REST API resources a site supports, and where they are located

Authentication: authorize your REST API requests so that you can create, update and delete your data

Frequently Asked Questions: see some of the most frequent inquiries about the REST API and learn how to solve common problems

Resources & Utilities

Backbone.js Client: interact with the API from within WP-Admin using Backbone models & collections

Client Libraries: utilities in a variety of programming languages that simplify interacting with the API

Extending the REST API

Guides

Modifying responses: add fields to REST API response objects using register_meta or register_rest_field Adding Endpoints: create custom REST API endpoints for your plugin or application Working with Custom Content Types: learn how to interact with your custom post types and custom taxonomies through the REST API

Resources

Defining your API Schema: define the schema for your REST API resources and their arguments Glossary: get up to speed with phrases used throughout our documentation Routes & Endpoints: dive deeper into the nuances of REST API routes and the endpoints they provide Controller Classes: discover how to structure and extend REST API endpoint controller classes Frequently Asked Questions: see some of the most frequent inquiries about the REST API and learn how to solve common problems

Frequently Asked Questions

This page provides solutions to some common questions and problems that may arise while using the API. If your question is not explained here it may have been answered in the WordPress support forums.

Can I disable the REST API?

You should not disable the REST API; doing so will break WordPress Admin functionality that depends on the API being active. However, you may use a filter to require that API consumers be authenticated, which effectively prevents anonymous external access. See below for more information.

Require Authentication for All Requests

You can require authentication for all REST API requests by adding an is_user_logged_in check to the rest_authentication_errors filter. Note: The incoming callback parameter can be either null, a WP_Error, or a boolean. The type of the parameter indicates the state of authentication:

add_filter( 'rest_authentication_errors', function( $result ) {
    // If a previous authentication check was applied,
    // pass that result along without modification.
    if ( true === $result || is_wp_error( $result ) ) {
        return $result;
    }

    // No authentication has been performed yet.
    // Return an error if user is not logged in.
    if ( ! is_user_logged_in() ) {
        return new WP_Error(
            'rest_not_logged_in',
            __( 'You are not currently logged in.' ),
            array( 'status' => 401 )
        );
    }

    // Our custom authentication check should have no effect
    // on logged-in requests
    return $result;
});

Can I make API requests from PHP within a plugin?

Yes, you can! Use rest_do_request to make API requests internally within other WordPress code:

$request = new WP_REST_Request( 'GET', '/wp/v2/posts' );
// Set one or more request query parameters
$request->set_param( 'per_page', 20 );
$response = rest_do_request( $request );

How do I use the _embed parameter on internal requests?

Setting the _embed param on the request object won’t work.

$request = new WP_REST_Request( 'GET', '/wp/v2/posts' );
$request->set_param( '_embed', 1 );
$response = rest_do_request( $request );

Instead, manually call the WP_REST_Server::response_to_data function.

$request = new WP_REST_Request( 'GET', '/wp/v2/posts' );
$response = rest_do_request( $request );
$data = rest_get_server()->response_to_data( $response, true );
var_dump( $data['_embedded'] );

What happened to the ?filter= query parameter?

When the REST API was merged into WordPress core the ?filter query parameter was removed to prevent future compatibility and maintenance issues. The ability to pass arbitrary WP_Query arguments to the API using a ?filter query parameter was necessary at the genesis of the REST API project, but most API response filtering functionality has been superseded by more robust query parameters like ?categories=, ?slug= and ?per_page=. First-party query parameters should be used whenever possible. However, the rest-filter plugin restores the ability to pass arbitrary ?filter values in API request if needed.

Query parameters are not working

If you find that query parameters such as ?page=2 or ?_embed are not having any effect, your server may not be properly configured to detect them. If you are using Nginx to serve your website, look for a try_files line in your site configuration. If it looks like this:

try_files $uri $uri/ /index.php$args;

change it to this:

try_files $uri $uri/ /index.php$is_args$args;

Adding $is_args (which will print a ? character if query arguments are found) will allow WordPress to properly receive and interpret the query parameters.

Why is Authentication not working?

If you’re finding that you are sending Authentication headers but the request is not being accepted, and you are using a CGI environment, your webserver may be stripping the headers. Please try adding the appropriate configuration below to remedy this.

Apache

Add the following to a configuration file or .htaccess:

<IfModule mod_setenvif>
  SetEnvIf Authorization "(.*)" HTTP_AUTHORIZATION=$1
</IfModule>

Nginx

Add the following to your server configurations fastcgi section:

fastcgi_pass_header Authorization;

Why is the REST API not verifying the incoming Origin header? Does this expose my site to CSRF attacks?

Cross-Origin Resource Sharing (CORS) is a mechanism which allows a website to control which Origins (originating external sites) are allowed to access your site’s data. CORS prevents against a particular type of attack known as Cross-Site Request Forgery, or CSRF. However, WordPress has an existing CSRF protection mechanism which uses nonces. Tightening CORS restrictions would prevent some authentication methods, so the WordPress REST API uses nonces for CSRF protection instead of CORS. Because the WordPress REST API does not verify the Origin header of incoming requests, public REST API endpoints may therefore be accessed from any site. This is an intentional design decision, but if you wish to prevent your site from being accessed from unknown origins you may unhook the default rest_send_cors_headers function from the rest_pre_serve_request filter hook, then hook in your own function to that same filter to specify stricter CORS headers.

Changelog

This document details changes to the WP REST API since its public release in version 4.7.0.

Version 5.6

Version 5.5

Version 5.4

Version 5.3

Version 5.2

Version 5.1

Version 5.0

Version 4.9.8

Version 4.8.1

Version 4.8.0

Version 4.7.4

Version 4.7.3

Version 4.7.2

Version 4.7.1

Rendered Blocks

Schema

The schema defines all the fields that exist within a Rendered Block record. Any response from these endpoints can be expected to contain the fields below unless the `_filter` query parameter is used or the schema field only appears in a specific context.

rendered The rendered block.

JSON data type: string

Context: edit

Create a Rendered Block

Arguments

name Unique registered name for the block.
context Scope under which the request is made; determines fields present in response.

Default: view

One of: edit

attributes Attributes for the block.
post_id ID of the post context.

Definition

POST /wp/v2/block-renderer/<name>

Search Results

Schema

The schema defines all the fields that exist within a search result record. Any response from these endpoints can be expected to contain the fields below unless the `_filter` query parameter is used or the schema field only appears in a specific context.

id Unique identifier for the object.

JSON data type: integer or string

Read only

Context: view, embed

title The title for the object.

JSON data type: string

Read only

Context: view, embed

url URL to the object.

JSON data type: string,
Format: uri

Read only

Context: view, embed

type Object type.

JSON data type: string

Read only

Context: view, embed

One of: post, term, post-format

subtype Object subtype.

JSON data type: string

Read only

Context: view, embed

One of: post, page, category, post_tag

List Search Results

Query this endpoint to retrieve a collection of search results. The response you receive can be controlled and filtered using the URL query parameters below.

Definition

GET /wp/v2/search

Example Request

$ curl https://example.com/wp-json/wp/v2/search

Arguments

context Scope under which the request is made; determines fields present in response.

Default: view

One of: view, embed

page Current page of the collection.

Default: 1

per_page Maximum number of items to be returned in result set.

Default: 10

search Limit results to those matching a string.
type Limit results to items of an object type.

Default: post

One of: post, term, post-format

subtype Limit results to items of one or more object subtypes.

Default: any

exclude Ensure result set excludes specific IDs.
include Limit result set to specific IDs.

Themes

Schema

The schema defines all the fields that exist within a theme record. Any response from these endpoints can be expected to contain the fields below unless the `_filter` query parameter is used or the schema field only appears in a specific context.

stylesheet The theme’s stylesheet. This uniquely identifies the theme.

JSON data type: string

Read only

Context:

template The theme’s template. If this is a child theme, this refers to the parent theme, otherwise this is the same as the theme’s stylesheet.

JSON data type: string

Read only

Context:

author The theme author.

JSON data type: object

Read only

Context:

author_uri The website of the theme author.

JSON data type: object

Read only

Context:

description A description of the theme.

JSON data type: object

Read only

Context:

is_block_theme Whether the theme is a block-based theme.

JSON data type: boolean

Read only

Context:

name The name of the theme.

JSON data type: object

Read only

Context:

requires_php The minimum PHP version required for the theme to work.

JSON data type: string

Read only

Context:

requires_wp The minimum WordPress version required for the theme to work.

JSON data type: string

Read only

Context:

screenshot The theme’s screenshot URL.

JSON data type: string,
Format: uri

Read only

Context:

tags Tags indicating styles and features of the theme.

JSON data type: object

Read only

Context:

textdomain The theme’s text domain.

JSON data type: string

Read only

Context:

theme_supports Features supported by this theme.

JSON data type: object

Read only

Context:

theme_uri The URI of the theme’s webpage.

JSON data type: object

Read only

Context:

version The theme’s current version.

JSON data type: string

Read only

Context:

status A named status for the theme.

JSON data type: string

Context:

One of: inactive, active

Retrieve a Theme

Definition & Example Request

GET /wp/v2/themes

Query this endpoint to retrieve a specific theme record.

$ curl https://example.com/wp-json/wp/v2/themes

Arguments

status Limit result set to themes assigned one or more statuses.

Retrieve a Theme

Definition & Example Request

GET /wp/v2/themes/<stylesheet>?)

Query this endpoint to retrieve a specific theme record.

$ curl https://example.com/wp-json/wp/v2/themes/<stylesheet>?)

Arguments

stylesheet The theme’s stylesheet. This uniquely identifies the theme.

Block Revisions

Schema

The schema defines all the fields that exist within a Block Revision record. Any response from these endpoints can be expected to contain the fields below unless the `_filter` query parameter is used or the schema field only appears in a specific context.

author The ID for the author of the revision.

JSON data type: integer

Context: view, edit, embed

date The date the revision was published, in the site’s timezone.

JSON data type: string,
Format: datetime (details)

Context: view, edit, embed

date_gmt The date the revision was published, as GMT.

JSON data type: string,
Format: datetime (details)

Context: view, edit

guid The globally unique identifier for the post.

JSON data type: object

Read only

Context: view, edit

id Unique identifier for the revision.

JSON data type: integer

Context: view, edit, embed

modified The date the revision was last modified, in the site’s timezone.

JSON data type: string,
Format: datetime (details)

Context: view, edit

modified_gmt The date the revision was last modified, as GMT.

JSON data type: string,
Format: datetime (details)

Context: view, edit

parent The ID for the parent of the revision.

JSON data type: integer

Context: view, edit, embed

slug An alphanumeric identifier for the revision unique to its type.

JSON data type: string

Context: view, edit, embed

title The title for the post.

JSON data type: object

Context: view, edit, embed

content The content for the post.

JSON data type: object

Context: view, edit

List Block Revisions

Query this endpoint to retrieve a collection of Block Revisions. The response you receive can be controlled and filtered using the URL query parameters below.

Definition

GET /wp/v2/blocks/<parent>/revisions

Example Request

$ curl https://example.com/wp-json/wp/v2/blocks/<parent>/revisions

Arguments

parent The ID for the parent of the revision.
context Scope under which the request is made; determines fields present in response.

Default: view

One of: view, embed, edit

page Current page of the collection.

Default: 1

per_page Maximum number of items to be returned in result set.
search Limit results to those matching a string.
exclude Ensure result set excludes specific IDs.
include Limit result set to specific IDs.
offset Offset the result set by a specific number of items.
order Order sort attribute ascending or descending.

Default: desc

One of: asc, desc

orderby Sort collection by object attribute.

Default: date

One of: date, id, include, relevance, slug, include_slugs, title

Retrieve a Block Revision

Definition & Example Request

GET /wp/v2/blocks/<parent>/revisions/<id>

Query this endpoint to retrieve a specific Block Revision record.

$ curl https://example.com/wp-json/wp/v2/blocks/<parent>/revisions/<id>

Arguments

parent The ID for the parent of the revision.
id Unique identifier for the revision.
context Scope under which the request is made; determines fields present in response.

Default: view

One of: view, embed, edit

Delete a Block Revision

Arguments

parent The ID for the parent of the revision.
id Unique identifier for the revision.
force Required to be true, as revisions do not support trashing.

Definition

DELETE /wp/v2/blocks/<parent>/revisions/<id>

Example Request

$ curl -X DELETE https://example.com/wp-json/wp/v2/blocks/<parent>/revisions/<id>

Retrieve a Block Revision

Definition & Example Request

GET /wp/v2/blocks/<id>/autosaves

Query this endpoint to retrieve a specific Block Revision record.

$ curl https://example.com/wp-json/wp/v2/blocks/<id>/autosaves

Arguments

parent The ID for the parent of the autosave.
context Scope under which the request is made; determines fields present in response.

Default: view

One of: view, embed, edit

Create a Block Revision

Arguments

parent The ID for the parent of the autosave.
date The date the post was published, in the site’s timezone.
date_gmt The date the post was published, as GMT.
slug An alphanumeric identifier for the post unique to its type.
status A named status for the post.
One of: publish, future, draft, pending, private
password A password to protect access to the content and excerpt.
title The title for the post.
content The content for the post.
meta Meta fields.
template The theme file to use to display the post.

Definition

POST /wp/v2/blocks/<id>/autosaves

Retrieve a Block Revision

Definition & Example Request

GET /wp/v2/blocks/<parent>/autosaves/<id>

Query this endpoint to retrieve a specific Block Revision record.

$ curl https://example.com/wp-json/wp/v2/blocks/<parent>/autosaves/<id>

Arguments

parent The ID for the parent of the autosave.
id The ID for the autosave.
context Scope under which the request is made; determines fields present in response.

Default: view

One of: view, embed, edit

Editor Blocks

Schema

The schema defines all the fields that exist within a Editor Block record. Any response from these endpoints can be expected to contain the fields below unless the `_filter` query parameter is used or the schema field only appears in a specific context.

date The date the post was published, in the site’s timezone.

JSON data type: string or null, Format: datetime (details)

Context: view, edit, embed

date_gmt The date the post was published, as GMT.

JSON data type: string or null, Format: datetime (details)

Context: view, edit

guid The globally unique identifier for the post.

JSON data type: object

Read only

Context: view, edit

id Unique identifier for the post.

JSON data type: integer

Read only

Context: view, edit, embed

link URL to the post.

JSON data type: string, Format: uri

Read only

Context: view, edit, embed

modified The date the post was last modified, in the site’s timezone.

JSON data type: string, Format: datetime (details)

Read only

Context: view, edit

modified_gmt The date the post was last modified, as GMT.

JSON data type: string, Format: datetime (details)

Read only

Context: view, edit

slug An alphanumeric identifier for the post unique to its type.

JSON data type: string

Context: view, edit, embed

status A named status for the post.

JSON data type: string

Context: view, edit

One of: publish, future, draft, pending, private
type Type of post.

JSON data type: string

Read only

Context: view, edit, embed

password A password to protect access to the content and excerpt.

JSON data type: string

Context: edit

title The title for the post.

JSON data type: object

Context: view, edit, embed

content The content for the post.

JSON data type: object

Context: view, edit

meta Meta fields.

JSON data type: object

Context: view, edit

template The theme file to use to display the post.

JSON data type: string

Context: view, edit

List Editor Blocks

Query this endpoint to retrieve a collection of Editor Blocks. The response you receive can be controlled and filtered using the URL query parameters below.

Definition

GET /wp/v2/blocks

Example Request

$ curl https://example.com/wp-json/wp/v2/blocks

Arguments

context
Scope under which the request is made; determines fields present in response.

Default: view

One of: view, embed, edit
page
Current page of the collection.

Default: 1

per_page
Maximum number of items to be returned in result set.

Default: 10

search
Limit results to those matching a string.
after
Limit response to posts published after a given ISO8601 compliant date.
modified_after
Limit response to posts modified after a given ISO8601 compliant date.
before
Limit response to posts published before a given ISO8601 compliant date.
modified_before
Limit response to posts modified before a given ISO8601 compliant date.
exclude
Ensure result set excludes specific IDs.
include
Limit result set to specific IDs.
offset
Offset the result set by a specific number of items.
order
Order sort attribute ascending or descending.

Default: desc

One of: asc, desc
orderby
Sort collection by post attribute.

Default: date

One of: author, date, id, include, modified, parent, relevance, slug, include_slugs, title
search_columns
Array of column names to be searched.
slug
Limit result set to posts with one or more specific slugs.
status
Limit result set to posts assigned one or more statuses.

Default: publish

Create a Editor Block

Arguments

date
The date the post was published, in the site’s timezone.
date_gmt
The date the post was published, as GMT.
slug
An alphanumeric identifier for the post unique to its type.
status
A named status for the post. One of: publish, future, draft, pending, private
password
A password to protect access to the content and excerpt.
title
The title for the post.
content
The content for the post.
meta
Meta fields.
template
The theme file to use to display the post.

Definition

POST /wp/v2/blocks

Retrieve a Editor Block

Definition & Example Request

GET /wp/v2/blocks/<id> Query this endpoint to retrieve a specific Editor Block record. $ curl https://example.com/wp-json/wp/v2/blocks/<id>

Arguments

id
Unique identifier for the post.
context
Scope under which the request is made; determines fields present in response.

Default: view

One of: view, embed, edit
password
The password for the post if it is password protected.

Update a Editor Block

Arguments

id
Unique identifier for the post.
date
The date the post was published, in the site’s timezone.
date_gmt
The date the post was published, as GMT.
slug
An alphanumeric identifier for the post unique to its type.
status
A named status for the post. One of: publish, future, draft, pending, private
password
A password to protect access to the content and excerpt.
title
The title for the post.
content
The content for the post.
meta
Meta fields.
template
The theme file to use to display the post.

Definition

POST /wp/v2/blocks/<id>

Example Request

Delete a Editor Block

Arguments

id
Unique identifier for the post.
force
Whether to bypass Trash and force deletion.

Definition

DELETE /wp/v2/blocks/<id>

Example Request

$ curl -X DELETE https://example.com/wp-json/wp/v2/blocks/<id>

Block Directory Items

Schema

The schema defines all the fields that exist within a block directory item record. Any response from these endpoints can be expected to contain the fields below unless the `_filter` query parameter is used or the schema field only appears in a specific context.

name The block name, in namespace/block-name format.

JSON data type: string

Context: view

title The block title, in human readable format.

JSON data type: string

Context: view

description A short description of the block, in human readable format.

JSON data type: string

Context: view

id The block slug.

JSON data type: string

Context: view

rating The star rating of the block.

JSON data type: number

Context: view

rating_count The number of ratings.

JSON data type: integer

Context: view

active_installs The number sites that have activated this block.

JSON data type: integer

Context: view

author_block_rating The average rating of blocks published by the same author.

JSON data type: number

Context: view

author_block_count The number of blocks published by the same author.

JSON data type: integer

Context: view

author The WordPress.org username of the block author.

JSON data type: string

Context: view

icon The block icon.

JSON data type: string,
Format: uri

Context: view

last_updated The date when the block was last updated.

JSON data type: string,
Format: datetime (details)

Context: view

humanized_updated The date when the block was last updated, in fuzzy human readable format.

JSON data type: string

Context: view

List Block Directory Items

Query this endpoint to retrieve a collection of block directory items. The response you receive can be controlled and filtered using the URL query parameters below.

Definition

GET /wp/v2/block-directory/search

Example Request

$ curl https://example.com/wp-json/wp/v2/block-directory/search

Arguments

context Scope under which the request is made; determines fields present in response.

Default: view

One of: view

page Current page of the collection.

Default: 1

per_page Maximum number of items to be returned in result set.

Default: 10

term Limit result set to blocks matching the search term.

Required: 1

Block Types

Schema

The schema defines all the fields that exist within a block type record. Any response from these endpoints can be expected to contain the fields below unless the `_filter` query parameter is used or the schema field only appears in a specific context.

api_version Version of block API.

JSON data type: integer

Read only

Context: embed, view, edit

title Title of block type.

JSON data type: string

Read only

Context: embed, view, edit

name Unique name identifying the block type.

JSON data type: string

Read only

Context: embed, view, edit

description Description of block type.

JSON data type: string

Read only

Context: embed, view, edit

icon Icon of block type.

JSON data type: string or null

Read only

Context: embed, view, edit

attributes Block attributes.

JSON data type: object or null

Read only

Context: embed, view, edit

provides_context Context provided by blocks of this type.

JSON data type: object

Read only

Context: embed, view, edit

uses_context Context values inherited by blocks of this type.

JSON data type: array

Read only

Context: embed, view, edit

selectors Custom CSS selectors.

JSON data type: object

Read only

Context: embed, view, edit

supports Block supports.

JSON data type: object

Read only

Context: embed, view, edit

category Block category.

JSON data type: string or null

Read only

Context: embed, view, edit

is_dynamic Is the block dynamically rendered.

JSON data type: boolean

Read only

Context: embed, view, edit

editor_script_handles Editor script handles.

JSON data type: array

Read only

Context: embed, view, edit

script_handles Public facing and editor script handles.

JSON data type: array

Read only

Context: embed, view, edit

view_script_handles Public facing script handles.

JSON data type: array

Read only

Context: embed, view, edit

editor_style_handles Editor style handles.

JSON data type: array

Read only

Context: embed, view, edit

style_handles Public facing and editor style handles.

JSON data type: array

Read only

Context: embed, view, edit

styles Block style variations.

JSON data type: array

Read only

Context: embed, view, edit

variations Block variations.

JSON data type: array

Read only

Context: embed, view, edit

textdomain Public text domain.

JSON data type: string or null

Read only

Context: embed, view, edit

parent Parent blocks.

JSON data type: array or null

Read only

Context: embed, view, edit

ancestor Ancestor blocks.

JSON data type: array or null

Read only

Context: embed, view, edit

keywords Block keywords.

JSON data type: array

Read only

Context: embed, view, edit

example Block example.

JSON data type: object or null

Read only

Context: embed, view, edit

editor_script Editor script handle. DEPRECATED: Use `editor_script_handles` instead.

JSON data type: string or null

Read only

Context: embed, view, edit

script Public facing and editor script handle. DEPRECATED: Use `script_handles` instead.

JSON data type: string or null

Read only

Context: embed, view, edit

view_script Public facing script handle. DEPRECATED: Use `view_script_handles` instead.

JSON data type: string or null

Read only

Context: embed, view, edit

editor_style Editor style handle. DEPRECATED: Use `editor_style_handles` instead.

JSON data type: string or null

Read only

Context: embed, view, edit

style Public facing and editor style handle. DEPRECATED: Use `style_handles` instead.

JSON data type: string or null

Read only

Context: embed, view, edit

Retrieve a Block Type

Definition & Example Request

GET /wp/v2/block-types

Query this endpoint to retrieve a specific block type record.

$ curl https://example.com/wp-json/wp/v2/block-types

Arguments

context Scope under which the request is made; determines fields present in response.

Default: view

One of: view, embed, edit

namespace Block namespace.

Retrieve a Block Type

Definition & Example Request

GET /wp/v2/block-types/<namespace>

Query this endpoint to retrieve a specific block type record.

$ curl https://example.com/wp-json/wp/v2/block-types/<namespace>

Arguments

context Scope under which the request is made; determines fields present in response.

Default: view

One of: view, embed, edit

namespace Block namespace.

Retrieve a Block Type

Definition & Example Request

GET /wp/v2/block-types/<namespace>/<name>

Query this endpoint to retrieve a specific block type record.

$ curl https://example.com/wp-json/wp/v2/block-types/<namespace>/<name>

Arguments

name Block name.
namespace Block namespace.
context Scope under which the request is made; determines fields present in response.

Default: view

One of: view, embed, edit

Plugins

Schema

The schema defines all the fields that exist within a plugin record. Any response from these endpoints can be expected to contain the fields below unless the `_filter` query parameter is used or the schema field only appears in a specific context.

plugin The plugin file.

JSON data type: string

Read only

Context: view, edit, embed

status The plugin activation status.

JSON data type: string

Context: view, edit, embed

One of: inactive, active

name The plugin name.

JSON data type: string

Read only

Context: view, edit, embed

plugin_uri The plugin’s website address.

JSON data type: string,
Format: uri

Read only

Context: view, edit

author The plugin author.

JSON data type: object

Read only

Context: view, edit

author_uri Plugin author’s website address.

JSON data type: string,
Format: uri

Read only

Context: view, edit

description The plugin description.

JSON data type: object

Read only

Context: view, edit

version The plugin version number.

JSON data type: string

Read only

Context: view, edit

network_only Whether the plugin can only be activated network-wide.

JSON data type: boolean

Read only

Context: view, edit, embed

requires_wp Minimum required version of WordPress.

JSON data type: string

Read only

Context: view, edit, embed

requires_php Minimum required version of PHP.

JSON data type: string

Read only

Context: view, edit, embed

textdomain The plugin’s text domain.

JSON data type: string

Read only

Context: view, edit

Retrieve a Plugin

Definition & Example Request

GET /wp/v2/plugins

Query this endpoint to retrieve a specific plugin record.

$ curl https://example.com/wp-json/wp/v2/plugins

Arguments

context Scope under which the request is made; determines fields present in response.

Default: view

One of: view, embed, edit

search Limit results to those matching a string.
status Limits results to plugins with the given status.

Create a Plugin

Arguments

slug WordPress.org plugin directory slug.

Required: 1

status The plugin activation status.

Default: inactive

One of: inactive, active

Definition

POST /wp/v2/plugins

Retrieve a Plugin

Definition & Example Request

GET /wp/v2/plugins/<plugin>?)

Query this endpoint to retrieve a specific plugin record.

$ curl https://example.com/wp-json/wp/v2/plugins/<plugin>?)

Arguments

context Scope under which the request is made; determines fields present in response.

Default: view

One of: view, embed, edit

plugin

Update a Plugin

Arguments

context Scope under which the request is made; determines fields present in response.

Default: view

One of: view, embed, edit

plugin
status The plugin activation status.
One of: inactive, active

Definition

POST /wp/v2/plugins/<plugin>?)

Example Request

Delete a Plugin

Arguments

context Scope under which the request is made; determines fields present in response.

Default: view

One of: view, embed, edit

plugin

Definition

DELETE /wp/v2/plugins/<plugin>?)

Example Request

$ curl -X DELETE https://example.com/wp-json/wp/v2/plugins/<plugin>?)

Application Passwords

Schema

The schema defines all the fields that exist within a application password record. Any response from these endpoints can be expected to contain the fields below unless the `_filter` query parameter is used or the schema field only appears in a specific context.

uuid The unique identifier for the application password.

JSON data type: string,
Format: uuid

Read only

Context: view, edit, embed

app_id A UUID provided by the application to uniquely identify it. It is recommended to use an UUID v5 with the URL or DNS namespace.

JSON data type: string,
Format: uuid

Context: view, edit, embed

name The name of the application password.

JSON data type: string

Context: view, edit, embed

password The generated password. Only available after adding an application.

JSON data type: string

Read only

Context: edit

created The GMT date the application password was created.

JSON data type: string,
Format: datetime (details)

Read only

Context: view, edit

last_used The GMT date the application password was last used.

JSON data type: string or null,
Format: datetime (details)

Read only

Context: view, edit

last_ip The IP address the application password was last used by.

JSON data type: string or null,
Format: ip

Read only

Context: view, edit

Retrieve a Application Password

Definition & Example Request

GET /wp/v2/users/<user_id>)/application-passwords

Query this endpoint to retrieve a specific application password record.

$ curl https://example.com/wp-json/wp/v2/users/<user_id>)/application-passwords

Arguments

context Scope under which the request is made; determines fields present in response.

Default: view

One of: view, embed, edit

Create a Application Password

Arguments

app_id A UUID provided by the application to uniquely identify it. It is recommended to use an UUID v5 with the URL or DNS namespace.
name The name of the application password.

Required: 1

Definition

POST /wp/v2/users/<user_id>)/application-passwords

Delete a Application Password

There are no arguments for this endpoint.

Definition

DELETE /wp/v2/users/<user_id>)/application-passwords

Example Request

$ curl -X DELETE https://example.com/wp-json/wp/v2/users/<user_id>)/application-passwords

Retrieve a Application Password

Definition & Example Request

GET /wp/v2/users/<user_id>)/application-passwords/introspect

Query this endpoint to retrieve a specific application password record.

$ curl https://example.com/wp-json/wp/v2/users/<user_id>)/application-passwords/introspect

Arguments

context Scope under which the request is made; determines fields present in response.

Default: view

One of: view, embed, edit

Retrieve a Application Password

Definition & Example Request

GET /wp/v2/users/<user_id>)/application-passwords/<uuid>

Query this endpoint to retrieve a specific application password record.

$ curl https://example.com/wp-json/wp/v2/users/<user_id>)/application-passwords/<uuid>

Arguments

context Scope under which the request is made; determines fields present in response.

Default: view

One of: view, embed, edit

Update a Application Password

Arguments

app_id A UUID provided by the application to uniquely identify it. It is recommended to use an UUID v5 with the URL or DNS namespace.
name The name of the application password.

Definition

POST /wp/v2/users/<user_id>)/application-passwords/<uuid>

Example Request

Delete a Application Password

There are no arguments for this endpoint.

Definition

DELETE /wp/v2/users/<user_id>)/application-passwords/<uuid>

Example Request

$ curl -X DELETE https://example.com/wp-json/wp/v2/users/<user_id>)/application-passwords/<uuid>

Block Pattern Categories

Schema

The schema defines all the fields that exist within a block pattern category record. Any response from these endpoints can be expected to contain the fields below unless the `_filter` query parameter is used or the schema field only appears in a specific context.

name The category name.

JSON data type: string

Read only

Context: view, edit, embed

label The category label, in human readable format.

JSON data type: string

Read only

Context: view, edit, embed

description The category description, in human readable format.

JSON data type: string

Read only

Context: view, edit, embed

Retrieve a Block Pattern Category

Definition & Example Request

GET /wp/v2/block-patterns/categories

Query this endpoint to retrieve a specific block pattern category record.

$ curl https://example.com/wp-json/wp/v2/block-patterns/categories

There are no arguments for this endpoint.

Block Patterns

Schema

The schema defines all the fields that exist within a block pattern record. Any response from these endpoints can be expected to contain the fields below unless the `_filter` query parameter is used or the schema field only appears in a specific context.

name The pattern name.

JSON data type: string

Read only

Context: view, edit, embed

title The pattern title, in human readable format.

JSON data type: string

Read only

Context: view, edit, embed

content The pattern content.

JSON data type: string

Read only

Context: view, edit, embed

description The pattern detailed description.

JSON data type: string

Read only

Context: view, edit, embed

viewport_width The pattern viewport width for inserter preview.

JSON data type: number

Read only

Context: view, edit, embed

inserter Determines whether the pattern is visible in inserter.

JSON data type: boolean

Read only

Context: view, edit, embed

categories The pattern category slugs.

JSON data type: array

Read only

Context: view, edit, embed

keywords The pattern keywords.

JSON data type: array

Read only

Context: view, edit, embed

block_types Block types that the pattern is intended to be used with.

JSON data type: array

Read only

Context: view, edit, embed

post_types An array of post types that the pattern is restricted to be used with.

JSON data type: array

Read only

Context: view, edit, embed

template_types An array of template types where the pattern fits.

JSON data type: array

Read only

Context: view, edit, embed

source Where the pattern comes from e.g. core

JSON data type: string

Read only

Context: view, edit, embed

One of: core, plugin, theme, pattern-directory/core, pattern-directory/theme, pattern-directory/featured

Retrieve a Block Pattern

Definition & Example Request

GET /wp/v2/block-patterns/patterns

Query this endpoint to retrieve a specific block pattern record.

$ curl https://example.com/wp-json/wp/v2/block-patterns/patterns

There are no arguments for this endpoint.

Menu Locations

Schema

The schema defines all the fields that exist within a menu location record. Any response from these endpoints can be expected to contain the fields below unless the `_filter` query parameter is used or the schema field only appears in a specific context.

name The name of the menu location.

JSON data type: string

Read only

Context: embed, view, edit

description The description of the menu location.

JSON data type: string

Read only

Context: embed, view, edit

menu The ID of the assigned menu.

JSON data type: integer

Read only

Context: embed, view, edit

Retrieve a Menu Location

Definition & Example Request

GET /wp/v2/menu-locations

Query this endpoint to retrieve a specific menu location record.

$ curl https://example.com/wp-json/wp/v2/menu-locations

Arguments

context Scope under which the request is made; determines fields present in response.

Default: view

One of: view, embed, edit

Retrieve a Menu Location

Definition & Example Request

GET /wp/v2/menu-locations/<location>

Query this endpoint to retrieve a specific menu location record.

$ curl https://example.com/wp-json/wp/v2/menu-locations/<location>

Arguments

location An alphanumeric identifier for the menu location.
context Scope under which the request is made; determines fields present in response.

Default: view

One of: view, embed, edit

Nav_Menu_Item Revisions

Schema

The schema defines all the fields that exist within a nav_menu_item revision record. Any response from these endpoints can be expected to contain the fields below unless the `_filter` query parameter is used or the schema field only appears in a specific context.

author The ID for the author of the revision.

JSON data type: integer

Context: view, edit, embed

date The date the revision was published, in the site’s timezone.

JSON data type: string,
Format: datetime (details)

Context: view, edit, embed

date_gmt The date the revision was published, as GMT.

JSON data type: string,
Format: datetime (details)

Context: view, edit

guid GUID for the revision, as it exists in the database.

JSON data type: string

Context: view, edit

id Unique identifier for the revision.

JSON data type: integer

Context: view, edit, embed

modified The date the revision was last modified, in the site’s timezone.

JSON data type: string,
Format: datetime (details)

Context: view, edit

modified_gmt The date the revision was last modified, as GMT.

JSON data type: string,
Format: datetime (details)

Context: view, edit

parent The ID for the parent of the revision.

JSON data type: integer

Context: view, edit, embed

slug An alphanumeric identifier for the revision unique to its type.

JSON data type: string

Context: view, edit, embed

title The title for the object.

JSON data type: string or object

Context: view, edit, embed

Retrieve a Nav_Menu_Item Revision

Definition & Example Request

GET /wp/v2/menu-items/<id>/autosaves

Query this endpoint to retrieve a specific nav_menu_item revision record.

$ curl https://example.com/wp-json/wp/v2/menu-items/<id>/autosaves

Arguments

parent The ID for the parent of the autosave.
context Scope under which the request is made; determines fields present in response.

Default: view

One of: view, embed, edit

Create a Nav_Menu_Item Revision

Arguments

parent The ID for the parent of the object.
title The title for the object.
type The family of objects originally represented, such as “post_type” or “taxonomy”.
One of: taxonomy, post_type, post_type_archive, custom
status A named status for the object.
One of: publish, future, draft, pending, private
attr_title Text for the title attribute of the link element for this menu item.
classes Class names for the link element of this menu item.
description The description of this menu item.
menu_order The DB ID of the nav_menu_item that is this item’s menu parent, if any, otherwise 0.
object The type of object originally represented, such as “category”, “post”, or “attachment”.
object_id The database ID of the original object this menu item represents, for example the ID for posts or the term_id for categories.
target The target attribute of the link element for this menu item.
One of: _blank,
url The URL to which this menu item points.
xfn The XFN relationship expressed in the link of this menu item.
menus The terms assigned to the object in the nav_menu taxonomy.
meta Meta fields.

Definition

POST /wp/v2/menu-items/<id>/autosaves

Retrieve a Nav_Menu_Item Revision

Definition & Example Request

GET /wp/v2/menu-items/<parent>/autosaves/<id>

Query this endpoint to retrieve a specific nav_menu_item revision record.

$ curl https://example.com/wp-json/wp/v2/menu-items/<parent>/autosaves/<id>

Arguments

parent The ID for the parent of the autosave.
id The ID for the autosave.
context Scope under which the request is made; determines fields present in response.

Default: view

One of: view, embed, edit

Nav_Menu_Items

Schema

The schema defines all the fields that exist within a nav_menu_item record. Any response from these endpoints can be expected to contain the fields below unless the `_filter` query parameter is used or the schema field only appears in a specific context.

title The title for the object.

JSON data type: string or object

Context: view, edit, embed

id Unique identifier for the object.

JSON data type: integer

Read only

Context: view, edit, embed

type_label The singular label used to describe this type of menu item.

JSON data type: string

Read only

Context: view, edit, embed

type The family of objects originally represented, such as “post_type” or “taxonomy”.

JSON data type: string

Context: view, edit, embed

One of: taxonomy, post_type, post_type_archive, custom

status A named status for the object.

JSON data type: string

Context: view, edit, embed

One of: publish, future, draft, pending, private

parent The ID for the parent of the object.

JSON data type: integer

Context: view, edit, embed

attr_title Text for the title attribute of the link element for this menu item.

JSON data type: string

Context: view, edit, embed

classes Class names for the link element of this menu item.

JSON data type: array

Context: view, edit, embed

description The description of this menu item.

JSON data type: string

Context: view, edit, embed

menu_order The DB ID of the nav_menu_item that is this item’s menu parent, if any, otherwise 0.

JSON data type: integer

Context: view, edit, embed

object The type of object originally represented, such as “category”, “post”, or “attachment”.

JSON data type: string

Context: view, edit, embed

object_id The database ID of the original object this menu item represents, for example the ID for posts or the term_id for categories.

JSON data type: integer

Context: view, edit, embed

target The target attribute of the link element for this menu item.

JSON data type: string

Context: view, edit, embed

One of: _blank,

url The URL to which this menu item points.

JSON data type: string,
Format: uri

Context: view, edit, embed

xfn The XFN relationship expressed in the link of this menu item.

JSON data type: array

Context: view, edit, embed

invalid Whether the menu item represents an object that no longer exists.

JSON data type: boolean

Read only

Context: view, edit, embed

menus The terms assigned to the object in the nav_menu taxonomy.

JSON data type: integer

Context: view, edit

meta Meta fields.

JSON data type: object

Context: view, edit

List Nav_Menu_Items

Query this endpoint to retrieve a collection of nav_menu_items. The response you receive can be controlled and filtered using the URL query parameters below.

Definition

GET /wp/v2/menu-items

Example Request

$ curl https://example.com/wp-json/wp/v2/menu-items

Arguments

context Scope under which the request is made; determines fields present in response.

Default: view

One of: view, embed, edit

page Current page of the collection.

Default: 1

per_page Maximum number of items to be returned in result set.

Default: 100

search Limit results to those matching a string.
after Limit response to posts published after a given ISO8601 compliant date.
modified_after Limit response to posts modified after a given ISO8601 compliant date.
before Limit response to posts published before a given ISO8601 compliant date.
modified_before Limit response to posts modified before a given ISO8601 compliant date.
exclude Ensure result set excludes specific IDs.
include Limit result set to specific IDs.
offset Offset the result set by a specific number of items.
order Order sort attribute ascending or descending.

Default: asc

One of: asc, desc

orderby Sort collection by object attribute.

Default: menu_order

One of: author, date, id, include, modified, parent, relevance, slug, include_slugs, title, menu_order

search_columns Array of column names to be searched.
slug Limit result set to posts with one or more specific slugs.
status Limit result set to posts assigned one or more statuses.

Default: publish

tax_relation Limit result set based on relationship between multiple taxonomies.
One of: AND, OR
menus Limit result set to items with specific terms assigned in the menus taxonomy.
menus_exclude Limit result set to items except those with specific terms assigned in the menus taxonomy.
menu_order Limit result set to posts with a specific menu_order value.

Create a Nav_Menu_Item

Arguments

title The title for the object.
type The family of objects originally represented, such as “post_type” or “taxonomy”.

Default: custom

One of: taxonomy, post_type, post_type_archive, custom

status A named status for the object.

Default: publish

One of: publish, future, draft, pending, private

parent The ID for the parent of the object.
attr_title Text for the title attribute of the link element for this menu item.
classes Class names for the link element of this menu item.
description The description of this menu item.
menu_order The DB ID of the nav_menu_item that is this item’s menu parent, if any, otherwise 0.

Default: 1

object The type of object originally represented, such as “category”, “post”, or “attachment”.
object_id The database ID of the original object this menu item represents, for example the ID for posts or the term_id for categories.
target The target attribute of the link element for this menu item.
One of: _blank,
url The URL to which this menu item points.
xfn The XFN relationship expressed in the link of this menu item.
menus The terms assigned to the object in the nav_menu taxonomy.
meta Meta fields.

Definition

POST /wp/v2/menu-items

Retrieve a Nav_Menu_Item

Definition & Example Request

GET /wp/v2/menu-items/<id>

Query this endpoint to retrieve a specific nav_menu_item record.

$ curl https://example.com/wp-json/wp/v2/menu-items/<id>

Arguments

id Unique identifier for the post.
context Scope under which the request is made; determines fields present in response.

Default: view

One of: view, embed, edit

Update a Nav_Menu_Item

Arguments

id Unique identifier for the post.
title The title for the object.
type The family of objects originally represented, such as “post_type” or “taxonomy”.
One of: taxonomy, post_type, post_type_archive, custom
status A named status for the object.
One of: publish, future, draft, pending, private
parent The ID for the parent of the object.
attr_title Text for the title attribute of the link element for this menu item.
classes Class names for the link element of this menu item.
description The description of this menu item.
menu_order The DB ID of the nav_menu_item that is this item’s menu parent, if any, otherwise 0.
object The type of object originally represented, such as “category”, “post”, or “attachment”.
object_id The database ID of the original object this menu item represents, for example the ID for posts or the term_id for categories.
target The target attribute of the link element for this menu item.
One of: _blank,
url The URL to which this menu item points.
xfn The XFN relationship expressed in the link of this menu item.
menus The terms assigned to the object in the nav_menu taxonomy.
meta Meta fields.

Definition

POST /wp/v2/menu-items/<id>

Example Request

Delete a Nav_Menu_Item

Arguments

id Unique identifier for the post.
force Whether to bypass Trash and force deletion.

Definition

DELETE /wp/v2/menu-items/<id>

Example Request

$ curl -X DELETE https://example.com/wp-json/wp/v2/menu-items/<id>

Nav_Menus

Schema

The schema defines all the fields that exist within a nav_menu record. Any response from these endpoints can be expected to contain the fields below unless the `_filter` query parameter is used or the schema field only appears in a specific context.

id Unique identifier for the term.

JSON data type: integer

Read only

Context: view, embed, edit

description HTML description of the term.

JSON data type: string

Context: view, edit

name HTML title for the term.

JSON data type: string

Context: view, embed, edit

slug An alphanumeric identifier for the term unique to its type.

JSON data type: string

Context: view, embed, edit

meta Meta fields.

JSON data type: object

Context: view, edit

locations The locations assigned to the menu.

JSON data type: array

Context: view, edit

auto_add Whether to automatically add top level pages to this menu.

JSON data type: boolean

Context: view, edit

List Nav_Menus

Query this endpoint to retrieve a collection of nav_menus. The response you receive can be controlled and filtered using the URL query parameters below.

Definition

GET /wp/v2/menus

Example Request

$ curl https://example.com/wp-json/wp/v2/menus

Arguments

context Scope under which the request is made; determines fields present in response.

Default: view

One of: view, embed, edit

page Current page of the collection.

Default: 1

per_page Maximum number of items to be returned in result set.

Default: 10

search Limit results to those matching a string.
exclude Ensure result set excludes specific IDs.
include Limit result set to specific IDs.
offset Offset the result set by a specific number of items.
order Order sort attribute ascending or descending.

Default: asc

One of: asc, desc

orderby Sort collection by term attribute.

Default: name

One of: id, include, name, slug, include_slugs, term_group, description, count

hide_empty Whether to hide terms not assigned to any posts.
post Limit result set to terms assigned to a specific post.
slug Limit result set to terms with one or more specific slugs.

Create a Nav_Menu

Arguments

description HTML description of the term.
name HTML title for the term.

Required: 1

slug An alphanumeric identifier for the term unique to its type.
meta Meta fields.
locations The locations assigned to the menu.
auto_add Whether to automatically add top level pages to this menu.

Definition

POST /wp/v2/menus

Retrieve a Nav_Menu

Definition & Example Request

GET /wp/v2/menus/<id>

Query this endpoint to retrieve a specific nav_menu record.

$ curl https://example.com/wp-json/wp/v2/menus/<id>

Arguments

id Unique identifier for the term.
context Scope under which the request is made; determines fields present in response.

Default: view

One of: view, embed, edit

Update a Nav_Menu

Arguments

id Unique identifier for the term.
description HTML description of the term.
name HTML title for the term.
slug An alphanumeric identifier for the term unique to its type.
meta Meta fields.
locations The locations assigned to the menu.
auto_add Whether to automatically add top level pages to this menu.

Definition

POST /wp/v2/menus/<id>

Example Request

Delete a Nav_Menu

Arguments

id Unique identifier for the term.
force Required to be true, as terms do not support trashing.

Definition

DELETE /wp/v2/menus/<id>

Example Request

$ curl -X DELETE https://example.com/wp-json/wp/v2/menus/<id>

Pattern Directory Items

Schema

The schema defines all the fields that exist within a pattern directory item record. Any response from these endpoints can be expected to contain the fields below unless the `_filter` query parameter is used or the schema field only appears in a specific context.

id The pattern ID.

JSON data type: integer

Context: view, edit, embed

title The pattern title, in human readable format.

JSON data type: string

Context: view, edit, embed

content The pattern content.

JSON data type: string

Context: view, edit, embed

categories The pattern’s category slugs.

JSON data type: array

Context: view, edit, embed

keywords The pattern’s keywords.

JSON data type: array

Context: view, edit, embed

description A description of the pattern.

JSON data type: string

Context: view, edit, embed

viewport_width The preferred width of the viewport when previewing a pattern, in pixels.

JSON data type: integer

Context: view, edit, embed

block_types The block types which can use this pattern.

JSON data type: array

Context: view, embed

List Pattern Directory Items

Query this endpoint to retrieve a collection of pattern directory items. The response you receive can be controlled and filtered using the URL query parameters below.

Definition

GET /wp/v2/pattern-directory/patterns

Example Request

$ curl https://example.com/wp-json/wp/v2/pattern-directory/patterns

Arguments

context Scope under which the request is made; determines fields present in response.

Default: view

One of: view, embed, edit

page Current page of the collection.

Default: 1

per_page Maximum number of items to be returned in result set.

Default: 100

search Limit results to those matching a string.
category Limit results to those matching a category ID.
keyword Limit results to those matching a keyword ID.
slug Limit results to those matching a pattern (slug).
offset Offset the result set by a specific number of items.
order Order sort attribute ascending or descending.

Default: desc

One of: asc, desc

orderby Sort collection by post attribute.

Default: date

One of: author, date, id, include, modified, parent, relevance, slug, include_slugs, title, favorite_count

Sidebars

Schema

The schema defines all the fields that exist within a sidebar record. Any response from these endpoints can be expected to contain the fields below unless the `_filter` query parameter is used or the schema field only appears in a specific context.

id ID of sidebar.

JSON data type: string

Read only

Context: embed, view, edit

name Unique name identifying the sidebar.

JSON data type: string

Read only

Context: embed, view, edit

description Description of sidebar.

JSON data type: string

Read only

Context: embed, view, edit

class Extra CSS class to assign to the sidebar in the Widgets interface.

JSON data type: string

Read only

Context: embed, view, edit

before_widget HTML content to prepend to each widget’s HTML output when assigned to this sidebar. Default is an opening list item element.

JSON data type: string

Read only

Context: embed, view, edit

after_widget HTML content to append to each widget’s HTML output when assigned to this sidebar. Default is a closing list item element.

JSON data type: string

Read only

Context: embed, view, edit

before_title HTML content to prepend to the sidebar title when displayed. Default is an opening h2 element.

JSON data type: string

Read only

Context: embed, view, edit

after_title HTML content to append to the sidebar title when displayed. Default is a closing h2 element.

JSON data type: string

Read only

Context: embed, view, edit

status Status of sidebar.

JSON data type: string

Read only

Context: embed, view, edit

One of: active, inactive

widgets Nested widgets.

JSON data type: array

Context: embed, view, edit

Retrieve a Sidebar

Definition & Example Request

GET /wp/v2/sidebars

Query this endpoint to retrieve a specific sidebar record.

$ curl https://example.com/wp-json/wp/v2/sidebars

Arguments

context Scope under which the request is made; determines fields present in response.

Default: view

One of: view, embed, edit

Retrieve a Sidebar

Definition & Example Request

GET /wp/v2/sidebars/<id>

Query this endpoint to retrieve a specific sidebar record.

$ curl https://example.com/wp-json/wp/v2/sidebars/<id>

Arguments

id The id of a registered sidebar
context Scope under which the request is made; determines fields present in response.

Default: view

One of: view, embed, edit

Update a Sidebar

Arguments

widgets Nested widgets.

Definition

POST /wp/v2/sidebars/<id>

Example Request

Widget Types

Schema

The schema defines all the fields that exist within a widget type record. Any response from these endpoints can be expected to contain the fields below unless the `_filter` query parameter is used or the schema field only appears in a specific context.

id Unique slug identifying the widget type.

JSON data type: string

Read only

Context: embed, view, edit

name Human-readable name identifying the widget type.

JSON data type: string

Read only

Context: embed, view, edit

description Description of the widget.

JSON data type: string

Context: view, edit, embed

is_multi Whether the widget supports multiple instances

JSON data type: boolean

Read only

Context: view, edit, embed

classname Class name

JSON data type: string

Read only

Context: embed, view, edit

Retrieve a Widget Type

Definition & Example Request

GET /wp/v2/widget-types

Query this endpoint to retrieve a specific widget type record.

$ curl https://example.com/wp-json/wp/v2/widget-types

Arguments

context Scope under which the request is made; determines fields present in response.

Default: view

One of: view, embed, edit

Retrieve a Widget Type

Definition & Example Request

GET /wp/v2/widget-types/<id>

Query this endpoint to retrieve a specific widget type record.

$ curl https://example.com/wp-json/wp/v2/widget-types/<id>

Arguments

id The widget type id.
context Scope under which the request is made; determines fields present in response.

Default: view

One of: view, embed, edit

Widgets

Schema

The schema defines all the fields that exist within a widget record. Any response from these endpoints can be expected to contain the fields below unless the `_filter` query parameter is used or the schema field only appears in a specific context.

id Unique identifier for the widget.

JSON data type: string

Context: view, edit, embed

id_base The type of the widget. Corresponds to ID in widget-types endpoint.

JSON data type: string

Context: view, edit, embed

sidebar The sidebar the widget belongs to.

JSON data type: string

Context: view, edit, embed

rendered HTML representation of the widget.

JSON data type: string

Read only

Context: view, edit, embed

rendered_form HTML representation of the widget admin form.

JSON data type: string

Read only

Context: edit

instance Instance settings of the widget, if supported.

JSON data type: object

Context: edit

form_data URL-encoded form data from the widget admin form. Used to update a widget that does not support instance. Write only.

JSON data type: string

Context:

Retrieve a Widget

Definition & Example Request

GET /wp/v2/widgets

Query this endpoint to retrieve a specific widget record.

$ curl https://example.com/wp-json/wp/v2/widgets

Arguments

context Scope under which the request is made; determines fields present in response.

Default: view

One of: view, embed, edit

sidebar The sidebar to return widgets for.

Create a Widget

Arguments

id Unique identifier for the widget.
id_base The type of the widget. Corresponds to ID in widget-types endpoint.
sidebar The sidebar the widget belongs to.

Required: 1

Default: wp_inactive_widgets

instance Instance settings of the widget, if supported.
form_data URL-encoded form data from the widget admin form. Used to update a widget that does not support instance. Write only.

Definition

POST /wp/v2/widgets

Retrieve a Widget

Definition & Example Request

GET /wp/v2/widgets/<id>

Query this endpoint to retrieve a specific widget record.

$ curl https://example.com/wp-json/wp/v2/widgets/<id>

Arguments

context Scope under which the request is made; determines fields present in response.

Default: view

One of: view, embed, edit

Update a Widget

Arguments

id Unique identifier for the widget.
id_base The type of the widget. Corresponds to ID in widget-types endpoint.
sidebar The sidebar the widget belongs to.
instance Instance settings of the widget, if supported.
form_data URL-encoded form data from the widget admin form. Used to update a widget that does not support instance. Write only.

Definition

POST /wp/v2/widgets/<id>

Example Request

Delete a Widget

Arguments

force Whether to force removal of the widget, or move it to the inactive sidebar.

Definition

DELETE /wp/v2/widgets/<id>

Example Request

$ curl -X DELETE https://example.com/wp-json/wp/v2/widgets/<id>

Wp Site Health Tests

Schema

The schema defines all the fields that exist within a wp site health test record. Any response from these endpoints can be expected to contain the fields below unless the `_filter` query parameter is used or the schema field only appears in a specific context.

test The name of the test being run.

JSON data type: string

Read only

Context:

label A label describing the test.

JSON data type: string

Read only

Context:

status The status of the test.

JSON data type: string

Read only

Context:

One of: good, recommended, critical

badge The category this test is grouped in.

JSON data type: object

Read only

Context:

description A more descriptive explanation of what the test looks for, and why it is important for the user.

JSON data type: string

Read only

Context:

actions HTML containing an action to direct the user to where they can resolve the issue.

JSON data type: string

Read only

Context:

Retrieve a Wp Site Health Test

Definition & Example Request

GET /wp-site-health/v1/tests/background-updates

Query this endpoint to retrieve a specific wp site health test record.

$ curl https://example.com/wp-json/wp-site-health/v1/tests/background-updates

There are no arguments for this endpoint.

Retrieve a Wp Site Health Test

Definition & Example Request

GET /wp-site-health/v1/tests/loopback-requests

Query this endpoint to retrieve a specific wp site health test record.

$ curl https://example.com/wp-json/wp-site-health/v1/tests/loopback-requests

There are no arguments for this endpoint.

Retrieve a Wp Site Health Test

Definition & Example Request

GET /wp-site-health/v1/tests/https-status

Query this endpoint to retrieve a specific wp site health test record.

$ curl https://example.com/wp-json/wp-site-health/v1/tests/https-status

There are no arguments for this endpoint.

Retrieve a Wp Site Health Test

Definition & Example Request

GET /wp-site-health/v1/tests/dotorg-communication

Query this endpoint to retrieve a specific wp site health test record.

$ curl https://example.com/wp-json/wp-site-health/v1/tests/dotorg-communication

There are no arguments for this endpoint.

Retrieve a Wp Site Health Test

Definition & Example Request

GET /wp-site-health/v1/tests/authorization-header

Query this endpoint to retrieve a specific wp site health test record.

$ curl https://example.com/wp-json/wp-site-health/v1/tests/authorization-header

There are no arguments for this endpoint.

Global_Styles

Schema

The schema defines all the fields that exist within a global_styles record. Any response from these endpoints can be expected to contain the fields below unless the `_filter` query parameter is used or the schema field only appears in a specific context.

id ID of global styles config.

JSON data type: string

Read only

Context: embed, view, edit

styles Global styles.

JSON data type: object

Context: view, edit

settings Global settings.

JSON data type: object

Context: view, edit

title Title of the global styles variation.

JSON data type: object or string

Context: embed, view, edit

Retrieve a Global_Styles

Definition & Example Request

GET /wp/v2/global-styles/<id>

Query this endpoint to retrieve a specific global_styles record.

$ curl https://example.com/wp-json/wp/v2/global-styles/<id>

Arguments

id The id of a template

Update a Global_Styles

Arguments

styles Global styles.
settings Global settings.
title Title of the global styles variation.

Definition

POST /wp/v2/global-styles/<id>

Example Request

Navigation Revisions

Schema

The schema defines all the fields that exist within a navigation revision record. Any response from these endpoints can be expected to contain the fields below unless the `_filter` query parameter is used or the schema field only appears in a specific context.

author The ID for the author of the revision.

JSON data type: integer

Context: view, edit, embed

date The date the revision was published, in the site’s timezone.

JSON data type: string,
Format: datetime (details)

Context: view, edit, embed

date_gmt The date the revision was published, as GMT.

JSON data type: string,
Format: datetime (details)

Context: view, edit

guid The globally unique identifier for the post.

JSON data type: object

Read only

Context: view, edit

id Unique identifier for the revision.

JSON data type: integer

Context: view, edit, embed

modified The date the revision was last modified, in the site’s timezone.

JSON data type: string,
Format: datetime (details)

Context: view, edit

modified_gmt The date the revision was last modified, as GMT.

JSON data type: string,
Format: datetime (details)

Context: view, edit

parent The ID for the parent of the revision.

JSON data type: integer

Context: view, edit, embed

slug An alphanumeric identifier for the revision unique to its type.

JSON data type: string

Context: view, edit, embed

title The title for the post.

JSON data type: object

Context: view, edit, embed

content The content for the post.

JSON data type: object

Context: view, edit, embed

List Navigation Revisions

Query this endpoint to retrieve a collection of navigation revisions. The response you receive can be controlled and filtered using the URL query parameters below.

Definition

GET /wp/v2/navigation/<parent>/revisions

Example Request

$ curl https://example.com/wp-json/wp/v2/navigation/<parent>/revisions

Arguments

parent The ID for the parent of the revision.
context Scope under which the request is made; determines fields present in response.

Default: view

One of: view, embed, edit

page Current page of the collection.

Default: 1

per_page Maximum number of items to be returned in result set.
search Limit results to those matching a string.
exclude Ensure result set excludes specific IDs.
include Limit result set to specific IDs.
offset Offset the result set by a specific number of items.
order Order sort attribute ascending or descending.

Default: desc

One of: asc, desc

orderby Sort collection by object attribute.

Default: date

One of: date, id, include, relevance, slug, include_slugs, title

Retrieve a Navigation Revision

Definition & Example Request

GET /wp/v2/navigation/<parent>/revisions/<id>

Query this endpoint to retrieve a specific navigation revision record.

$ curl https://example.com/wp-json/wp/v2/navigation/<parent>/revisions/<id>

Arguments

parent The ID for the parent of the revision.
id Unique identifier for the revision.
context Scope under which the request is made; determines fields present in response.

Default: view

One of: view, embed, edit

Delete a Navigation Revision

Arguments

parent The ID for the parent of the revision.
id Unique identifier for the revision.
force Required to be true, as revisions do not support trashing.

Definition

DELETE /wp/v2/navigation/<parent>/revisions/<id>

Example Request

$ curl -X DELETE https://example.com/wp-json/wp/v2/navigation/<parent>/revisions/<id>

Retrieve a Navigation Revision

Definition & Example Request

GET /wp/v2/navigation/<id>/autosaves

Query this endpoint to retrieve a specific navigation revision record.

$ curl https://example.com/wp-json/wp/v2/navigation/<id>/autosaves

Arguments

parent The ID for the parent of the autosave.
context Scope under which the request is made; determines fields present in response.

Default: view

One of: view, embed, edit

Create a Navigation Revision

Arguments

parent The ID for the parent of the autosave.
date The date the post was published, in the site’s timezone.
date_gmt The date the post was published, as GMT.
slug An alphanumeric identifier for the post unique to its type.
status A named status for the post.
One of: publish, future, draft, pending, private
password A password to protect access to the content and excerpt.
title The title for the post.
content The content for the post.
template The theme file to use to display the post.

Definition

POST /wp/v2/navigation/<id>/autosaves

Retrieve a Navigation Revision

Definition & Example Request

GET /wp/v2/navigation/<parent>/autosaves/<id>

Query this endpoint to retrieve a specific navigation revision record.

$ curl https://example.com/wp-json/wp/v2/navigation/<parent>/autosaves/<id>

Arguments

parent The ID for the parent of the autosave.
id The ID for the autosave.
context Scope under which the request is made; determines fields present in response.

Default: view

One of: view, embed, edit

Navigations

Schema

The schema defines all the fields that exist within a navigation record. Any response from these endpoints can be expected to contain the fields below unless the `_filter` query parameter is used or the schema field only appears in a specific context.

date The date the post was published, in the site’s timezone.

JSON data type: string or null,
Format: datetime (details)

Context: view, edit, embed

date_gmt The date the post was published, as GMT.

JSON data type: string or null,
Format: datetime (details)

Context: view, edit

guid The globally unique identifier for the post.

JSON data type: object

Read only

Context: view, edit

id Unique identifier for the post.

JSON data type: integer

Read only

Context: view, edit, embed

link URL to the post.

JSON data type: string,
Format: uri

Read only

Context: view, edit, embed

modified The date the post was last modified, in the site’s timezone.

JSON data type: string,
Format: datetime (details)

Read only

Context: view, edit

modified_gmt The date the post was last modified, as GMT.

JSON data type: string,
Format: datetime (details)

Read only

Context: view, edit

slug An alphanumeric identifier for the post unique to its type.

JSON data type: string

Context: view, edit, embed

status A named status for the post.

JSON data type: string

Context: view, edit, embed

One of: publish, future, draft, pending, private

type Type of post.

JSON data type: string

Read only

Context: view, edit, embed

password A password to protect access to the content and excerpt.

JSON data type: string

Context: edit

title The title for the post.

JSON data type: object

Context: view, edit, embed

content The content for the post.

JSON data type: object

Context: view, edit, embed

template The theme file to use to display the post.

JSON data type: string

Context: view, edit

List Navigations

Query this endpoint to retrieve a collection of navigations. The response you receive can be controlled and filtered using the URL query parameters below.

Definition

GET /wp/v2/navigation

Example Request

$ curl https://example.com/wp-json/wp/v2/navigation

Arguments

context Scope under which the request is made; determines fields present in response.

Default: view

One of: view, embed, edit

page Current page of the collection.

Default: 1

per_page Maximum number of items to be returned in result set.

Default: 10

search Limit results to those matching a string.
after Limit response to posts published after a given ISO8601 compliant date.
modified_after Limit response to posts modified after a given ISO8601 compliant date.
before Limit response to posts published before a given ISO8601 compliant date.
modified_before Limit response to posts modified before a given ISO8601 compliant date.
exclude Ensure result set excludes specific IDs.
include Limit result set to specific IDs.
offset Offset the result set by a specific number of items.
order Order sort attribute ascending or descending.

Default: desc

One of: asc, desc

orderby Sort collection by post attribute.

Default: date

One of: author, date, id, include, modified, parent, relevance, slug, include_slugs, title

search_columns Array of column names to be searched.
slug Limit result set to posts with one or more specific slugs.
status Limit result set to posts assigned one or more statuses.

Default: publish

Create a Navigation

Arguments

date The date the post was published, in the site’s timezone.
date_gmt The date the post was published, as GMT.
slug An alphanumeric identifier for the post unique to its type.
status A named status for the post.
One of: publish, future, draft, pending, private
password A password to protect access to the content and excerpt.
title The title for the post.
content The content for the post.
template The theme file to use to display the post.

Definition

POST /wp/v2/navigation

Retrieve a Navigation

Definition & Example Request

GET /wp/v2/navigation/<id>

Query this endpoint to retrieve a specific navigation record.

$ curl https://example.com/wp-json/wp/v2/navigation/<id>

Arguments

id Unique identifier for the post.
context Scope under which the request is made; determines fields present in response.

Default: view

One of: view, embed, edit

password The password for the post if it is password protected.

Update a Navigation

Arguments

id Unique identifier for the post.
date The date the post was published, in the site’s timezone.
date_gmt The date the post was published, as GMT.
slug An alphanumeric identifier for the post unique to its type.
status A named status for the post.
One of: publish, future, draft, pending, private
password A password to protect access to the content and excerpt.
title The title for the post.
content The content for the post.
template The theme file to use to display the post.

Definition

POST /wp/v2/navigation/<id>

Example Request

Delete a Navigation

Arguments

id Unique identifier for the post.
force Whether to bypass Trash and force deletion.

Definition

DELETE /wp/v2/navigation/<id>

Example Request

$ curl -X DELETE https://example.com/wp-json/wp/v2/navigation/<id>

Template Revisions

Schema

The schema defines all the fields that exist within a template revision record. Any response from these endpoints can be expected to contain the fields below unless the `_filter` query parameter is used or the schema field only appears in a specific context.

author The ID for the author of the revision.

JSON data type: integer

Context: view, edit, embed

date The date the revision was published, in the site’s timezone.

JSON data type: string,
Format: datetime (details)

Context: view, edit, embed

date_gmt The date the revision was published, as GMT.

JSON data type: string,
Format: datetime (details)

Context: view, edit

guid GUID for the revision, as it exists in the database.

JSON data type: string

Context: view, edit

id Unique identifier for the revision.

JSON data type: integer

Context: view, edit, embed

modified The date the revision was last modified, in the site’s timezone.

JSON data type: string,
Format: datetime (details)

Context: view, edit

modified_gmt The date the revision was last modified, as GMT.

JSON data type: string,
Format: datetime (details)

Context: view, edit

parent The ID for the parent of the revision.

JSON data type: integer

Context: view, edit, embed

slug An alphanumeric identifier for the revision unique to its type.

JSON data type: string

Context: view, edit, embed

title Title of template.

JSON data type: object or string

Context: embed, view, edit

content Content of template.

JSON data type: object or string

Context: embed, view, edit

List Template Revisions

Query this endpoint to retrieve a collection of template revisions. The response you receive can be controlled and filtered using the URL query parameters below.

Definition

GET /wp/v2/templates/<parent>/revisions

Example Request

$ curl https://example.com/wp-json/wp/v2/templates/<parent>/revisions

Arguments

parent The ID for the parent of the revision.
context Scope under which the request is made; determines fields present in response.

Default: view

One of: view, embed, edit

page Current page of the collection.

Default: 1

per_page Maximum number of items to be returned in result set.
search Limit results to those matching a string.
exclude Ensure result set excludes specific IDs.
include Limit result set to specific IDs.
offset Offset the result set by a specific number of items.
order Order sort attribute ascending or descending.

Default: desc

One of: asc, desc

orderby Sort collection by object attribute.

Default: date

One of: date, id, include, relevance, slug, include_slugs, title

Retrieve a Template Revision

Definition & Example Request

GET /wp/v2/templates/<parent>/revisions/<id>

Query this endpoint to retrieve a specific template revision record.

$ curl https://example.com/wp-json/wp/v2/templates/<parent>/revisions/<id>

Arguments

parent The ID for the parent of the revision.
id Unique identifier for the revision.
context Scope under which the request is made; determines fields present in response.

Default: view

One of: view, embed, edit

Delete a Template Revision

Arguments

parent The ID for the parent of the revision.
id Unique identifier for the revision.
force Required to be true, as revisions do not support trashing.

Definition

DELETE /wp/v2/templates/<parent>/revisions/<id>

Example Request

$ curl -X DELETE https://example.com/wp-json/wp/v2/templates/<parent>/revisions/<id>

Retrieve a Template Revision

Definition & Example Request

GET /wp/v2/templates/<id>/autosaves

Query this endpoint to retrieve a specific template revision record.

$ curl https://example.com/wp-json/wp/v2/templates/<id>/autosaves

Arguments

parent The ID for the parent of the autosave.
context Scope under which the request is made; determines fields present in response.

Default: view

One of: view, embed, edit

Create a Template Revision

Arguments

parent The ID for the parent of the autosave.
slug Unique slug identifying the template.
theme Theme identifier for the template.
type Type of template.
content Content of template.
title Title of template.
description Description of template.
status Status of template.
One of: publish, future, draft, pending, private
author The ID for the author of the template.

Definition

POST /wp/v2/templates/<id>/autosaves

Retrieve a Template Revision

Definition & Example Request

GET /wp/v2/templates/<parent>/autosaves/<id>

Query this endpoint to retrieve a specific template revision record.

$ curl https://example.com/wp-json/wp/v2/templates/<parent>/autosaves/<id>

Arguments

parent The ID for the parent of the autosave.
id The ID for the autosave.
context Scope under which the request is made; determines fields present in response.

Default: view

One of: view, embed, edit

Template_Part Revisions

Schema

The schema defines all the fields that exist within a template_part revision record. Any response from these endpoints can be expected to contain the fields below unless the `_filter` query parameter is used or the schema field only appears in a specific context.

author The ID for the author of the revision.

JSON data type: integer

Context: view, edit, embed

date The date the revision was published, in the site’s timezone.

JSON data type: string,
Format: datetime (details)

Context: view, edit, embed

date_gmt The date the revision was published, as GMT.

JSON data type: string,
Format: datetime (details)

Context: view, edit

guid GUID for the revision, as it exists in the database.

JSON data type: string

Context: view, edit

id Unique identifier for the revision.

JSON data type: integer

Context: view, edit, embed

modified The date the revision was last modified, in the site’s timezone.

JSON data type: string,
Format: datetime (details)

Context: view, edit

modified_gmt The date the revision was last modified, as GMT.

JSON data type: string,
Format: datetime (details)

Context: view, edit

parent The ID for the parent of the revision.

JSON data type: integer

Context: view, edit, embed

slug An alphanumeric identifier for the revision unique to its type.

JSON data type: string

Context: view, edit, embed

title Title of template.

JSON data type: object or string

Context: embed, view, edit

content Content of template.

JSON data type: object or string

Context: embed, view, edit

List Template_Part Revisions

Query this endpoint to retrieve a collection of template_part revisions. The response you receive can be controlled and filtered using the URL query parameters below.

Definition

GET /wp/v2/template-parts/<parent>/revisions

Example Request

$ curl https://example.com/wp-json/wp/v2/template-parts/<parent>/revisions

Arguments

parent The ID for the parent of the revision.
context Scope under which the request is made; determines fields present in response.

Default: view

One of: view, embed, edit

page Current page of the collection.

Default: 1

per_page Maximum number of items to be returned in result set.
search Limit results to those matching a string.
exclude Ensure result set excludes specific IDs.
include Limit result set to specific IDs.
offset Offset the result set by a specific number of items.
order Order sort attribute ascending or descending.

Default: desc

One of: asc, desc

orderby Sort collection by object attribute.

Default: date

One of: date, id, include, relevance, slug, include_slugs, title

Retrieve a Template_Part Revision

Definition & Example Request

GET /wp/v2/template-parts/<parent>/revisions/<id>

Query this endpoint to retrieve a specific template_part revision record.

$ curl https://example.com/wp-json/wp/v2/template-parts/<parent>/revisions/<id>

Arguments

parent The ID for the parent of the revision.
id Unique identifier for the revision.
context Scope under which the request is made; determines fields present in response.

Default: view

One of: view, embed, edit

Delete a Template_Part Revision

Arguments

parent The ID for the parent of the revision.
id Unique identifier for the revision.
force Required to be true, as revisions do not support trashing.

Definition

DELETE /wp/v2/template-parts/<parent>/revisions/<id>

Example Request

$ curl -X DELETE https://example.com/wp-json/wp/v2/template-parts/<parent>/revisions/<id>

Retrieve a Template_Part Revision

Definition & Example Request

GET /wp/v2/template-parts/<id>/autosaves

Query this endpoint to retrieve a specific template_part revision record.

$ curl https://example.com/wp-json/wp/v2/template-parts/<id>/autosaves

Arguments

parent The ID for the parent of the autosave.
context Scope under which the request is made; determines fields present in response.

Default: view

One of: view, embed, edit

Create a Template_Part Revision

Arguments

parent The ID for the parent of the autosave.
slug Unique slug identifying the template.
theme Theme identifier for the template.
type Type of template.
content Content of template.
title Title of template.
description Description of template.
status Status of template.
One of: publish, future, draft, pending, private
author The ID for the author of the template.
area Where the template part is intended for use (header, footer, etc.)

Definition

POST /wp/v2/template-parts/<id>/autosaves

Retrieve a Template_Part Revision

Definition & Example Request

GET /wp/v2/template-parts/<parent>/autosaves/<id>

Query this endpoint to retrieve a specific template_part revision record.

$ curl https://example.com/wp-json/wp/v2/template-parts/<parent>/autosaves/<id>

Arguments

parent The ID for the parent of the autosave.
id The ID for the autosave.
context Scope under which the request is made; determines fields present in response.

Default: view

One of: view, embed, edit

Template_Parts

Schema

The schema defines all the fields that exist within a template_part record. Any response from these endpoints can be expected to contain the fields below unless the `_filter` query parameter is used or the schema field only appears in a specific context.

id ID of template.

JSON data type: string

Read only

Context: embed, view, edit

slug Unique slug identifying the template.

JSON data type: string

Context: embed, view, edit

theme Theme identifier for the template.

JSON data type: string

Context: embed, view, edit

type Type of template.

JSON data type: string

Context: embed, view, edit

source Source of template

JSON data type: string

Read only

Context: embed, view, edit

origin Source of a customized template

JSON data type: string

Read only

Context: embed, view, edit

content Content of template.

JSON data type: object or string

Context: embed, view, edit

title Title of template.

JSON data type: object or string

Context: embed, view, edit

description Description of template.

JSON data type: string

Context: embed, view, edit

status Status of template.

JSON data type: string

Context: embed, view, edit

One of: publish, future, draft, pending, private

wp_id Post ID.

JSON data type: integer

Read only

Context: embed, view, edit

has_theme_file Theme file exists.

JSON data type: bool

Read only

Context: embed, view, edit

author The ID for the author of the template.

JSON data type: integer

Context: view, edit, embed

modified The date the template was last modified, in the site’s timezone.

JSON data type: string,
Format: datetime (details)

Read only

Context: view, edit

area Where the template part is intended for use (header, footer, etc.)

JSON data type: string

Context: embed, view, edit

Retrieve a Template_Part

Definition & Example Request

GET /wp/v2/template-parts

Query this endpoint to retrieve a specific template_part record.

$ curl https://example.com/wp-json/wp/v2/template-parts

Arguments

context Scope under which the request is made; determines fields present in response.

Default: view

One of: view, embed, edit

wp_id Limit to the specified post id.
area Limit to the specified template part area.
post_type Post type to get the templates for.

Create a Template_Part

Arguments

slug Unique slug identifying the template.

Required: 1

theme Theme identifier for the template.
type Type of template.
content Content of template.
title Title of template.
description Description of template.
status Status of template.

Default: publish

One of: publish, future, draft, pending, private

author The ID for the author of the template.
area Where the template part is intended for use (header, footer, etc.)

Definition

POST /wp/v2/template-parts

Retrieve a Template_Part

Definition & Example Request

GET /wp/v2/template-parts/<id>?)[\/\w%-]+)

Query this endpoint to retrieve a specific template_part record.

$ curl https://example.com/wp-json/wp/v2/template-parts/<id>?)[\/\w%-]+)

Arguments

id The id of a template
context Scope under which the request is made; determines fields present in response.

Default: view

One of: view, embed, edit

Update a Template_Part

Arguments

id The id of a template
slug Unique slug identifying the template.
theme Theme identifier for the template.
type Type of template.
content Content of template.
title Title of template.
description Description of template.
status Status of template.
One of: publish, future, draft, pending, private
author The ID for the author of the template.
area Where the template part is intended for use (header, footer, etc.)

Definition

POST /wp/v2/template-parts/<id>?)[\/\w%-]+)

Example Request

Delete a Template_Part

Arguments

id The id of a template
force Whether to bypass Trash and force deletion.

Definition

DELETE /wp/v2/template-parts/<id>?)[\/\w%-]+)

Example Request

$ curl -X DELETE https://example.com/wp-json/wp/v2/template-parts/<id>?)[\/\w%-]+)

Templates

Schema

The schema defines all the fields that exist within a template record. Any response from these endpoints can be expected to contain the fields below unless the `_filter` query parameter is used or the schema field only appears in a specific context.

id ID of template.

JSON data type: string

Read only

Context: embed, view, edit

slug Unique slug identifying the template.

JSON data type: string

Context: embed, view, edit

theme Theme identifier for the template.

JSON data type: string

Context: embed, view, edit

type Type of template.

JSON data type: string

Context: embed, view, edit

source Source of template

JSON data type: string

Read only

Context: embed, view, edit

origin Source of a customized template

JSON data type: string

Read only

Context: embed, view, edit

content Content of template.

JSON data type: object or string

Context: embed, view, edit

title Title of template.

JSON data type: object or string

Context: embed, view, edit

description Description of template.

JSON data type: string

Context: embed, view, edit

status Status of template.

JSON data type: string

Context: embed, view, edit

One of: publish, future, draft, pending, private

wp_id Post ID.

JSON data type: integer

Read only

Context: embed, view, edit

has_theme_file Theme file exists.

JSON data type: bool

Read only

Context: embed, view, edit

author The ID for the author of the template.

JSON data type: integer

Context: view, edit, embed

modified The date the template was last modified, in the site’s timezone.

JSON data type: string,
Format: datetime (details)

Read only

Context: view, edit

is_custom Whether a template is a custom template.

JSON data type: bool

Read only

Context: embed, view, edit

Retrieve a Template

Definition & Example Request

GET /wp/v2/templates

Query this endpoint to retrieve a specific template record.

$ curl https://example.com/wp-json/wp/v2/templates

Arguments

context Scope under which the request is made; determines fields present in response.

Default: view

One of: view, embed, edit

wp_id Limit to the specified post id.
area Limit to the specified template part area.
post_type Post type to get the templates for.

Create a Template

Arguments

slug Unique slug identifying the template.

Required: 1

theme Theme identifier for the template.
type Type of template.
content Content of template.
title Title of template.
description Description of template.
status Status of template.

Default: publish

One of: publish, future, draft, pending, private

author The ID for the author of the template.

Definition

POST /wp/v2/templates

Retrieve a Template

Definition & Example Request

GET /wp/v2/templates/<id>?)[\/\w%-]+)

Query this endpoint to retrieve a specific template record.

$ curl https://example.com/wp-json/wp/v2/templates/<id>?)[\/\w%-]+)

Arguments

id The id of a template
context Scope under which the request is made; determines fields present in response.

Default: view

One of: view, embed, edit

Update a Template

Arguments

id The id of a template
slug Unique slug identifying the template.
theme Theme identifier for the template.
type Type of template.
content Content of template.
title Title of template.
description Description of template.
status Status of template.
One of: publish, future, draft, pending, private
author The ID for the author of the template.

Definition

POST /wp/v2/templates/<id>?)[\/\w%-]+)

Example Request

Delete a Template

Arguments

id The id of a template
force Whether to bypass Trash and force deletion.

Definition

DELETE /wp/v2/templates/<id>?)[\/\w%-]+)

Example Request

$ curl -X DELETE https://example.com/wp-json/wp/v2/templates/<id>?)[\/\w%-]+)

Posts

Schema

The schema defines all the fields that exist within a post record. Any response from these endpoints can be expected to contain the fields below unless the `_filter` query parameter is used or the schema field only appears in a specific context.

date The date the post was published, in the site’s timezone.

JSON data type: string or null,
Format: datetime (details)

Context: view, edit, embed

date_gmt The date the post was published, as GMT.

JSON data type: string or null,
Format: datetime (details)

Context: view, edit

guid The globally unique identifier for the post.

JSON data type: object

Read only

Context: view, edit

id Unique identifier for the post.

JSON data type: integer

Read only

Context: view, edit, embed

link URL to the post.

JSON data type: string,
Format: uri

Read only

Context: view, edit, embed

modified The date the post was last modified, in the site’s timezone.

JSON data type: string,
Format: datetime (details)

Read only

Context: view, edit

modified_gmt The date the post was last modified, as GMT.

JSON data type: string,
Format: datetime (details)

Read only

Context: view, edit

slug An alphanumeric identifier for the post unique to its type.

JSON data type: string

Context: view, edit, embed

status A named status for the post.

JSON data type: string

Context: view, edit

One of: publish, future, draft, pending, private

type Type of post.

JSON data type: string

Read only

Context: view, edit, embed

password A password to protect access to the content and excerpt.

JSON data type: string

Context: edit

generated_slug Slug automatically generated from the post title.

JSON data type: string

Read only

Context: edit

title The title for the post.

JSON data type: object

Context: view, edit, embed

content The content for the post.

JSON data type: object

Context: view, edit

author The ID for the author of the post.

JSON data type: integer

Context: view, edit, embed

excerpt The excerpt for the post.

JSON data type: object

Context: view, edit, embed

comment_status Whether or not comments are open on the post.

JSON data type: string

Context: view, edit

One of: open, closed

ping_status Whether or not the post can be pinged.

JSON data type: string

Context: view, edit

One of: open, closed

format The format for the post.

JSON data type: string

Context: view, edit

One of: standard, aside, chat, gallery, link, image, quote, status, video, audio

meta Meta fields.

JSON data type: object

Context: view, edit

sticky Whether or not the post should be treated as sticky.

JSON data type: boolean

Context: view, edit

template The theme file to use to display the post.

JSON data type: string

Context: view, edit

categories The terms assigned to the post in the category taxonomy.

JSON data type: array

Context: view, edit

tags The terms assigned to the post in the post_tag taxonomy.

JSON data type: array

Context: view, edit

List Posts

Query this endpoint to retrieve a collection of posts. The response you receive can be controlled and filtered using the URL query parameters below.

Definition

GET /wp/v2/posts

Example Request

$ curl https://example.com/wp-json/wp/v2/posts

Arguments

context Scope under which the request is made; determines fields present in response.

Default: view

One of: view, embed, edit

page Current page of the collection.

Default: 1

per_page Maximum number of items to be returned in result set.

Default: 10

search Limit results to those matching a string.
after Limit response to posts published after a given ISO8601 compliant date.
modified_after Limit response to posts modified after a given ISO8601 compliant date.
author Limit result set to posts assigned to specific authors.
author_exclude Ensure result set excludes posts assigned to specific authors.
before Limit response to posts published before a given ISO8601 compliant date.
modified_before Limit response to posts modified before a given ISO8601 compliant date.
exclude Ensure result set excludes specific IDs.
include Limit result set to specific IDs.
offset Offset the result set by a specific number of items.
order Order sort attribute ascending or descending.

Default: desc

One of: asc, desc

orderby Sort collection by post attribute.

Default: date

One of: author, date, id, include, modified, parent, relevance, slug, include_slugs, title

search_columns Array of column names to be searched.
slug Limit result set to posts with one or more specific slugs.
status Limit result set to posts assigned one or more statuses.

Default: publish

tax_relation Limit result set based on relationship between multiple taxonomies.
One of: AND, OR
categories Limit result set to items with specific terms assigned in the categories taxonomy.
categories_exclude Limit result set to items except those with specific terms assigned in the categories taxonomy.
tags Limit result set to items with specific terms assigned in the tags taxonomy.
tags_exclude Limit result set to items except those with specific terms assigned in the tags taxonomy.
sticky Limit result set to items that are sticky.

Create a Post

Arguments

date The date the post was published, in the site’s timezone.
date_gmt The date the post was published, as GMT.
slug An alphanumeric identifier for the post unique to its type.
status A named status for the post.
One of: publish, future, draft, pending, private
password A password to protect access to the content and excerpt.
title The title for the post.
content The content for the post.
author The ID for the author of the post.
excerpt The excerpt for the post.
featured_media The ID of the featured media for the post.
comment_status Whether or not comments are open on the post.
One of: open, closed
ping_status Whether or not the post can be pinged.
One of: open, closed
format The format for the post.
One of: standard, aside, chat, gallery, link, image, quote, status, video, audio
meta Meta fields.
sticky Whether or not the post should be treated as sticky.
template The theme file to use to display the post.
categories The terms assigned to the post in the category taxonomy.
tags The terms assigned to the post in the post_tag taxonomy.

Definition

POST /wp/v2/posts

Retrieve a Post

Definition & Example Request

GET /wp/v2/posts/<id>

Query this endpoint to retrieve a specific post record.

$ curl https://example.com/wp-json/wp/v2/posts/<id>

Arguments

id Unique identifier for the post.
context Scope under which the request is made; determines fields present in response.

Default: view

One of: view, embed, edit

password The password for the post if it is password protected.

Update a Post

Arguments

id Unique identifier for the post.
date The date the post was published, in the site’s timezone.
date_gmt The date the post was published, as GMT.
slug An alphanumeric identifier for the post unique to its type.
status A named status for the post.
One of: publish, future, draft, pending, private
password A password to protect access to the content and excerpt.
title The title for the post.
content The content for the post.
author The ID for the author of the post.
excerpt The excerpt for the post.
featured_media The ID of the featured media for the post.
comment_status Whether or not comments are open on the post.
One of: open, closed
ping_status Whether or not the post can be pinged.
One of: open, closed
format The format for the post.
One of: standard, aside, chat, gallery, link, image, quote, status, video, audio
meta Meta fields.
sticky Whether or not the post should be treated as sticky.
template The theme file to use to display the post.
categories The terms assigned to the post in the category taxonomy.
tags The terms assigned to the post in the post_tag taxonomy.

Definition

POST /wp/v2/posts/<id>

Example Request

$ curl -X POST https://example.com/wp-json/wp/v2/posts/<id> -d '{"title":"My New Title"}'\

Delete a Post

Arguments

id Unique identifier for the post.
force Whether to bypass Trash and force deletion.

Definition

DELETE /wp/v2/posts/<id>

Example Request

$ curl -X DELETE https://example.com/wp-json/wp/v2/posts/<id>

Post Revisions

Schema

The schema defines all the fields that exist within a post revision record. Any response from these endpoints can be expected to contain the fields below unless the `_filter` query parameter is used or the schema field only appears in a specific context.

author The ID for the author of the revision.

JSON data type: integer

Context: view, edit, embed

date The date the revision was published, in the site’s timezone.

JSON data type: string,
Format: datetime (details)

Context: view, edit, embed

date_gmt The date the revision was published, as GMT.

JSON data type: string,
Format: datetime (details)

Context: view, edit

guid The globally unique identifier for the post.

JSON data type: object

Read only

Context: view, edit

id Unique identifier for the revision.

JSON data type: integer

Context: view, edit, embed

modified The date the revision was last modified, in the site’s timezone.

JSON data type: string,
Format: datetime (details)

Context: view, edit

modified_gmt The date the revision was last modified, as GMT.

JSON data type: string,
Format: datetime (details)

Context: view, edit

parent The ID for the parent of the revision.

JSON data type: integer

Context: view, edit, embed

slug An alphanumeric identifier for the revision unique to its type.

JSON data type: string

Context: view, edit, embed

title The title for the post.

JSON data type: object

Context: view, edit, embed

content The content for the post.

JSON data type: object

Context: view, edit

excerpt The excerpt for the post.

JSON data type: object

Context: view, edit, embed

List Post Revisions

Query this endpoint to retrieve a collection of post revisions. The response you receive can be controlled and filtered using the URL query parameters below.

Definition

GET /wp/v2/posts/<parent>/revisions

Example Request

$ curl https://example.com/wp-json/wp/v2/posts/<parent>/revisions

Arguments

parent The ID for the parent of the revision.
context Scope under which the request is made; determines fields present in response.

Default: view

One of: view, embed, edit

page Current page of the collection.

Default: 1

per_page Maximum number of items to be returned in result set.
search Limit results to those matching a string.
exclude Ensure result set excludes specific IDs.
include Limit result set to specific IDs.
offset Offset the result set by a specific number of items.
order Order sort attribute ascending or descending.

Default: desc

One of: asc, desc

orderby Sort collection by object attribute.

Default: date

One of: date, id, include, relevance, slug, include_slugs, title

Retrieve a Post Revision

Definition & Example Request

GET /wp/v2/posts/<parent>/revisions/<id>

Query this endpoint to retrieve a specific post revision record.

$ curl https://example.com/wp-json/wp/v2/posts/<parent>/revisions/<id>

Arguments

parent The ID for the parent of the revision.
id Unique identifier for the revision.
context Scope under which the request is made; determines fields present in response.

Default: view

One of: view, embed, edit

Delete a Post Revision

Arguments

parent The ID for the parent of the revision.
id Unique identifier for the revision.
force Required to be true, as revisions do not support trashing.

Definition

DELETE /wp/v2/posts/<parent>/revisions/<id>

Example Request

$ curl -X DELETE https://example.com/wp-json/wp/v2/posts/<parent>/revisions/<id>

Retrieve a Post Revision

Definition & Example Request

GET /wp/v2/posts/<id>/autosaves

Query this endpoint to retrieve a specific post revision record.

$ curl https://example.com/wp-json/wp/v2/posts/<id>/autosaves

Arguments

parent The ID for the parent of the autosave.
context Scope under which the request is made; determines fields present in response.

Default: view

One of: view, embed, edit

Create a Post Revision

Arguments

parent The ID for the parent of the autosave.
date The date the post was published, in the site’s timezone.
date_gmt The date the post was published, as GMT.
slug An alphanumeric identifier for the post unique to its type.
status A named status for the post.
One of: publish, future, draft, pending, private
password A password to protect access to the content and excerpt.
title The title for the post.
content The content for the post.
author The ID for the author of the post.
excerpt The excerpt for the post.
featured_media The ID of the featured media for the post.
comment_status Whether or not comments are open on the post.
One of: open, closed
ping_status Whether or not the post can be pinged.
One of: open, closed
format The format for the post.
One of: standard, aside, chat, gallery, link, image, quote, status, video, audio
meta Meta fields.
sticky Whether or not the post should be treated as sticky.
template The theme file to use to display the post.
categories The terms assigned to the post in the category taxonomy.
tags The terms assigned to the post in the post_tag taxonomy.

Definition

POST /wp/v2/posts/<id>/autosaves

Retrieve a Post Revision

Definition & Example Request

GET /wp/v2/posts/<parent>/autosaves/<id>

Query this endpoint to retrieve a specific post revision record.

$ curl https://example.com/wp-json/wp/v2/posts/<parent>/autosaves/<id>

Arguments

parent The ID for the parent of the autosave.
id The ID for the autosave.
context Scope under which the request is made; determines fields present in response.

Default: view

One of: view, embed, edit

Pages

Schema

The schema defines all the fields that exist within a page record. Any response from these endpoints can be expected to contain the fields below unless the `_filter` query parameter is used or the schema field only appears in a specific context.

date The date the post was published, in the site’s timezone.

JSON data type: string or null,
Format: datetime (details)

Context: view, edit, embed

date_gmt The date the post was published, as GMT.

JSON data type: string or null,
Format: datetime (details)

Context: view, edit

guid The globally unique identifier for the post.

JSON data type: object

Read only

Context: view, edit

id Unique identifier for the post.

JSON data type: integer

Read only

Context: view, edit, embed

link URL to the post.

JSON data type: string,
Format: uri

Read only

Context: view, edit, embed

modified The date the post was last modified, in the site’s timezone.

JSON data type: string,
Format: datetime (details)

Read only

Context: view, edit

modified_gmt The date the post was last modified, as GMT.

JSON data type: string,
Format: datetime (details)

Read only

Context: view, edit

slug An alphanumeric identifier for the post unique to its type.

JSON data type: string

Context: view, edit, embed

status A named status for the post.

JSON data type: string

Context: view, edit

One of: publish, future, draft, pending, private

type Type of post.

JSON data type: string

Read only

Context: view, edit, embed

password A password to protect access to the content and excerpt.

JSON data type: string

Context: edit

generated_slug Slug automatically generated from the post title.

JSON data type: string

Read only

Context: edit

parent The ID for the parent of the post.

JSON data type: integer

Context: view, edit

title The title for the post.

JSON data type: object

Context: view, edit, embed

content The content for the post.

JSON data type: object

Context: view, edit

author The ID for the author of the post.

JSON data type: integer

Context: view, edit, embed

excerpt The excerpt for the post.

JSON data type: object

Context: view, edit, embed

comment_status Whether or not comments are open on the post.

JSON data type: string

Context: view, edit

One of: open, closed

ping_status Whether or not the post can be pinged.

JSON data type: string

Context: view, edit

One of: open, closed

menu_order The order of the post in relation to other posts.

JSON data type: integer

Context: view, edit

meta Meta fields.

JSON data type: object

Context: view, edit

template The theme file to use to display the post.

JSON data type: string

Context: view, edit

List Pages

Query this endpoint to retrieve a collection of pages. The response you receive can be controlled and filtered using the URL query parameters below.

Definition

GET /wp/v2/pages

Example Request

$ curl https://example.com/wp-json/wp/v2/pages

Arguments

context Scope under which the request is made; determines fields present in response.

Default: view

One of: view, embed, edit

page Current page of the collection.

Default: 1

per_page Maximum number of items to be returned in result set.

Default: 10

search Limit results to those matching a string.
after Limit response to posts published after a given ISO8601 compliant date.
modified_after Limit response to posts modified after a given ISO8601 compliant date.
author Limit result set to posts assigned to specific authors.
author_exclude Ensure result set excludes posts assigned to specific authors.
before Limit response to posts published before a given ISO8601 compliant date.
modified_before Limit response to posts modified before a given ISO8601 compliant date.
exclude Ensure result set excludes specific IDs.
include Limit result set to specific IDs.
menu_order Limit result set to posts with a specific menu_order value.
offset Offset the result set by a specific number of items.
order Order sort attribute ascending or descending.

Default: desc

One of: asc, desc

orderby Sort collection by post attribute.

Default: date

One of: author, date, id, include, modified, parent, relevance, slug, include_slugs, title, menu_order

parent Limit result set to items with particular parent IDs.
parent_exclude Limit result set to all items except those of a particular parent ID.
search_columns Array of column names to be searched.
slug Limit result set to posts with one or more specific slugs.
status Limit result set to posts assigned one or more statuses.

Default: publish

Create a Page

Arguments

date The date the post was published, in the site’s timezone.
date_gmt The date the post was published, as GMT.
slug An alphanumeric identifier for the post unique to its type.
status A named status for the post.
One of: publish, future, draft, pending, private
password A password to protect access to the content and excerpt.
parent The ID for the parent of the post.
title The title for the post.
content The content for the post.
author The ID for the author of the post.
excerpt The excerpt for the post.
featured_media The ID of the featured media for the post.
comment_status Whether or not comments are open on the post.
One of: open, closed
ping_status Whether or not the post can be pinged.
One of: open, closed
menu_order The order of the post in relation to other posts.
meta Meta fields.
template The theme file to use to display the post.

Definition

POST /wp/v2/pages

Retrieve a Page

Definition & Example Request

GET /wp/v2/pages/<id>

Query this endpoint to retrieve a specific page record.

$ curl https://example.com/wp-json/wp/v2/pages/<id>

Arguments

id Unique identifier for the post.
context Scope under which the request is made; determines fields present in response.

Default: view

One of: view, embed, edit

password The password for the post if it is password protected.

Update a Page

Arguments

id Unique identifier for the post.
date The date the post was published, in the site’s timezone.
date_gmt The date the post was published, as GMT.
slug An alphanumeric identifier for the post unique to its type.
status A named status for the post.
One of: publish, future, draft, pending, private
password A password to protect access to the content and excerpt.
parent The ID for the parent of the post.
title The title for the post.
content The content for the post.
author The ID for the author of the post.
excerpt The excerpt for the post.
featured_media The ID of the featured media for the post.
comment_status Whether or not comments are open on the post.
One of: open, closed
ping_status Whether or not the post can be pinged.
One of: open, closed
menu_order The order of the post in relation to other posts.
meta Meta fields.
template The theme file to use to display the post.

Definition

POST /wp/v2/pages/<id>

Example Request

Delete a Page

Arguments

id Unique identifier for the post.
force Whether to bypass Trash and force deletion.

Definition

DELETE /wp/v2/pages/<id>

Example Request

$ curl -X DELETE https://example.com/wp-json/wp/v2/pages/<id>

Site Settings

Schema

The schema defines all the fields that exist within a Site Setting record. Any response from these endpoints can be expected to contain the fields below unless the `_filter` query parameter is used or the schema field only appears in a specific context.

title Site title.

JSON data type: string

Context:

description Site tagline.

JSON data type: string

Context:

url Site URL.

JSON data type: string,
Format: uri

Context:

email This address is used for admin purposes, like new user notification.

JSON data type: string,
Format: email

Context:

timezone A city in the same timezone as you.

JSON data type: string

Context:

date_format A date format for all date strings.

JSON data type: string

Context:

time_format A time format for all time strings.

JSON data type: string

Context:

start_of_week A day number of the week that the week should start on.

JSON data type: integer

Context:

language WordPress locale code.

JSON data type: string

Context:

use_smilies Convert emoticons like :-) and :-P to graphics on display.

JSON data type: boolean

Context:

default_category Default post category.

JSON data type: integer

Context:

default_post_format Default post format.

JSON data type: string

Context:

posts_per_page Blog pages show at most.

JSON data type: integer

Context:

show_on_front What to show on the front page

JSON data type: string

Context:

page_on_front The ID of the page that should be displayed on the front page

JSON data type: integer

Context:

page_for_posts The ID of the page that should display the latest posts

JSON data type: integer

Context:

default_ping_status Allow link notifications from other blogs (pingbacks and trackbacks) on new articles.

JSON data type: string

Context:

One of: open, closed

default_comment_status Allow people to submit comments on new posts.

JSON data type: string

Context:

One of: open, closed

site_logo Site logo.

JSON data type: integer

Context:

site_icon Site icon.

JSON data type: integer

Context:

Retrieve a Site Setting

Definition & Example Request

GET /wp/v2/settings

Query this endpoint to retrieve a specific Site Setting record.

$ curl https://example.com/wp-json/wp/v2/settings

There are no arguments for this endpoint.

Update a Site Setting

Arguments

title Site title.
description Site tagline.
url Site URL.
email This address is used for admin purposes, like new user notification.
timezone A city in the same timezone as you.
date_format A date format for all date strings.
time_format A time format for all time strings.
start_of_week A day number of the week that the week should start on.
language WordPress locale code.
use_smilies Convert emoticons like :-) and :-P to graphics on display.
default_category Default post category.
default_post_format Default post format.
posts_per_page Blog pages show at most.
show_on_front What to show on the front page
page_on_front The ID of the page that should be displayed on the front page
page_for_posts The ID of the page that should display the latest posts
default_ping_status Allow link notifications from other blogs (pingbacks and trackbacks) on new articles.
One of: open, closed
default_comment_status Allow people to submit comments on new posts.
One of: open, closed
site_logo Site logo.
site_icon Site icon.

Definition

POST /wp/v2/settings

Example Request

Users

Schema

The schema defines all the fields that exist within a user record. Any response from these endpoints can be expected to contain the fields below unless the `_filter` query parameter is used or the schema field only appears in a specific context.

id Unique identifier for the user.

JSON data type: integer

Read only

Context: embed, view, edit

username Login name for the user.

JSON data type: string

Context: edit

name Display name for the user.

JSON data type: string

Context: embed, view, edit

first_name First name for the user.

JSON data type: string

Context: edit

last_name Last name for the user.

JSON data type: string

Context: edit

email The email address for the user.

JSON data type: string,
Format: email

Context: edit

url URL of the user.

JSON data type: string,
Format: uri

Context: embed, view, edit

description Description of the user.

JSON data type: string

Context: embed, view, edit

locale Locale for the user.

JSON data type: string

Context: edit

One of: , en_US

nickname The nickname for the user.

JSON data type: string

Context: edit

slug An alphanumeric identifier for the user.

JSON data type: string

Context: embed, view, edit

registered_date Registration date for the user.

JSON data type: string,
Format: datetime (details)

Read only

Context: edit

roles Roles assigned to the user.

JSON data type: array

Context: edit

password Password for the user (never included).

JSON data type: string

Context:

capabilities All capabilities assigned to the user.

JSON data type: object

Read only

Context: edit

extra_capabilities Any extra capabilities assigned to the user.

JSON data type: object

Read only

Context: edit

avatar_urls Avatar URLs for the user.

JSON data type: object

Read only

Context: embed, view, edit

meta Meta fields.

JSON data type: object

Context: view, edit

List Users

Query this endpoint to retrieve a collection of users. The response you receive can be controlled and filtered using the URL query parameters below.

Definition

GET /wp/v2/users

Example Request

$ curl https://example.com/wp-json/wp/v2/users

Arguments

context Scope under which the request is made; determines fields present in response.

Default: view

One of: view, embed, edit

page Current page of the collection.

Default: 1

per_page Maximum number of items to be returned in result set.

Default: 10

search Limit results to those matching a string.
exclude Ensure result set excludes specific IDs.
include Limit result set to specific IDs.
offset Offset the result set by a specific number of items.
order Order sort attribute ascending or descending.

Default: asc

One of: asc, desc

orderby Sort collection by user attribute.

Default: name

One of: id, include, name, registered_date, slug, include_slugs, email, url

slug Limit result set to users with one or more specific slugs.
roles Limit result set to users matching at least one specific role provided. Accepts csv list or single role.
capabilities Limit result set to users matching at least one specific capability provided. Accepts csv list or single capability.
who Limit result set to users who are considered authors.
One of: authors
has_published_posts Limit result set to users who have published posts.

Create a User

Arguments

username Login name for the user.

Required: 1

name Display name for the user.
first_name First name for the user.
last_name Last name for the user.
email The email address for the user.

Required: 1

url URL of the user.
description Description of the user.
locale Locale for the user.
One of: , en_US
nickname The nickname for the user.
slug An alphanumeric identifier for the user.
roles Roles assigned to the user.
password Password for the user (never included).

Required: 1

meta Meta fields.

Definition

POST /wp/v2/users

Retrieve a User

Definition & Example Request

GET /wp/v2/users/<id>

Query this endpoint to retrieve a specific user record.

$ curl https://example.com/wp-json/wp/v2/users/<id>

Arguments

id Unique identifier for the user.
context Scope under which the request is made; determines fields present in response.

Default: view

One of: view, embed, edit

Update a User

Arguments

id Unique identifier for the user.
username Login name for the user.
name Display name for the user.
first_name First name for the user.
last_name Last name for the user.
email The email address for the user.
url URL of the user.
description Description of the user.
locale Locale for the user.
One of: , en_US
nickname The nickname for the user.
slug An alphanumeric identifier for the user.
roles Roles assigned to the user.
password Password for the user (never included).
meta Meta fields.

Definition

POST /wp/v2/users/<id>

Example Request

Delete a User

Arguments

id Unique identifier for the user.
force Required to be true, as users do not support trashing.
reassign Reassign the deleted user’s posts and links to this user ID.

Required: 1

Definition

DELETE /wp/v2/users/<id>

Example Request

$ curl -X DELETE https://example.com/wp-json/wp/v2/users/<id>

Retrieve a User

Definition & Example Request

GET /wp/v2/users/me

Query this endpoint to retrieve a specific user record.

$ curl https://example.com/wp-json/wp/v2/users/me

Arguments

context Scope under which the request is made; determines fields present in response.

Default: view

One of: view, embed, edit

Update a User

Arguments

username Login name for the user.
name Display name for the user.
first_name First name for the user.
last_name Last name for the user.
email The email address for the user.
url URL of the user.
description Description of the user.
locale Locale for the user.
One of: , en_US
nickname The nickname for the user.
slug An alphanumeric identifier for the user.
roles Roles assigned to the user.
password Password for the user (never included).
meta Meta fields.

Definition

POST /wp/v2/users/me

Example Request

Delete a User

Arguments

force Required to be true, as users do not support trashing.
reassign Reassign the deleted user’s posts and links to this user ID.

Required: 1

Definition

DELETE /wp/v2/users/me

Example Request

$ curl -X DELETE https://example.com/wp-json/wp/v2/users/me

Media

Schema

The schema defines all the fields that exist within a Media Item record. Any response from these endpoints can be expected to contain the fields below unless the `_filter` query parameter is used or the schema field only appears in a specific context.

date The date the post was published, in the site’s timezone.

JSON data type: string or null,
Format: datetime (details)

Context: view, edit, embed

date_gmt The date the post was published, as GMT.

JSON data type: string or null,
Format: datetime (details)

Context: view, edit

guid The globally unique identifier for the post.

JSON data type: object

Read only

Context: view, edit

id Unique identifier for the post.

JSON data type: integer

Read only

Context: view, edit, embed

link URL to the post.

JSON data type: string,
Format: uri

Read only

Context: view, edit, embed

modified The date the post was last modified, in the site’s timezone.

JSON data type: string,
Format: datetime (details)

Read only

Context: view, edit

modified_gmt The date the post was last modified, as GMT.

JSON data type: string,
Format: datetime (details)

Read only

Context: view, edit

slug An alphanumeric identifier for the post unique to its type.

JSON data type: string

Context: view, edit, embed

status A named status for the post.

JSON data type: string

Context: view, edit

One of: publish, future, draft, pending, private

type Type of post.

JSON data type: string

Read only

Context: view, edit, embed

generated_slug Slug automatically generated from the post title.

JSON data type: string

Read only

Context: edit

title The title for the post.

JSON data type: object

Context: view, edit, embed

author The ID for the author of the post.

JSON data type: integer

Context: view, edit, embed

comment_status Whether or not comments are open on the post.

JSON data type: string

Context: view, edit

One of: open, closed

ping_status Whether or not the post can be pinged.

JSON data type: string

Context: view, edit

One of: open, closed

meta Meta fields.

JSON data type: object

Context: view, edit

template The theme file to use to display the post.

JSON data type: string

Context: view, edit

alt_text Alternative text to display when attachment is not displayed.

JSON data type: string

Context: view, edit, embed

caption The attachment caption.

JSON data type: object

Context: view, edit, embed

description The attachment description.

JSON data type: object

Context: view, edit

media_type Attachment type.

JSON data type: string

Read only

Context: view, edit, embed

One of: image, file

mime_type The attachment MIME type.

JSON data type: string

Read only

Context: view, edit, embed

media_details Details about the media file, specific to its type.

JSON data type: object

Read only

Context: view, edit, embed

post The ID for the associated post of the attachment.

JSON data type: integer

Context: view, edit

source_url URL to the original attachment file.

JSON data type: string,
Format: uri

Read only

Context: view, edit, embed

missing_image_sizes List of the missing image sizes of the attachment.

JSON data type: array

Read only

Context: edit

List Media

Query this endpoint to retrieve a collection of media. The response you receive can be controlled and filtered using the URL query parameters below.

Definition

GET /wp/v2/media

Example Request

$ curl https://example.com/wp-json/wp/v2/media

Arguments

context Scope under which the request is made; determines fields present in response.

Default: view

One of: view, embed, edit

page Current page of the collection.

Default: 1

per_page Maximum number of items to be returned in result set.

Default: 10

search Limit results to those matching a string.
after Limit response to posts published after a given ISO8601 compliant date.
modified_after Limit response to posts modified after a given ISO8601 compliant date.
author Limit result set to posts assigned to specific authors.
author_exclude Ensure result set excludes posts assigned to specific authors.
before Limit response to posts published before a given ISO8601 compliant date.
modified_before Limit response to posts modified before a given ISO8601 compliant date.
exclude Ensure result set excludes specific IDs.
include Limit result set to specific IDs.
offset Offset the result set by a specific number of items.
order Order sort attribute ascending or descending.

Default: desc

One of: asc, desc

orderby Sort collection by post attribute.

Default: date

One of: author, date, id, include, modified, parent, relevance, slug, include_slugs, title

parent Limit result set to items with particular parent IDs.
parent_exclude Limit result set to all items except those of a particular parent ID.
search_columns Array of column names to be searched.
slug Limit result set to posts with one or more specific slugs.
status Limit result set to posts assigned one or more statuses.

Default: inherit

media_type Limit result set to attachments of a particular media type.
One of: image, video, text, application, audio
mime_type Limit result set to attachments of a particular MIME type.

Create a Media Item

Arguments

date The date the post was published, in the site’s timezone.
date_gmt The date the post was published, as GMT.
slug An alphanumeric identifier for the post unique to its type.
status A named status for the post.
One of: publish, future, draft, pending, private
title The title for the post.
author The ID for the author of the post.
comment_status Whether or not comments are open on the post.
One of: open, closed
ping_status Whether or not the post can be pinged.
One of: open, closed
meta Meta fields.
template The theme file to use to display the post.
alt_text Alternative text to display when attachment is not displayed.
caption The attachment caption.
description The attachment description.
post The ID for the associated post of the attachment.

Definition

POST /wp/v2/media

Retrieve a Media Item

Definition & Example Request

GET /wp/v2/media/<id>

Query this endpoint to retrieve a specific Media Item record.

$ curl https://example.com/wp-json/wp/v2/media/<id>

Arguments

id Unique identifier for the post.
context Scope under which the request is made; determines fields present in response.

Default: view

One of: view, embed, edit

Update a Media Item

Arguments

id Unique identifier for the post.
date The date the post was published, in the site’s timezone.
date_gmt The date the post was published, as GMT.
slug An alphanumeric identifier for the post unique to its type.
status A named status for the post.
One of: publish, future, draft, pending, private
title The title for the post.
author The ID for the author of the post.
comment_status Whether or not comments are open on the post.
One of: open, closed
ping_status Whether or not the post can be pinged.
One of: open, closed
meta Meta fields.
template The theme file to use to display the post.
alt_text Alternative text to display when attachment is not displayed.
caption The attachment caption.
description The attachment description.
post The ID for the associated post of the attachment.

Definition

POST /wp/v2/media/<id>

Example Request

Delete a Media Item

Arguments

id Unique identifier for the post.
force Whether to bypass Trash and force deletion.

Definition

DELETE /wp/v2/media/<id>

Example Request

$ curl -X DELETE https://example.com/wp-json/wp/v2/media/<id>

Types

Schema

The schema defines all the fields that exist within a type record. Any response from these endpoints can be expected to contain the fields below unless the `_filter` query parameter is used or the schema field only appears in a specific context.

capabilities All capabilities used by the post type.

JSON data type: object

Read only

Context: edit

description A human-readable description of the post type.

JSON data type: string

Read only

Context: view, edit

hierarchical Whether or not the post type should have children.

JSON data type: boolean

Read only

Context: view, edit

viewable Whether or not the post type can be viewed.

JSON data type: boolean

Read only

Context: edit

labels Human-readable labels for the post type for various contexts.

JSON data type: object

Read only

Context: edit

name The title for the post type.

JSON data type: string

Read only

Context: view, edit, embed

slug An alphanumeric identifier for the post type.

JSON data type: string

Read only

Context: view, edit, embed

supports All features, supported by the post type.

JSON data type: object

Read only

Context: edit

has_archive If the value is a string, the value will be used as the archive slug. If the value is false the post type has no archive.

JSON data type: string or boolean

Read only

Context: view, edit

taxonomies Taxonomies associated with post type.

JSON data type: array

Read only

Context: view, edit

rest_base REST base route for the post type.

JSON data type: string

Read only

Context: view, edit, embed

rest_namespace REST route’s namespace for the post type.

JSON data type: string

Read only

Context: view, edit, embed

visibility The visibility settings for the post type.

JSON data type: object

Read only

Context: edit

icon The icon for the post type.

JSON data type: string or null

Read only

Context: view, edit, embed

Retrieve a Type

Definition & Example Request

GET /wp/v2/types

Query this endpoint to retrieve a specific type record.

$ curl https://example.com/wp-json/wp/v2/types

Arguments

context Scope under which the request is made; determines fields present in response.

Default: view

One of: view, embed, edit

Retrieve a Type

Definition & Example Request

GET /wp/v2/types/<type>

Query this endpoint to retrieve a specific type record.

$ curl https://example.com/wp-json/wp/v2/types/<type>

Arguments

type An alphanumeric identifier for the post type.
context Scope under which the request is made; determines fields present in response.

Default: view

One of: view, embed, edit

Categories

Schema

The schema defines all the fields that exist within a category record. Any response from these endpoints can be expected to contain the fields below unless the `_filter` query parameter is used or the schema field only appears in a specific context.

id Unique identifier for the term.

JSON data type: integer

Read only

Context: view, embed, edit

count Number of published posts for the term.

JSON data type: integer

Read only

Context: view, edit

description HTML description of the term.

JSON data type: string

Context: view, edit

name HTML title for the term.

JSON data type: string

Context: view, embed, edit

slug An alphanumeric identifier for the term unique to its type.

JSON data type: string

Context: view, embed, edit

taxonomy Type attribution for the term.

JSON data type: string

Read only

Context: view, embed, edit

One of: category

parent The parent term ID.

JSON data type: integer

Context: view, edit

meta Meta fields.

JSON data type: object

Context: view, edit

List Categories

Query this endpoint to retrieve a collection of categories. The response you receive can be controlled and filtered using the URL query parameters below.

Definition

GET /wp/v2/categories

Example Request

$ curl https://example.com/wp-json/wp/v2/categories

Arguments

context Scope under which the request is made; determines fields present in response.

Default: view

One of: view, embed, edit

page Current page of the collection.

Default: 1

per_page Maximum number of items to be returned in result set.

Default: 10

search Limit results to those matching a string.
exclude Ensure result set excludes specific IDs.
include Limit result set to specific IDs.
order Order sort attribute ascending or descending.

Default: asc

One of: asc, desc

orderby Sort collection by term attribute.

Default: name

One of: id, include, name, slug, include_slugs, term_group, description, count

hide_empty Whether to hide terms not assigned to any posts.
parent Limit result set to terms assigned to a specific parent.
post Limit result set to terms assigned to a specific post.
slug Limit result set to terms with one or more specific slugs.

Create a Category

Arguments

description HTML description of the term.
name HTML title for the term.

Required: 1

slug An alphanumeric identifier for the term unique to its type.
parent The parent term ID.
meta Meta fields.

Definition

POST /wp/v2/categories

Retrieve a Category

Definition & Example Request

GET /wp/v2/categories/<id>

Query this endpoint to retrieve a specific category record.

$ curl https://example.com/wp-json/wp/v2/categories/<id>

Arguments

id Unique identifier for the term.
context Scope under which the request is made; determines fields present in response.

Default: view

One of: view, embed, edit

Update a Category

Arguments

id Unique identifier for the term.
description HTML description of the term.
name HTML title for the term.
slug An alphanumeric identifier for the term unique to its type.
parent The parent term ID.
meta Meta fields.

Definition

POST /wp/v2/categories/<id>

Example Request

Delete a Category

Arguments

id Unique identifier for the term.
force Required to be true, as terms do not support trashing.

Definition

DELETE /wp/v2/categories/<id>

Example Request

$ curl -X DELETE https://example.com/wp-json/wp/v2/categories/<id>

Statuses

Schema

The schema defines all the fields that exist within a status record. Any response from these endpoints can be expected to contain the fields below unless the `_filter` query parameter is used or the schema field only appears in a specific context.

name The title for the status.

JSON data type: string

Read only

Context: embed, view, edit

private Whether posts with this status should be private.

JSON data type: boolean

Read only

Context: edit

protected Whether posts with this status should be protected.

JSON data type: boolean

Read only

Context: edit

public Whether posts of this status should be shown in the front end of the site.

JSON data type: boolean

Read only

Context: view, edit

queryable Whether posts with this status should be publicly-queryable.

JSON data type: boolean

Read only

Context: view, edit

show_in_list Whether to include posts in the edit listing for their post type.

JSON data type: boolean

Read only

Context: edit

slug An alphanumeric identifier for the status.

JSON data type: string

Read only

Context: embed, view, edit

date_floating Whether posts of this status may have floating published dates.

JSON data type: boolean

Read only

Context: view, edit

Retrieve a Status

Definition & Example Request

GET /wp/v2/statuses

Query this endpoint to retrieve a specific status record.

$ curl https://example.com/wp-json/wp/v2/statuses

Arguments

context Scope under which the request is made; determines fields present in response.

Default: view

One of: view, embed, edit

Retrieve a Status

Definition & Example Request

GET /wp/v2/statuses/<status>

Query this endpoint to retrieve a specific status record.

$ curl https://example.com/wp-json/wp/v2/statuses/<status>

Arguments

status An alphanumeric identifier for the status.
context Scope under which the request is made; determines fields present in response.

Default: view

One of: view, embed, edit

Comments

Schema

The schema defines all the fields that exist within a comment record. Any response from these endpoints can be expected to contain the fields below unless the `_filter` query parameter is used or the schema field only appears in a specific context.

id Unique identifier for the comment.

JSON data type: integer

Read only

Context: view, edit, embed

author The ID of the user object, if author was a user.

JSON data type: integer

Context: view, edit, embed

author_email Email address for the comment author.

JSON data type: string,
Format: email

Context: edit

author_ip IP address for the comment author.

JSON data type: string,
Format: ip

Context: edit

author_name Display name for the comment author.

JSON data type: string

Context: view, edit, embed

author_url URL for the comment author.

JSON data type: string,
Format: uri

Context: view, edit, embed

author_user_agent User agent for the comment author.

JSON data type: string

Context: edit

content The content for the comment.

JSON data type: object

Context: view, edit, embed

date The date the comment was published, in the site’s timezone.

JSON data type: string,
Format: datetime (details)

Context: view, edit, embed

date_gmt The date the comment was published, as GMT.

JSON data type: string,
Format: datetime (details)

Context: view, edit

parent The ID for the parent of the comment.

JSON data type: integer

Context: view, edit, embed

post The ID of the associated post object.

JSON data type: integer

Context: view, edit

status State of the comment.

JSON data type: string

Context: view, edit

type Type of the comment.

JSON data type: string

Read only

Context: view, edit, embed

author_avatar_urls Avatar URLs for the comment author.

JSON data type: object

Read only

Context: view, edit, embed

meta Meta fields.

JSON data type: object

Context: view, edit

List Comments

Query this endpoint to retrieve a collection of comments. The response you receive can be controlled and filtered using the URL query parameters below.

Definition

GET /wp/v2/comments

Example Request

$ curl https://example.com/wp-json/wp/v2/comments

Arguments

context Scope under which the request is made; determines fields present in response.

Default: view

One of: view, embed, edit

page Current page of the collection.

Default: 1

per_page Maximum number of items to be returned in result set.

Default: 10

search Limit results to those matching a string.
after Limit response to comments published after a given ISO8601 compliant date.
author Limit result set to comments assigned to specific user IDs. Requires authorization.
author_exclude Ensure result set excludes comments assigned to specific user IDs. Requires authorization.
author_email Limit result set to that from a specific author email. Requires authorization.
before Limit response to comments published before a given ISO8601 compliant date.
exclude Ensure result set excludes specific IDs.
include Limit result set to specific IDs.
offset Offset the result set by a specific number of items.
order Order sort attribute ascending or descending.

Default: desc

One of: asc, desc

orderby Sort collection by comment attribute.

Default: date_gmt

One of: date, date_gmt, id, include, post, parent, type

parent Limit result set to comments of specific parent IDs.
parent_exclude Ensure result set excludes specific parent IDs.
post Limit result set to comments assigned to specific post IDs.
status Limit result set to comments assigned a specific status. Requires authorization.

Default: approve

type Limit result set to comments assigned a specific type. Requires authorization.

Default: comment

password The password for the post if it is password protected.

Create a Comment

Arguments

author The ID of the user object, if author was a user.
author_email Email address for the comment author.
author_ip IP address for the comment author.
author_name Display name for the comment author.
author_url URL for the comment author.
author_user_agent User agent for the comment author.
content The content for the comment.
date The date the comment was published, in the site’s timezone.
date_gmt The date the comment was published, as GMT.
parent The ID for the parent of the comment.
post The ID of the associated post object.
status State of the comment.
meta Meta fields.

Definition

POST /wp/v2/comments

Retrieve a Comment

Definition & Example Request

GET /wp/v2/comments/<id>

Query this endpoint to retrieve a specific comment record.

$ curl https://example.com/wp-json/wp/v2/comments/<id>

Arguments

id Unique identifier for the comment.
context Scope under which the request is made; determines fields present in response.

Default: view

One of: view, embed, edit

password The password for the parent post of the comment (if the post is password protected).

Update a Comment

Arguments

id Unique identifier for the comment.
author The ID of the user object, if author was a user.
author_email Email address for the comment author.
author_ip IP address for the comment author.
author_name Display name for the comment author.
author_url URL for the comment author.
author_user_agent User agent for the comment author.
content The content for the comment.
date The date the comment was published, in the site’s timezone.
date_gmt The date the comment was published, as GMT.
parent The ID for the parent of the comment.
post The ID of the associated post object.
status State of the comment.
meta Meta fields.

Definition

POST /wp/v2/comments/<id>

Example Request

Delete a Comment

Arguments

id Unique identifier for the comment.
force Whether to bypass Trash and force deletion.
password The password for the parent post of the comment (if the post is password protected).

Definition

DELETE /wp/v2/comments/<id>

Example Request

$ curl -X DELETE https://example.com/wp-json/wp/v2/comments/<id>

Tags

Schema

The schema defines all the fields that exist within a tag record. Any response from these endpoints can be expected to contain the fields below unless the `_filter` query parameter is used or the schema field only appears in a specific context.

id Unique identifier for the term.

JSON data type: integer

Read only

Context: view, embed, edit

count Number of published posts for the term.

JSON data type: integer

Read only

Context: view, edit

description HTML description of the term.

JSON data type: string

Context: view, edit

name HTML title for the term.

JSON data type: string

Context: view, embed, edit

slug An alphanumeric identifier for the term unique to its type.

JSON data type: string

Context: view, embed, edit

taxonomy Type attribution for the term.

JSON data type: string

Read only

Context: view, embed, edit

One of: post_tag

meta Meta fields.

JSON data type: object

Context: view, edit

List Tags

Query this endpoint to retrieve a collection of tags. The response you receive can be controlled and filtered using the URL query parameters below.

Definition

GET /wp/v2/tags

Example Request

$ curl https://example.com/wp-json/wp/v2/tags

Arguments

context Scope under which the request is made; determines fields present in response.

Default: view

One of: view, embed, edit

page Current page of the collection.

Default: 1

per_page Maximum number of items to be returned in result set.

Default: 10

search Limit results to those matching a string.
exclude Ensure result set excludes specific IDs.
include Limit result set to specific IDs.
offset Offset the result set by a specific number of items.
order Order sort attribute ascending or descending.

Default: asc

One of: asc, desc

orderby Sort collection by term attribute.

Default: name

One of: id, include, name, slug, include_slugs, term_group, description, count

hide_empty Whether to hide terms not assigned to any posts.
post Limit result set to terms assigned to a specific post.
slug Limit result set to terms with one or more specific slugs.

Create a Tag

Arguments

description HTML description of the term.
name HTML title for the term.

Required: 1

slug An alphanumeric identifier for the term unique to its type.
meta Meta fields.

Definition

POST /wp/v2/tags

Retrieve a Tag

Definition & Example Request

GET /wp/v2/tags/<id>

Query this endpoint to retrieve a specific tag record.

$ curl https://example.com/wp-json/wp/v2/tags/<id>

Arguments

id Unique identifier for the term.
context Scope under which the request is made; determines fields present in response.

Default: view

One of: view, embed, edit

Update a Tag

Arguments

id Unique identifier for the term.
description HTML description of the term.
name HTML title for the term.
slug An alphanumeric identifier for the term unique to its type.
meta Meta fields.

Definition

POST /wp/v2/tags/<id>

Example Request

Delete a Tag

Arguments

id Unique identifier for the term.
force Required to be true, as terms do not support trashing.

Definition

DELETE /wp/v2/tags/<id>

Example Request

$ curl -X DELETE https://example.com/wp-json/wp/v2/tags/<id>

Taxonomies

Schema

The schema defines all the fields that exist within a taxonomy record. Any response from these endpoints can be expected to contain the fields below unless the `_filter` query parameter is used or the schema field only appears in a specific context.

capabilities All capabilities used by the taxonomy.

JSON data type: object

Read only

Context: edit

description A human-readable description of the taxonomy.

JSON data type: string

Read only

Context: view, edit

hierarchical Whether or not the taxonomy should have children.

JSON data type: boolean

Read only

Context: view, edit

labels Human-readable labels for the taxonomy for various contexts.

JSON data type: object

Read only

Context: edit

name The title for the taxonomy.

JSON data type: string

Read only

Context: view, edit, embed

slug An alphanumeric identifier for the taxonomy.

JSON data type: string

Read only

Context: view, edit, embed

show_cloud Whether or not the term cloud should be displayed.

JSON data type: boolean

Read only

Context: edit

types Types associated with the taxonomy.

JSON data type: array

Read only

Context: view, edit

rest_base REST base route for the taxonomy.

JSON data type: string

Read only

Context: view, edit, embed

rest_namespace REST namespace route for the taxonomy.

JSON data type: string

Read only

Context: view, edit, embed

visibility The visibility settings for the taxonomy.

JSON data type: object

Read only

Context: edit

Retrieve a Taxonomy

Definition & Example Request

GET /wp/v2/taxonomies

Query this endpoint to retrieve a specific taxonomy record.

$ curl https://example.com/wp-json/wp/v2/taxonomies

Arguments

context Scope under which the request is made; determines fields present in response.

Default: view

One of: view, embed, edit

type Limit results to taxonomies associated with a specific post type.

Retrieve a Taxonomy

Definition & Example Request

GET /wp/v2/taxonomies/<taxonomy>

Query this endpoint to retrieve a specific taxonomy record.

$ curl https://example.com/wp-json/wp/v2/taxonomies/<taxonomy>

Arguments

taxonomy An alphanumeric identifier for the taxonomy.
context Scope under which the request is made; determines fields present in response.

Default: view

One of: view, embed, edit

Page Revisions

Schema

The schema defines all the fields that exist within a page revision record. Any response from these endpoints can be expected to contain the fields below unless the `_filter` query parameter is used or the schema field only appears in a specific context.

author The ID for the author of the revision.

JSON data type: integer

Context: view, edit, embed

date The date the revision was published, in the site’s timezone.

JSON data type: string,
Format: datetime (details)

Context: view, edit, embed

date_gmt The date the revision was published, as GMT.

JSON data type: string,
Format: datetime (details)

Context: view, edit

guid The globally unique identifier for the post.

JSON data type: object

Read only

Context: view, edit

id Unique identifier for the revision.

JSON data type: integer

Context: view, edit, embed

modified The date the revision was last modified, in the site’s timezone.

JSON data type: string,
Format: datetime (details)

Context: view, edit

modified_gmt The date the revision was last modified, as GMT.

JSON data type: string,
Format: datetime (details)

Context: view, edit

parent The ID for the parent of the revision.

JSON data type: integer

Context: view, edit, embed

slug An alphanumeric identifier for the revision unique to its type.

JSON data type: string

Context: view, edit, embed

title The title for the post.

JSON data type: object

Context: view, edit, embed

content The content for the post.

JSON data type: object

Context: view, edit

excerpt The excerpt for the post.

JSON data type: object

Context: view, edit, embed

List Page Revisions

Query this endpoint to retrieve a collection of page revisions. The response you receive can be controlled and filtered using the URL query parameters below.

Definition

GET /wp/v2/pages/<parent>/revisions

Example Request

$ curl https://example.com/wp-json/wp/v2/pages/<parent>/revisions

Arguments

parent The ID for the parent of the revision.
context Scope under which the request is made; determines fields present in response.

Default: view

One of: view, embed, edit

page Current page of the collection.

Default: 1

per_page Maximum number of items to be returned in result set.
search Limit results to those matching a string.
exclude Ensure result set excludes specific IDs.
include Limit result set to specific IDs.
offset Offset the result set by a specific number of items.
order Order sort attribute ascending or descending.

Default: desc

One of: asc, desc

orderby Sort collection by object attribute.

Default: date

One of: date, id, include, relevance, slug, include_slugs, title

Retrieve a Page Revision

Definition & Example Request

GET /wp/v2/pages/<parent>/revisions/<id>

Query this endpoint to retrieve a specific page revision record.

$ curl https://example.com/wp-json/wp/v2/pages/<parent>/revisions/<id>

Arguments

parent The ID for the parent of the revision.
id Unique identifier for the revision.
context Scope under which the request is made; determines fields present in response.

Default: view

One of: view, embed, edit

Delete a Page Revision

Arguments

parent The ID for the parent of the revision.
id Unique identifier for the revision.
force Required to be true, as revisions do not support trashing.

Definition

DELETE /wp/v2/pages/<parent>/revisions/<id>

Example Request

$ curl -X DELETE https://example.com/wp-json/wp/v2/pages/<parent>/revisions/<id>

Retrieve a Page Revision

Definition & Example Request

GET /wp/v2/pages/<id>/autosaves

Query this endpoint to retrieve a specific page revision record.

$ curl https://example.com/wp-json/wp/v2/pages/<id>/autosaves

Arguments

parent The ID for the parent of the autosave.
context Scope under which the request is made; determines fields present in response.

Default: view

One of: view, embed, edit

Create a Page Revision

Arguments

parent The ID for the parent of the post.
date The date the post was published, in the site’s timezone.
date_gmt The date the post was published, as GMT.
slug An alphanumeric identifier for the post unique to its type.
status A named status for the post.
One of: publish, future, draft, pending, private
password A password to protect access to the content and excerpt.
title The title for the post.
content The content for the post.
author The ID for the author of the post.
excerpt The excerpt for the post.
featured_media The ID of the featured media for the post.
comment_status Whether or not comments are open on the post.
One of: open, closed
ping_status Whether or not the post can be pinged.
One of: open, closed
menu_order The order of the post in relation to other posts.
meta Meta fields.
template The theme file to use to display the post.

Definition

POST /wp/v2/pages/<id>/autosaves

Retrieve a Page Revision

Definition & Example Request

GET /wp/v2/pages/<parent>/autosaves/<id>

Query this endpoint to retrieve a specific page revision record.

$ curl https://example.com/wp-json/wp/v2/pages/<parent>/autosaves/<id>

Arguments

parent The ID for the parent of the autosave.
id The ID for the autosave.
context Scope under which the request is made; determines fields present in response.

Default: view

One of: view, embed, edit

Authentication

<?php
wp_localize_script( 'wp-api', 'wpApiSettings', array(
    'root' => esc_url_raw( rest_url() ),
    'nonce' => wp_create_nonce( 'wp_rest' )
) );

This is then used in the base model:

options.beforeSend = function(xhr) {
    xhr.setRequestHeader('X-WP-Nonce', wpApiSettings.nonce);

    if (beforeSend) {
        return beforeSend.apply(this, arguments);
    }
};

Here is an example of editing the title of a post, using jQuery AJAX:

$.ajax( {
    url: wpApiSettings.root + 'wp/v2/posts/1',
    method: 'POST',
    beforeSend: function ( xhr ) {
        xhr.setRequestHeader( 'X-WP-Nonce', wpApiSettings.nonce );
    },
    data:{
        'title' : 'Hello Moon'
    }
} ).done( function ( response ) {
    console.log( response );
} );

Note that you do not need to verify that the nonce is valid inside your custom end point. This is automatically done for you in rest_cookie_check_errors().

Basic Authentication with Application Passwords

As of 5.6, WordPress has shipped with Application Passwords, which can be generated from an Edit User page (wp-admin -> Users -> Edit User). The credentials can be passed along to REST API requests served over https:// using Basic Auth / RFC 7617 — here’s the documentation for how to use it with cURL. For a simple command-line script example, just swap out USERNAME, PASSWORD, and HOSTNAME in this with their respective values:

curl --user "USERNAME:PASSWORD" https://HOSTNAME/wp-json/wp/v2/users?context=edit

Authentication Plugins

Plugins may be added to support alternative modes of authentication that will work from remote applications. Some example plugins are OAuth 1.0a Server and JSON Web Tokens.

There’s also a Basic Authentication plugin. Note that this plugin requires sending your username and password with every request, and should only be used for development and testing i.e. not in a production environment. Using Application Passwords (see above) is preferred.

Pagination

WordPress sites can have a lot of content—far more than you’d want to pull down in a single request. The API endpoints default to providing a limited number of items per request, the same way that a WordPress site will default to 10 posts per page in archive views.

Pagination Parameters

Any API response which contains multiple resources supports several common query parameters to handle paging through the response data:

Large queries can hurt site performance, so per_page is capped at 100 records. If you wish to retrieve more than 100 records, for example to build a client-side list of all available categories, you may make multiple API requests and combine the results within your application.

To determine how many pages of data are available, the API returns two header fields with every paginated response:

By inspecting these header fields you can determine how much more data is available within the API.

Ordering Results

In addition to the pagination query parameters detailed above, several other parameters control the order of the returned results:

Discovery

When your client talks to an unknown site, you’ll need to discover what the site is capable of and how the site is configured. There are a couple of steps for this, depending on what you need to discover.

Discovering the API

The first step of connecting to a site is finding out whether the site has the API enabled. Typically, you’ll be working with URLs from user input, so the site you’re accessing could be anything. The discovery step lets you verify the API is available, as well as indicating how to access it.

The preferred way to handle discovery is to send a HEAD request to the supplied address. The REST API automatically adds a Link header to all front-end pages that looks like the following:

Link: <http://example.com/wp-json/>; rel="https://api.w.org/"

This URL points to the root route (/) of the API, which is then used for further discovery steps.

For sites without “pretty permalinks” enabled, /wp-json/ isn’t automatically handled by WordPress. This means that normal/default WordPress permalinks will be used instead. These headers look more like this:

Link: <http://example.com/?rest_route=/>; rel="https://api.w.org/"

Clients should keep this variation in mind and ensure that both routes can be handled seamlessly.

This auto-discovery can be applied to any URL served by a WordPress installation, so no pre-processing on user input needs to be added. Since this is a HEAD request, the request should be safe to send blindly to servers without worrying about causing side-effects.

Element

For clients with a HTML parser, or running in the browser, the equivalent of the Link header is included in the <head> of front-end pages through a <link> element:

In-browser Javascript can access this via the DOM:

// jQuery method
var $link = jQuery( 'link[rel="https://api.w.org/"]' );
var api_root = $link.attr( 'href' );

// Native method
var links = document.getElementsByTagName( 'link' );
var link = Array.prototype.filter.call( links, function ( item ) {
    return ( item.rel === 'https://api.w.org/' );
} );
var api_root = link[0].href;

For in-browser clients, or clients without access to HTTP headers, this may be a more usable way of discovering the API. This is similar to Atom/RSS feed discovery, so existing code for that purpose may also be automatically adapted instead.

RSD (Really Simple Discovery)

For clients with support for XML-RPC discovery, the RSD method may be more applicable. This is an XML-based discovery format typically used for XML-RPC. RSD has two steps. The first step is to find the RSD endpoint, supplied as a <link> element:

The second step is to fetch the RSD document and parse the available endpoints. This involves using an XML parser on a document like the following:

<?xml version="1.0" encoding="utf-8"?>
<rsd version="1.0" xmlns="http://archipelago.phrasewise.com/rsd">
  <service>
    <engineName>WordPress</engineName>
    <engineLink>https://wordpress.org/</engineLink>
    <homePageLink>http://example.com/</homePageLink>
    <apis>
      <api name="WordPress" blogID="1" preferred="true" apiLink="http://example.com/xmlrpc.php" />
      <!-- ... -->
      <api name="WP-API" blogID="1" preferred="false" apiLink="http://example.com/wp-json/" />
    </apis>
  </service>
</rsd>

The REST API always has a name attribute with the value equal to WP-API.

RSD is the least-preferred method of autodiscovery for a couple of reasons. The first step of RSD-based discovery involves parsing the HTML to first find the RSD document itself, which is equivalent to the <link> Element autodiscovery. It then involves another step to parse the RSD document, which requires a full XML parser.

Where possible, we suggest avoiding RSD-based discovery due to the complexity, but existing XML-RPC clients may prefer to use this method if they already have an RSD parser enabled. For XML-RPC clients which wish to use the REST API as a progressive enhancement to the codebase, this avoids needing to support different forms of discovery.

Authentication Discovery

Discovery is also available for authentication methods available via the API. The API root’s response is an object describing the API, which includes an authentication key:

{
    "name": "Example WordPress Site",
    "description": "YOLO",
    "routes": { ... },
    "authentication": {
        "oauth1": {
            "request": "http://example.com/oauth/request",
            "authorize": "http://example.com/oauth/authorize",
            "access": "http://example.com/oauth/access",
            "version": "0.1"
        }
    }
}

The authentication value is a map (associative array) of authentication method ID to authentication options. The options available here are specific to the authentication method itself. See the authentication documentation for the options for specific authentication methods.

Extension Discovery

Once you’ve discovered the API, the next step is check what the API supports. The index of the API exposes the namespaces item, which contains the extensions to the API that are supported.

For WordPress sites using versions 4.4 through 4.6, only the base API infrastructure is available, not the full API with endpoints. This also includes the oEmbed endpoints:

{
    "name": "Example WordPress Site",
    "namespaces": [
        "oembed/1.0/"
    ]
}

Sites with the full API available (i.e. with WordPress 4.7+ or the REST API plugin installed) will have the wp/v2 item in namespaces as well:

{
    "name": "Example WordPress Site",
    "namespaces": [
        "wp/v2",
        "oembed/1.0/"
    ]
}

Before attempting to use any of the core endpoints, you should be sure to check that the API is supported by checking for wp/v2 support. WordPress 4.4 enabled the API infrastructure for all sites, but did not include the core endpoints under wp/v2. Core endpoints were added in WordPress 4.7.

This same mechanism can be used for detecting support for any plugins that support the REST API. For example, take a plugin which registers the following route:

<?php
register_rest_route( 'testplugin/v1', '/testroute', array( /* ... */ ) );

This would add the testplugin/v1 namespace to the index:

{
    "name": "Example WordPress Site",
    "namespaces": [
        "wp/v2",
        "oembed/1.0/",
        "testplugin/v1"
    ]
}

Resource Discovery

As of WordPress 5.5 the REST API also provides a discovery mechanism for identifying the REST API route equivalent of the current document. A link is added with a rel of alternate and a type of application/json that points to a REST API url. The link is added both as a Link header and a <link> element.

For instance, in the <head> section of this page, the following <link> appears.

Linking and Embedding

The WP REST API incorporates hyperlinking throughout the API to allow discoverability and browsability, as well as embedding related resources together in one response. While the REST API does not completely conform to the entire HAL standard, it implements the ._links and ._embedded properties from that standard as described below.

Examples include:
– author – describing a relationship between a resource and its author
– wp:term – describing the relationship between a post and its tags or categories

The relation is either a
– standardized relation
– a URI relation – like https://api.w.org/term
– or a Compact URI relation – like wp:term

Compact URI relations can be normalized to full URI relations to ensure full compatibility if required. This is similar to HTML <link> tags, or <a rel=""> links.

For collection responses (those that return a list of objects rather than a top-level object), each item contains links, and the top-level response includes links via the Link header instead.

If your client library does not allow accessing headers, you can use the _envelope parameter to include the headers as body data instead.

Example Response

A typical single post request (/wp/v2/posts/42):

{
  "id": 42,
  "_links": {
    "collection": [
      {
        "href": "https://example.com/wp-json/wp/v2/posts"
      }
    ],
    "author": [
      {
        "href": "https://example.com/wp-json/wp/v2/users/1",
        "embeddable": true
      }
    ]
  }
}

Embedding

Optionally, some linked resources may be included in the response to reduce the number of HTTP requests required. These resources are “embedded” into the main response.

Embedding is triggered by setting the _embed query parameter on the request. This will then include embedded resources under the _embedded key adjacent to the _links key. The layout of this object mirrors the _links object, but includes the embedded resource in place of the link properties.

When embedding a collection response, for instance /wp/v2/posts?author=1, the embedded collection will have the default pagination limits applied.

Example Response

{
  "id": 42,
  "_links": {
    "collection": [
      {
        "href": "https://example.com/wp-json/wp/v2/posts"
      }
    ],
    "author": [
      {
        "href": "https://example.com/wp-json/wp/v2/users/1",
        "embeddable": true
      }
    ]
  },
  "_embedded": {
    "author": {
      "id": 1,
      "name": "admin",
      "description": "Site administrator"
    }
  }
}

Global Parameters

The API includes a number of global parameters (also called “meta-parameters”) which control how the API handles the request/response handling. These operate at a layer above the actual resources themselves, and are available on all resources.

_fields

A REST resource like a Post contains a large quantity of data: basic information such as content, title, and author ID, but also registered metadata and fields, media information, and links to other resources. Your application may not need all of this information on every request. To instruct WordPress to return only a subset of the fields in a response, you may use the _fields query parameter. If for example you are building an archive view and only need the ID, title, permalink, author and excerpt for a collection of posts, you can restrict the response to only those properties with this fields query:

/wp/v2/posts?_fields=author,id,excerpt,title,link

You may alternatively provide that same list using query parameter array syntax instead of a comma-separated list:

/wp/v2/posts?_fields[]=author&_fields[]=id&_fields[]=excerpt&_fields[]=title&_fields[]=link

When _fields is provided then WordPress will skip unneeded fields when generating your response object, avoiding potentially expensive internal computation or queries for data you don’t need. This also means the JSON object returned from the REST API will be smaller, requiring less time to download and less time to parse on your client device. Carefully design your queries to pull in only the needed properties from each resource to make your application faster to use and more efficient to run. As of WordPress 5.3 the _fields parameter supports nested properties. This can be useful if you have registered many meta keys, permitting you to request the value for only one of the registered meta properties:

?_fields=meta.one-of-many-keys

Only the meta value with the key one-of-many-keys will be returned, and others will be excluded. You can also request specific deeply-nested properties within a complex meta object:

?_fields=meta.key_name.nested_prop.deeply_nested_prop,meta.key_name.other_nested_prop

_embed

Most resources include links to related resources. For example, a post can link to the parent post, or to comments on the post. To reduce the number of HTTP requests required, clients may wish to fetch a resource as well as the linked resources. The _embed parameter indicates to the server that the response should include these embedded resources. Embed mode is enabled if the _embed parameter is passed in the query string (GET parameter). This parameter does not require a value (i.e. ?_embed is valid), however can be passed “1” as a value if required by a client library. As of WordPress 5.4, the resources to embed can be limited by passing a list of link relation names to the _embed parameter. For example, /wp/v2/posts?_embed=author,wp:term will only embed the post’s author and the lists of terms associated with the post. Resources in embed mode will contain an additional _embedded key next to the _links key containing the linked resources. Only links with the embeddable parameter set to true will be embedded. In order to use _embed together with _fields, add _embedded as well as _links to the fields, for instance, /wp-json/wp/v2/posts/_embed=author,wp:term&_fields=title,author,_links,_embedded. For more about linking and embedding, see the Linking and Embedding page.

_method (or X-HTTP-Method-Override header)

Some servers and clients cannot correctly process some HTTP methods that the API makes use of. For example, all deletion requests on resources use the DELETE method, but some clients do not provide the ability to send this method. To ensure compatibility with these servers and clients, the API supports a method override. This can be passed either via a _method parameter or the X-HTTP-Method-Override header, with the value set to the HTTP method to use.

Clients should only ever send a method override parameter or header with POST requests. Using the method override with GET requests may cause the request to be incorrectly cached.

A POST to /wp-json/wp/v2/posts/42?_method=DELETE would be translated to a DELETE to the wp/v2/posts/42 route. Similarly, the following POST request would become a DELETE:

POST /wp-json/wp/v2/posts/42 HTTP/1.1
Host: example.com
X-HTTP-Method-Override: DELETE

_envelope

Similarly to _method, some servers, clients, and proxies do not support accessing the full response data. The API supports passing an _envelope parameter, which sends all response data in the body, including headers and status code. Envelope mode is enabled if the _envelope parameter is passed in the query string (GET parameter). This parameter does not require a value (i.e. ?_envelope is valid), but can be passed “1” as a value if required by a client library.

For future compatibility, other values should not be passed.

Enveloped responses include a “fake” HTTP 200 response code with no additional headers (apart from Content-Type) that should ensure the response correctly passes through intermediaries. For example, given the following response to a GET to wp/v2/users/me:

HTTP/1.1 302 Found
Location: http://example.com/wp-json/wp/v2/users/42

{
  "id": 42,
  ...
}

The equivalent enveloped response (with a GET to wp/v2/users/me?_envelope) would be:

HTTP/1.1 200 OK

{
  "status": 302,
  "headers": {
    "Location": "http://example.com/wp-json/wp/v2/users/42"
  },
  "body": {
    "id": 42
  }
}

_jsonp

The API natively supports JSONP responses to allow cross-domain requests for legacy browsers and clients. This parameter takes a JavaScript callback function which will be prepended to the data. This URL can then be loaded via a <script> tag. The callback function can contain any alphanumeric, _ (underscore), or . (period) character. Callbacks which contain invalid characters will receive a HTTP 400 error response, and the callback will not be called.

Modern browsers can use Cross-Origin Resource Sharing (CORS) preflight requests for cross-domain requests, but JSONP can be used to ensure support with all browsers.

For example:

<script>
function receiveData( data ) {
  // Do something with the data here.
  // For demonstration purposes, we'll simply log it.
  console.log( data );
}
</script>
<script src="https://example.com/wp-json/?_jsonp=receiveData"></script>

Backbone JavaScript Client

The REST API includes a JavaScript/Backbone client library. The library provides an interface for the WP REST API by providing Backbone Models and Collections for all endpoints exposed through the API Schema.

Using

Activate the WP-API plugin. Enqueue the script directly:

wp_enqueue_script( 'wp-api' );

or as a dependency for your script:

wp_enqueue_script( 'my_script', 'path/to/my/script', array( 'wp-api' ) );

The library parses the root endpoint (the ‘Schema’) and creates matching Backbone models and collections. You will now have two root objects available to you: wp.api.models and wp.api.collections. The models and collections include: Models: * Category * Comment * Media * Page * PageMeta * PageRevision * Post * PostMeta * PostRevision * Schema * Status * Tag * Taxonomy * Type * User Collections: * Categories * Comments * Media * PageMeta * PageRevisions * Pages * Posts * Statuses * Tags * Taxonomies * Types * Users You can use these endpoints as-is to read, update, create and delete items using standard Backbone methods (fetch, sync, save & destroy for models, sync for collections). You can also extend these objects to make them your own, and build your views on top of them.

Default values

Each model and collection includes a reference to its default values, for example: wp.api.models.Post.prototype.args

Available methods

Each model and collection contains a list of methods the corresponding endpoint supports. For example, models created from wp.api.models.Post have a methods array of:

["GET", "POST", "PUT", "PATCH", "DELETE"]

Accepted options

Each model and collection contains a list of options the corresponding endpoint accepts (note that options are passed as the second parameter when creating models or collections), for example: wp.api.collections.Posts.prototype.options

Localizing the API Schema

The client will accept and use a localized schema as part of the wpApiSettings object. The Schema is currently not passed by default; instead the client makes an ajax request to the API to load the Schema, then caches it in the browser’s session storage (if available). Activating the client-js plugin with SCRIPT_DEBUG enabled uses a localized Schema. Check the client-js example or this branch which attempts to only localize the schema once per client.

Waiting for the client to load

Client startup is asynchronous. If the api schema is localized, the client can start immediately; if not the client makes an ajax request to load the schema. The client exposes a load promise for provide a reliable wait to wait for client to be ready:

wp.api.loadPromise.done( function() {
//... use the client here
} )

Model examples:

To create a post and edit its categories, make sure you are logged in, then:

// Create a new post
var post = new wp.api.models.Post( { title: 'This is a test post' } );
post.save();

// Load an existing post
var post = new wp.api.models.Post( { id: 1 } );
post.fetch();

// Get a collection of the post's categories (returns a promise)
// Uses _embedded data if available, in which case promise resolves immediately.
post.getCategories().done( function( postCategories ) {
  // ... do something with the categories.
  // The new post has an single Category: Uncategorized
  console.log( postCategories[0].name );
  // response -> "Uncategorized"
} );

// Get a posts author User model.
post.getAuthorUser().done( function( user ){
  // ... do something with user
  console.log( user.get( "name" ) );
} );

// Get a posts featured image Media model.
post.getFeaturedMedia().done( function( image ){
  // ... do something with image
  console.log( image );
} );

// Set the post categories.
post.setCategories( [ "apples", "oranges" ] );

// Get all the categories
var allCategories = new wp.api.collections.Categories()
allCategories.fetch();

var appleCategory = allCategories.findWhere( { slug: "apples" } );

// Add the category to the postCategories collection we previously fetched.
appleCategory.set( "parent_post", post.get( "id" ) );

// Use the POST method so Backbone will not PUT it even though it has an id.
postCategories.create( appleCategory.toJSON(), { type: "POST" } );

// Remove the Uncategorized category
postCategories.at( 0 ).destroy();

// Check the results - re-fetch
postCategories = post.getCategories();

postCategories.at( 0 ).get( "name" );
// response -> "apples"

Collection examples:

To get the last 10 posts:

var postsCollection = new wp.api.collections.Posts();
postsCollection.fetch();

To get the last 25 posts:

postsCollection.fetch( { data: { per_page: 25 } } );

Use filter to change the order & orderby options:

postsCollection.fetch( { data: { 'filter': { 'orderby': 'title', 'order': 'ASC' } } } );

All collections support pagination automatically, and you can get the next page of results using more:

postsCollection.more();

To get page 5 of a collection:

posts.fetch( { data: { page: 5 } } );

Check if the collection has any more posts:

posts.hasMore();

Working With Revisions

You can access post or page revisions using the PostRevisions or PageRevisions collections or through the Post or Page collection. For example, to get a collection of all revisions of post ID 1:

var revisions = new wp.api.collections.PostRevisions({}, { parent: 1 });

Revision collections can also be accessed via their parent’s collection. This example makes 2 HTTP requests instead of one, but now the original post and its revisions are available:

var post = new wp.api.models.Post( { id: 1 } );
post.fetch();
post.getRevisions().done( function( revisions ){
  console.log( revisions );
});

If you add custom endpoints to the API they will also become available as models/collections. For example, you will get new models and collections when you add REST API support to your custom post type. To access custom endpoints created, use the item’s JSON endpoint name as CamelCase; for example if the item is found at the JSON path of /wp-json/wp/v2/my-custom-post, it can be accessed via the api at wp.api.collections.MyCustomPost. Note: Because the schema is stored in the user’s session cache to avoid re-fetching, you may need to open a new tab to get a new read of the Schema.

// Extend wp.api.models.Post and wp.api.collections.Posts to load a custom post type
const CustomPost = wp.api.models.Post.extend( {
  urlRoot: wpApiSettings.root + 'wp/v2/custom_post_slug',
  defaults: {
    type: 'custom_post_slug',
  },
} );
const CustomPosts = wp.api.collections.Posts.extend( {
  url: wpApiSettings.root + 'wp/v2/custom_post_slug',
  model: BLProduct,
} );
const someCustomPosts = new CustomPosts();
someCustomPosts.fetch().then( ( posts ) => {
  // do something with the custom posts
} );

Client Libraries

The API can be used from any application by sending basic HTTP requests; however, client libraries simplify the process of querying or creating specific resources. These libraries make it easy to connect an external application to the WordPress REST API using a variety of programming languages.

Aside from the Backbone.js client, these libraries are not part of WordPress core, and are not necessarily maintained or endorsed by the WordPress REST API team.

To perform authenticated requests from outside of the WordPress admin, themes, or plugins, a separate authentication plugin is required.

PHP

Requests for PHP is a general purpose HTTP request library. While not specifically designed for the WordPress REST API, it is a great tool for interacting with any HTTP API.

WordPress-PHP-SDK is a PHP SDK for the WordPress REST API, which can be installed using composer.

WordPress-SDK is a Laravel package for the WordPress REST API, which can be installed using composer.

JavaScript

The Backbone.js client is built in to WordPress core and provides Backbone.js models & collections for working with REST API resources.

node-wpapi is an isomorphic JavaScript client library for querying or writing to the REST API using an intuitive chaining syntax. It can be used with Node.js or with client-side JavaScript applications.

ember-wordpress provides a connection between Ember Data and the REST API

Ruby

wp-api-client: a read-only REST API client written in Ruby.

C# / .NET

WordPressPCL: a full REST API client written in C#.

Dart / Flutter

wordpress_client: A library exposing a fluent api to interact with the WordPress REST API.

Routes and Endpoints

Overview

The REST API provides us a way to match URIs to various resources in our WordPress install. By default, if you have pretty permalinks enabled, the WordPress REST API “lives” at /wp-json/. At our WordPress site https://ourawesomesite.com`, we can access the REST API's index by making aGETrequest tohttps://ourawesomesite.com/wp-json/`. The index provides information regarding what routes are available for that particular WordPress install, along with what HTTP methods are supported and what endpoints are registered.

Routes vs Endpoints

Endpoints are functions available through the API. This can be things like retrieving the API index, updating a post, or deleting a comment. Endpoints perform a specific function, taking some number of parameters and return data to the client.

A route is the “name” you use to access endpoints, used in the URL. A route can have multiple endpoints associated with it, and which is used depends on the HTTP verb.

For example, with the URL `http://example.com/wp-json/wp/v2/posts/123`:

On sites without pretty permalinks, the route is instead added to the URL as the rest_route parameter. For the above example, the full URL would then be http://example.com/?rest_route=/wp/v2/posts/123

Creating Endpoints

If we wanted to create an endpoint that would return the phrase “Hello World, this is the WordPress REST API” when it receives a GET request, we would first need to register the route for that endpoint. To register routes you should use the register_rest_route() function. It needs to be called on the rest_api_init action hook. register_rest_route() handles all of the mapping for routes to endpoints. Let’s try to create a “Hello World, this is the WordPress REST API” route.

/**
 * This is our callback function that embeds our phrase in a WP_REST_Response
 */
function prefix_get_endpoint_phrase() {
    // rest_ensure_response() wraps the data we want to return into a WP_REST_Response, and ensures it will be properly returned.
    return rest_ensure_response( 'Hello World, this is the WordPress REST API' );
}

/**
 * This function is where we register our routes for our example endpoint.
 */
function prefix_register_example_routes() {
    // register_rest_route() handles more arguments but we are going to stick to the basics for now.
    register_rest_route( 'hello-world/v1', '/phrase', array(
        // By using this constant we ensure that when the WP_REST_Server changes our readable endpoints will work as intended.
        'methods'  => WP_REST_Server::READABLE,
        // Here we register our callback. The callback is fired when this endpoint is matched by the WP_REST_Server class.
        'callback' => 'prefix_get_endpoint_phrase',
    ) );
}

add_action( 'rest_api_init', 'prefix_register_example_routes' );

The first argument passed into register_rest_route() is the namespace, which provides us a way to group our routes. The second argument passed in is the resource path, or resource base. For our example, the resource we are retrieving is the “Hello World, this is the WordPress REST API” phrase. The third argument is an array of options. We specify what methods the endpoint can use and what callback should happen when the endpoint is matched (more things can be done but these are the fundamentals).

The third argument also allows us to provide a permissions callback, which can restrict access for the endpoint to only certain users. The third argument also offers a way to register arguments for the endpoint so that requests can modify the response of our endpoint. We will get into those concepts in the endpoints section of this guide.

When we go to `https://ourawesomesite.com/wp-json/hello-world/v1/phrase` we can now see our REST API greeting us kindly. Let’s take a look at routes a bit more in depth.

Routes

Routes in the REST API are represented by URIs. The route itself is what is tacked onto the end of https://ourawesomesite.com/wp-json`. The index route for the API is/which is whyhttps://ourawesomesite.com/wp-json/` returns all of the available information for the API. All routes should be built onto this route, the wp-json portion can be changed, but in general, it is advised to keep it the same.

We want to make sure that our routes are unique. For instance we could have a route for books like this: /books. Our books route would now live at https://ourawesomesite.com/wp-json/books`. However, this is not a good practice as we would end up polluting potential routes for the API. What if another plugin we wanted to register a books route as well? We would be in big trouble in that case, as the two routes would conflict with each other and only one could be used. The fourth parameter toregister_rest_route() ` is a boolean for whether the route should override an existing route.

The override parameter does not really solve our problem either, as both routes could override or we would want to use both routes for different things. This is where using namespaces for our routes comes in.

Namespaces

It is extremely important to add namespaces to your routes. The “core” endpoints use the wp/v2 namespace.

Do not place anything into the wp namespace unless you are making endpoints with the intention of merging them into core.

There are some key things to take notice of in the core endpoint namespace. The first part of the namespace is wp, which represents the vendor name; WordPress. For our plugins we will want to come up with unique names for what we call the vendor portion of the namespace. In the example above we used hello-world.

Following the vendor portion is the version portion of the namespace. The “core” endpoints utilize v2 to represent version 2 of the WordPress REST API. If you are writing a plugin, you can maintain backwards compatibility of your REST API endpoints by simply creating new endpoints and bumping up the version number you provide. This way both the original v1 and v2 endpoints can be accessed.

The part of the route that follows the namespace is the resource path.

Resource Paths

The resource path should signify what resource the endpoint is associated with. In the example we used above, we used the word phrase to signify that the resource we are interacting with is a phrase. To avoid any collisions, each resource path we register should also be unique within a namespace. Resource paths should be used to define different resource routes within a given namespace.

Let’s say we have a plugin that handles some basic eCommerce functionality. We will have two main resource types orders, and products. Orders are a request for product(s) but they are not the product themselves. The same concept applies to products. Although these resources are related they are not the same thing and each should live in a separate resource paths. Our routes will end up looking something like this for our eCommerce plugin: /my-shop/v1/orders and /my-shop/v1/products.

Using routes like this, we would want each to return a collection of orders or products. What if we wanted to grab a specific product by ID, we would need to use path variables in our routes.

Path Variables

Path variables enable us to add dynamic routes. To expand on our eCommerce routes, we could register a route to grab individual products.

/**
 * This is our callback function to return our products.
 *
 * @param WP_REST_Request $request This function accepts a rest request to process data.
 */
function prefix_get_products( $request ) {
    // In practice this function would fetch the desired data. Here we are just making stuff up.
    $products = array(
        '1' => 'I am product 1',
        '2' => 'I am product 2',
        '3' => 'I am product 3',
    );

    return rest_ensure_response( $products );
}

/**
 * This is our callback function to return a single product.
 *
 * @param WP_REST_Request $request This function accepts a rest request to process data.
 */
function prefix_get_product( $request ) {
    // In practice this function would fetch the desired data. Here we are just making stuff up.
    $products = array(
        '1' => 'I am product 1',
        '2' => 'I am product 2',
        '3' => 'I am product 3',
    );

    // Here we are grabbing the 'id' path variable from the $request object. WP_REST_Request implements ArrayAccess, which allows us to grab properties as though it is an array.
    $id = (string) $request['id'];

    if ( isset( $products[ $id ] ) ) {
        // Grab the product.
        $product = $products[ $id ];

        // Return the product as a response.
        return rest_ensure_response( $product );
    } else {
        // Return a WP_Error because the request product was not found. In this case we return a 404 because the main resource was not found.
        return new WP_Error( 'rest_product_invalid', esc_html__( 'The product does not exist.', 'my-text-domain' ), array( 'status' => 404 ) );
    }

    // If the code somehow executes to here something bad happened return a 500.
    return new WP_Error( 'rest_api_sad', esc_html__( 'Something went horribly wrong.', 'my-text-domain' ), array( 'status' => 500 ) );
}

/**
 * This function is where we register our routes for our example endpoint.
 */
function prefix_register_product_routes() {
    // Here we are registering our route for a collection of products.
    register_rest_route( 'my-shop/v1', '/products', array(
        // By using this constant we ensure that when the WP_REST_Server changes our readable endpoints will work as intended.
        'methods'  => WP_REST_Server::READABLE,
        // Here we register our callback. The callback is fired when this endpoint is matched by the WP_REST_Server class.
        'callback' => 'prefix_get_products',
    ) );
    // Here we are registering our route for single products. The (?P<id>[\d]+) is our path variable for the ID, which, in this example, can only be some form of positive number.
    register_rest_route( 'my-shop/v1', '/products/(?P<id>[\d]+)', array(
        // By using this constant we ensure that when the WP_REST_Server changes our readable endpoints will work as intended.
        'methods'  => WP_REST_Server::READABLE,
        // Here we register our callback. The callback is fired when this endpoint is matched by the WP_REST_Server class.
        'callback' => 'prefix_get_product',
    ) );
}

add_action( 'rest_api_init', 'prefix_register_product_routes' );

The above example covers a lot. The important part to note is that in the second route we register, we add on a path variable /(?P<id>[\d]+) to our resource path /products. The path variable is a regular expression. In this case it uses [\d]+ to signify that should be any numerical character at least once. If you are using numeric IDs for your resources, then this is a great example of how to use a path variable. When using path variables, we now have to be careful around what can be matched as it is user input.

The regex luckily will filter out anything that is not numerical. However, what if the product for the requested ID doesn’t exist. We need to do error handling. You can see the basic way we are handling errors in the code example above. When you return a WP_Error in your endpoint callbacks the API server will automatically handle serving the error to the client.

Although this section is about routes, we have covered quite a bit about endpoints. Endpoints and routes are interrelated, but they definitely have distinctions.

Endpoints

Endpoints are the destination that a route needs to map to. For any given route, you could have a number of different endpoints registered to it. We will expand on our fictitious eCommerce plugin, to better show the distinction between routes and endpoints. We are going to create two endpoints that exist at the /wp-json/my-shop/v1/products/ route. One endpoint uses the HTTP verb GET to get products, and the other endpoint uses the HTTP verb POST to create a new product.

/**
 * This is our callback function to return our products.
 *
 * @param WP_REST_Request $request This function accepts a rest request to process data.
 */
function prefix_get_products( $request ) {
    // In practice this function would fetch the desired data. Here we are just making stuff up.
    $products = array(
        '1' => 'I am product 1',
        '2' => 'I am product 2',
        '3' => 'I am product 3',
    );

    return rest_ensure_response( $products );
}

/**
 * This is our callback function to return a single product.
 *
 * @param WP_REST_Request $request This function accepts a rest request to process data.
 */
function prefix_create_product( $request ) {
    // In practice this function would create a product. Here we are just making stuff up.
   return rest_ensure_response( 'Product has been created' );
}

/**
 * This function is where we register our routes for our example endpoint.
 */
function prefix_register_product_routes() {
    // Here we are registering our route for a collection of products and creation of products.
    register_rest_route( 'my-shop/v1', '/products', array(
        array(
            // By using this constant we ensure that when the WP_REST_Server changes, our readable endpoints will work as intended.
            'methods'  => WP_REST_Server::READABLE,
            // Here we register our callback. The callback is fired when this endpoint is matched by the WP_REST_Server class.
            'callback' => 'prefix_get_products',
        ),
        array(
            // By using this constant we ensure that when the WP_REST_Server changes, our create endpoints will work as intended.
            'methods'  => WP_REST_Server::CREATABLE,
            // Here we register our callback. The callback is fired when this endpoint is matched by the WP_REST_Server class.
            'callback' => 'prefix_create_product',
        ),
    ) );
}

add_action( 'rest_api_init', 'prefix_register_product_routes' );

Depending on what HTTP Method we use for the route /wp-json/my-shop/v1/products, we are matched to a different endpoint and a different callback is fired. When we use POST we trigger the prefix_create_product() callback, and when we use GET we trigger the prefix_get_products() callback.

There are a number of different HTTP methods and the REST API can make use of any of them.

HTTP Methods

HTTP methods are sometimes referred to as HTTP verbs. They are simply just different ways to communicate via HTTP. The main ones used by the WordPress REST API are:

It is important to note that these methods are not supported by every client, as they were introduced in HTTP 1.1. Luckily, the API provides a workaround for these unfortunate cases. If you want to delete a resource but can’t send a DELETE request, then you can use the _method parameter or the X-HTTP-Method-Override header in your request. How this works is you will send a POST request to `https://ourawesomesite.com/wp-json/my-shop/v1/products/1?_method=DELETE`. Now you will have deleted product number 1, even though your client could not send the proper HTTP method in the request, or maybe there was a firewall in place that blocks out DELETE requests.

The HTTP method, in combination with the route and callbacks, are what make up the core of an endpoint.

Callbacks

There are currently only two types of callbacks for endpoints supported by the REST API; callback and permission_callback. The main callback should handle the interaction with the resource. The permissions callback should handle what users have access to the endpoint. You can add additional callbacks by adding additional information when registering an endpoint. You can then hook into rest_pre_dispatch, rest_dispatch_request, or rest_post_dispatch hooks to fire your new custom callbacks.

Endpoint Callback

The main callback for a delete endpoint should only delete the resource and return a copy of it in the response. The main callback for a creation endpoint should only create the resource and return a response matching the newly created data. An update callback should only modify resources that actually exist. A reading callback should only retrieve data that already exists. It is important to take into account the concept of idempotence.

Idempotence, in the context of a REST API, means that if you make the same request to an endpoint the server will process the request the same way. Imagine if our read endpoint was not idempotent. Whenever we made a request to it the state of our server would be modified by the request, even though we were only trying to get data. This could be catastrophic. Any time someone fetched data from your server something would change internally. It is important to make sure that read, update, and delete endpoints do not have nasty side effects and just stick to what they are intended to do.

In a REST API, the concept of idempotence is tied to HTTP methods instead of endpoint callbacks. Any callback using GET, HEAD, TRACE, OPTIONS, PUT, or DELETE, should not produce any side effects. POST requests are not idempotent, and are typically used for creating resources. If you created an idempotent creation method then you would only ever create one resource because when you make the same request there would be no more side effects to the server. For creating, if you make the same request over and over the server should generate new resources each time.

To restrict usage of endpoints we need to register a permissions callback.

Permissions Callback

Permissions callbacks are extremely important for security with the WordPress REST API. If you have any private data that should not be displayed publicly, then you need to have permissions callbacks registered for your endpoints. Below is an example of how to register permissions callbacks.

/**
 * This is our callback function that embeds our resource in a WP_REST_Response
 */
function prefix_get_private_data() {
    // rest_ensure_response() wraps the data we want to return into a WP_REST_Response, and ensures it will be properly returned.
    return rest_ensure_response( 'This is private data.' );
}

/**
 * This is our callback function that embeds our resource in a WP_REST_Response
 */
function prefix_get_private_data_permissions_check() {
    // Restrict endpoint to only users who have the edit_posts capability.
    if ( ! current_user_can( 'edit_posts' ) ) {
        return new WP_Error( 'rest_forbidden', esc_html__( 'OMG you can not view private data.', 'my-text-domain' ), array( 'status' => 401 ) );
    }

    // This is a black-listing approach. You could alternatively do this via white-listing, by returning false here and changing the permissions check.
    return true;
}

/**
 * This function is where we register our routes for our example endpoint.
 */
function prefix_register_example_routes() {
    // register_rest_route() handles more arguments but we are going to stick to the basics for now.
    register_rest_route( 'my-plugin/v1', '/private-data', array(
        // By using this constant we ensure that when the WP_REST_Server changes our readable endpoints will work as intended.
        'methods'  => WP_REST_Server::READABLE,
        // Here we register our callback. The callback is fired when this endpoint is matched by the WP_REST_Server class.
        'callback' => 'prefix_get_private_data',
        // Here we register our permissions callback. The callback is fired before the main callback to check if the current user can access the endpoint.
        'permission_callback' => 'prefix_get_private_data_permissions_check',
    ) );
}

add_action( 'rest_api_init', 'prefix_register_example_routes' );

If you try out this endpoint without any Authentication enabled then you will also be returned the error response, preventing you from seeing the data. Authentication is a huge topic and eventually a portion of this chapter will be created to show you how to create your own authentication processes.

Arguments

When making requests to an endpoint you might need to specify extra parameters to change the response. These extra parameters can be added while registering endpoints. Let’s look at an example of how to use arguments with an endpoint.

/**
 * This is our callback function that embeds our resource in a WP_REST_Response
 */
function prefix_get_colors( $request ) {
    // In practice this function would fetch the desired data. Here we are just making stuff up.
    $colors = array(
        'blue',
        'blue',
        'red',
        'red',
        'green',
        'green',
    );

    if ( isset( $request['filter'] ) ) {
       $filtered_colors = array();
       foreach ( $colors as $color ) {
           if ( $request['filter'] === $color ) {
               $filtered_colors[] = $color;
           }
       }
       return rest_ensure_response( $filtered_colors );
    }
    return rest_ensure_response( $colors );
}

/**
 * We can use this function to contain our arguments for the example product endpoint.
 */
function prefix_get_color_arguments() {
    $args = array();
    // Here we are registering the schema for the filter argument.
    $args['filter'] = array(
        // description should be a human readable description of the argument.
        'description' => esc_html__( 'The filter parameter is used to filter the collection of colors', 'my-text-domain' ),
        // type specifies the type of data that the argument should be.
        'type'        => 'string',
        // enum specified what values filter can take on.
        'enum'        => array( 'red', 'green', 'blue' ),
    );
    return $args;
}

/**
 * This function is where we register our routes for our example endpoint.
 */
function prefix_register_example_routes() {
    // register_rest_route() handles more arguments but we are going to stick to the basics for now.
    register_rest_route( 'my-colors/v1', '/colors', array(
        // By using this constant we ensure that when the WP_REST_Server changes our readable endpoints will work as intended.
        'methods'  => WP_REST_Server::READABLE,
        // Here we register our callback. The callback is fired when this endpoint is matched by the WP_REST_Server class.
        'callback' => 'prefix_get_colors',
        // Here we register our permissions callback. The callback is fired before the main callback to check if the current user can access the endpoint.
        'args' => prefix_get_color_arguments(),
    ) );
}

add_action( 'rest_api_init', 'prefix_register_example_routes' );

We have now specified a filter argument for this example. We can specify the argument as a query parameter when we request the endpoint. If we make a GET request to `https://ourawesomesitem.com/my-colors/v1/colors?filter=blue`, we will be returned only the blue colors in our collection. You could also pass these as body parameters in the request body, instead of in the query string. To understand the distinction between query parameters and body parameters you should read about the HTTP spec. Query parameters live in the query string tacked onto the URL and body parameters are directly embedded in the body of an HTTP request.

We have created an argument for our endpoint, but how do we verify that the argument is a string and tell whether it matches the value red, green, or blue. To do this we need to specify a validation callback for our argument.

Validation

Validation and sanitization are extremely important for security in the API. The validate callback (in WP 4.6+), fires before the sanitize callback. You should use the validate_callback for your arguments to verify whether the input you are receiving is valid. The sanitize_callback should be used to transform the argument input or clean out unwanted parts out of the argument, before the argument is processed by the main callback.

In the example above, we need to verify that the filter parameter is a string, and it matches the value red, green, or blue. Let’s look at what the code looks like after adding in a validate_callback.

/**
 * This is our callback function that embeds our resource in a WP_REST_Response
 */
function prefix_get_colors( $request ) {
    // In practice this function would fetch more practical data. Here we are just making stuff up.
    $colors = array(
        'blue',
        'blue',
        'red',
        'red',
        'green',
        'green',
    );

    if ( isset( $request['filter'] ) ) {
       $filtered_colors = array();
       foreach ( $colors as $color ) {
           if ( $request['filter'] === $color ) {
               $filtered_colors[] = $color;
           }
       }
       return rest_ensure_response( $filtered_colors );
    }
    return rest_ensure_response( $colors );
}
/**
 * Validate a request argument based on details registered to the route.
 *
 * @param  mixed            $value   Value of the 'filter' argument.
 * @param  WP_REST_Request  $request The current request object.
 * @param  string           $param   Key of the parameter. In this case it is 'filter'.
 * @return WP_Error|boolean
 */
function prefix_filter_arg_validate_callback( $value, $request, $param ) {
    // If the 'filter' argument is not a string return an error.
    if ( ! is_string( $value ) ) {
        return new WP_Error( 'rest_invalid_param', esc_html__( 'The filter argument must be a string.', 'my-text-domain' ), array( 'status' => 400 ) );
    }

    // Get the registered attributes for this endpoint request.
    $attributes = $request->get_attributes();

    // Grab the filter param schema.
    $args = $attributes['args'][ $param ];

    // If the filter param is not a value in our enum then we should return an error as well.
    if ( ! in_array( $value, $args['enum'], true ) ) {
        return new WP_Error( 'rest_invalid_param', sprintf( __( '%s is not one of %s' ), $param, implode( ', ', $args['enum'] ) ), array( 'status' => 400 ) );
    }
}

/**
 * We can use this function to contain our arguments for the example product endpoint.
 */
function prefix_get_color_arguments() {
    $args = array();
    // Here we are registering the schema for the filter argument.
    $args['filter'] = array(
        // description should be a human readable description of the argument.
        'description' => esc_html__( 'The filter parameter is used to filter the collection of colors', 'my-text-domain' ),
        // type specifies the type of data that the argument should be.
        'type'        => 'string',
        // enum specified what values filter can take on.
        'enum'        => array( 'red', 'green', 'blue' ),
        // Here we register the validation callback for the filter argument.
        'validate_callback' => 'prefix_filter_arg_validate_callback',
    );
    return $args;
}

/**
 * This function is where we register our routes for our example endpoint.
 */
function prefix_register_example_routes() {
    // register_rest_route() handles more arguments but we are going to stick to the basics for now.
    register_rest_route( 'my-colors/v1', '/colors', array(
        // By using this constant we ensure that when the WP_REST_Server changes our readable endpoints will work as intended.
        'methods'  => WP_REST_Server::READABLE,
        // Here we register our callback. The callback is fired when this endpoint is matched by the WP_REST_Server class.
        'callback' => 'prefix_get_colors',
        // Here we register our permissions callback. The callback is fired before the main callback to check if the current user can access the endpoint.
        'args' => prefix_get_color_arguments(),
    ) );
}

add_action( 'rest_api_init', 'prefix_register_example_routes' );

Sanitizing

In the above example, we do not need to use a sanitize_callback, because we are restricting input to only values in our enum. If we did not have strict validation and accepted any string as a parameter, we would definitely need to register a sanitize_callback. What if we wanted to update a content field and the user entered something like alert('ZOMG Hacking you');. The field value could potentially be an executable script. To strip out unwanted data or to transform data into a desired format we need to register a sanitize_callback for our arguments. Here is an example of how to use WordPress’s sanitize_text_field() for a sanitize callback:

/**
 * This is our callback function that embeds our resource in a WP_REST_Response.
 *
 * The parameter is already sanitized by this point so we can use it without any worries.
 */
function prefix_get_item( $request ) {
    if ( isset( $request['data'] ) ) {
        return rest_ensure_response( $request['data'] );
    }

    return new WP_Error( 'rest_invalid', esc_html__( 'The data parameter is required.', 'my-text-domain' ), array( 'status' => 400 ) );
}

/**
 * Validate a request argument based on details registered to the route.
 *
 * @param  mixed            $value   Value of the 'filter' argument.
 * @param  WP_REST_Request  $request The current request object.
 * @param  string           $param   Key of the parameter. In this case it is 'filter'.
 * @return WP_Error|boolean
 */
function prefix_data_arg_validate_callback( $value, $request, $param ) {
    // If the 'data' argument is not a string return an error.
    if ( ! is_string( $value ) ) {
        return new WP_Error( 'rest_invalid_param', esc_html__( 'The filter argument must be a string.', 'my-text-domain' ), array( 'status' => 400 ) );
    }
}

/**
 * Sanitize a request argument based on details registered to the route.
 *
 * @param  mixed            $value   Value of the 'filter' argument.
 * @param  WP_REST_Request  $request The current request object.
 * @param  string           $param   Key of the parameter. In this case it is 'filter'.
 * @return WP_Error|boolean
 */
function prefix_data_arg_sanitize_callback( $value, $request, $param ) {
    // It is as simple as returning the sanitized value.
    return sanitize_text_field( $value );
}

/**
 * We can use this function to contain our arguments for the example product endpoint.
 */
function prefix_get_data_arguments() {
    $args = array();
    // Here we are registering the schema for the filter argument.
    $args['data'] = array(
        // description should be a human readable description of the argument.
        'description' => esc_html__( 'The data parameter is used to be sanitized and returned in the response.', 'my-text-domain' ),
        // type specifies the type of data that the argument should be.
        'type'        => 'string',
        // Set the argument to be required for the endpoint.
        'required'    => true,
        // We are registering a basic validation callback for the data argument.
        'validate_callback' => 'prefix_data_arg_validate_callback',
        // Here we register the validation callback for the filter argument.
        'sanitize_callback' => 'prefix_data_arg_sanitize_callback',
    );
    return $args;
}

/**
 * This function is where we register our routes for our example endpoint.
 */
function prefix_register_example_routes() {
    // register_rest_route() handles more arguments but we are going to stick to the basics for now.
    register_rest_route( 'my-plugin/v1', '/sanitized-data', array(
        // By using this constant we ensure that when the WP_REST_Server changes our readable endpoints will work as intended.
        'methods'  => WP_REST_Server::READABLE,
        // Here we register our callback. The callback is fired when this endpoint is matched by the WP_REST_Server class.
        'callback' => 'prefix_get_item',
        // Here we register our permissions callback. The callback is fired before the main callback to check if the current user can access the endpoint.
        'args' => prefix_get_data_arguments(),
    ) );
}

add_action( 'rest_api_init', 'prefix_register_example_routes' );

Summary

We have covered the basics of registering endpoints for the WordPress REST API. Routes are the URIs that our endpoints live at. Endpoints are a collection of callbacks, methods, args, and other options. Each endpoint is mapped to a route when using register_rest_route(). An endpoint by default can support various HTTP methods, a main callback, a permissions callback, and registered arguments. We can register endpoints to cover any of our use cases for interacting with WordPress. The endpoints serve as the core interaction point with the REST API, but there are many other topics to explore and understand, to fully utilize this powerful API.

Controller Classes

Overview

To register a new REST route, you must specify a number of callback functions to control endpoint behavior such as how a request is fulfilled, how permissions checks are applied, and how the schema for your resource gets generated. While it is possible to declare all of these methods in an ordinary PHP file without any wrapping namespace or class, all functions declared in that manner coexist in the same global scope. If you decide to use a common function name for your endpoint logic like get_items() and another plugin (or another endpoint in your own plugin) also registers a function with that same name, PHP will fail with a fatal error because the function get_items() is being declared twice.

You can avoid this issue by naming your callback functions using a unique prefix such as myplugin_myendpoint_ to avoid any potential conflics:

function myplugin_myendpoint_register_routes() { /* ... */ }
function myplugin_myendpoint_get_item() { /* ... */ }
function myplugin_myendpoint_get_item_schema() { /* ... */ }
// etcetera

add_action( 'rest_api_init', 'myplugin_myendpoint_register_routes' );

You may already be familiar with this approach because it is commonly used within theme functions.php files. However these prefixes are unnecessarily verbose, and several better options exist to group and encapsulate your endpoint’s logic in a more maintainable way.

WordPress currently requires PHP 5.6 or greater. PHP 5.6 supports namespaces, which provide an easy way to encapsulate your endpoint’s functionality. By declaring a namespace at the top of your endpoint’s PHP file, all methods within that namespace will be declared within that namespace and will no longer conflict with global functions. You may then use shorter, more-readable names for your endpoint callbacks.

namespace MyPlugin\API\MyEndpoint;

function register_routes() { /* ... */ }
function get_item() { /* ... */ }
function get_item_schema() { /* ... */ }
// and so on

add_action( 'rest_api_init', __NAMESPACE__ . '\\register_routes' );

While these shorter function names are simpler to work with, they don’t provide any other benefits over declaring global functions. For this reason the core REST API endpoints within WordPress are all implemented using a controller class.

The remainder of this page details how to write your own controller class and explains the advantages of doing so.

Controllers

A controller receives input (a WP_REST_Request object, in the case of the WordPress REST API) and generates response output as WP_REST_Response objects. Let’s look at an example controller class:

class My_REST_Posts_Controller {

    // Here initialize our namespace and resource name.
    public function __construct() {
        $this->namespace     = '/my-namespace/v1';
        $this->resource_name = 'posts';
    }

    // Register our routes.
    public function register_routes() {
        register_rest_route( $this->namespace, '/' . $this->resource_name, array(
            // Here we register the readable endpoint for collections.
            array(
                'methods'   => 'GET',
                'callback'  => array( $this, 'get_items' ),
                'permission_callback' => array( $this, 'get_items_permissions_check' ),
            ),
            // Register our schema callback.
            'schema' => array( $this, 'get_item_schema' ),
        ) );
        register_rest_route( $this->namespace, '/' . $this->resource_name . '/(?P<id>[\d]+)', array(
            // Notice how we are registering multiple endpoints the 'schema' equates to an OPTIONS request.
            array(
                'methods'   => 'GET',
                'callback'  => array( $this, 'get_item' ),
                'permission_callback' => array( $this, 'get_item_permissions_check' ),
            ),
            // Register our schema callback.
            'schema' => array( $this, 'get_item_schema' ),
        ) );
    }

    /**
     * Check permissions for the posts.
     *
     * @param WP_REST_Request $request Current request.
     */
    public function get_items_permissions_check( $request ) {
        if ( ! current_user_can( 'read' ) ) {
            return new WP_Error( 'rest_forbidden', esc_html__( 'You cannot view the post resource.' ), array( 'status' => $this->authorization_status_code() ) );
        }
        return true;
    }

    /**
     * Grabs the five most recent posts and outputs them as a rest response.
     *
     * @param WP_REST_Request $request Current request.
     */
    public function get_items( $request ) {
        $args = array(
            'post_per_page' => 5,
        );
        $posts = get_posts( $args );

        $data = array();

        if ( empty( $posts ) ) {
            return rest_ensure_response( $data );
        }

        foreach ( $posts as $post ) {
            $response = $this->prepare_item_for_response( $post, $request );
            $data[] = $this->prepare_response_for_collection( $response );
        }

        // Return all of our comment response data.
        return rest_ensure_response( $data );
    }

    /**
     * Check permissions for the posts.
     *
     * @param WP_REST_Request $request Current request.
     */
    public function get_item_permissions_check( $request ) {
        if ( ! current_user_can( 'read' ) ) {
            return new WP_Error( 'rest_forbidden', esc_html__( 'You cannot view the post resource.' ), array( 'status' => $this->authorization_status_code() ) );
        }
        return true;
    }

    /**
     * Gets post data of requested post id and outputs it as a rest response.
     *
     * @param WP_REST_Request $request Current request.
     */
    public function get_item( $request ) {
        $id = (int) $request['id'];
        $post = get_post( $id );

        if ( empty( $post ) ) {
            return rest_ensure_response( array() );
        }

        $response = $this->prepare_item_for_response( $post, $request );

        // Return all of our post response data.
        return $response;
    }

    /**
     * Matches the post data to the schema we want.
     *
     * @param WP_Post $post The comment object whose response is being prepared.
     */
    public function prepare_item_for_response( $post, $request ) {
        $post_data = array();

        $schema = $this->get_item_schema( $request );

        // We are also renaming the fields to more understandable names.
        if ( isset( $schema['properties']['id'] ) ) {
            $post_data['id'] = (int) $post->ID;
        }

        if ( isset( $schema['properties']['content'] ) ) {
            $post_data['content'] = apply_filters( 'the_content', $post->post_content, $post );
        }

        return rest_ensure_response( $post_data );
    }

    /**
     * Prepare a response for inserting into a collection of responses.
     *
     * This is copied from WP_REST_Controller class in the WP REST API v2 plugin.
     *
     * @param WP_REST_Response $response Response object.
     * @return array Response data, ready for insertion into collection data.
     */
    public function prepare_response_for_collection( $response ) {
        if ( ! ( $response instanceof WP_REST_Response ) ) {
            return $response;
        }

        $data = (array) $response->get_data();
        $server = rest_get_server();

        if ( method_exists( $server, 'get_compact_response_links' ) ) {
            $links = call_user_func( array( $server, 'get_compact_response_links' ), $response );
        } else {
            $links = call_user_func( array( $server, 'get_response_links' ), $response );
        }

        if ( ! empty( $links ) ) {
            $data['_links'] = $links;
        }

        return $data;
    }

    /**
     * Get our sample schema for a post.
     *
     * @return array The sample schema for a post
     */
    public function get_item_schema() {
        if ( $this->schema ) {
            // Since WordPress 5.3, the schema can be cached in the $schema property.
            return $this->schema;
        }

        $this->schema = array(
            // This tells the spec of JSON Schema we are using which is draft 4.
            '$schema'              => 'http://json-schema.org/draft-04/schema#',
            // The title property marks the identity of the resource.
            'title'                => 'post',
            'type'                 => 'object',
            // In JSON Schema you can specify object properties in the properties attribute.
            'properties'           => array(
                'id' => array(
                    'description'  => esc_html__( 'Unique identifier for the object.', 'my-textdomain' ),
                    'type'         => 'integer',
                    'context'      => array( 'view', 'edit', 'embed' ),
                    'readonly'     => true,
                ),
                'content' => array(
                    'description'  => esc_html__( 'The content for the object.', 'my-textdomain' ),
                    'type'         => 'string',
                ),
            ),
        );

        return $this->schema;
    }

    // Sets up the proper HTTP status code for authorization.
    public function authorization_status_code() {

        $status = 401;

        if ( is_user_logged_in() ) {
            $status = 403;
        }

        return $status;
    }
}

// Function to register our new routes from the controller.
function prefix_register_my_rest_routes() {
    $controller = new My_REST_Posts_Controller();
    $controller->register_routes();
}

add_action( 'rest_api_init', 'prefix_register_my_rest_routes' );

Benefits of Classes

This class contains all the same components you may have written using simple functions. The structure of a class gives us a convenient way to refer to related methods using the $this->method_name() syntax, but unlike a namespace the class also permits us to cache values and share logic.

In the get_item_schema method, note that we store the generated schema on the class as $this->schema. Class properties make it easy to cache these sorts of generated values. The introduction of schema caching in WordPress 5.3 increased the speed of some core REST API collection responses by up to 40%, so you should definitely consider following this pattern in your own controllers.

Class Inheritance & WP_REST_Controller

We’ve seen above how classes solve the global-function encapsulation issue, and how a class instance can be used to cache complex values to speed up response processing. The other major advantage of classes is the way in which class inheritance lets you share logic between multiple endpoints.

Our example class here did not extend any base class, but within WordPress core all endpoint controllers extend a single abstract controller class called WP_REST_Controller. Extending this class gives you access to a number of useful methods, including but not limited to:

Endpoint-specific methods like get_item, register_routes, and update_item_permissions_check are not fully implemented by the abstract class, and must be defined in your own class.

Visit the WP_REST_Controller class reference page for a complete list of this controller’s methods.

It is important to note that WP_REST_Controller is implemented as an abstract class and only contains logic that is clearly needed in multiple classes. Inheritance couples your class to the base class it extends, and poorly-considered inheritance trees can make your endpoints much harder to maintain.

As an example, if you wrote a controller class for a posts endpoint (like the example above) and wanted to support custom post types as well, you should NOT extend your My_REST_Posts_Controller like this: class My_CPT_REST_Controller extends My_REST_Posts_Controller. Instead, you should either create an entirely separate base controller class for the shared logic, or make My_REST_Posts_Controller handle all available post types. Endpoint logic is subject to changing business requirements, and you don’t want to have to change a number of unrelated controllers every time you update your base posts controller.

In most cases you will want to create a base controller class as either an interface or abstract class which each of your endpoint controllers can implement or extend, or to extend one of the core WordPress REST classes directly.

Internal WordPress REST API Classes

The WordPress REST API follows a deliberate design pattern for its internal classes, which may be categorized as either infrastructure or endpoint classes.

Endpoint classes encapsulate the functional logic necessary to perform CRUD operations on WordPress resources. WordPress exposes many REST API endpoints (such as WP_REST_Posts_Controller), but as discussed above all endpoints extend from a common base controller class:

Infrastructure classes support the endpoint classes. They handle the logic for the WordPress REST API without performing any data transformation. The WordPress REST API implements three key infrastructure classes:

Most types of API-driven application will not require you to extend or interact directly with the infrastructure layer, but if you are implementing your own REST API endpoints your application will likely benefit from one or more endpoint controller classes which extend WP_REST_Controller.

Schema

Overview

A schema is metadata that tells us how our data is structured. Most databases implement some form of schema which enables us to reason about our data in a more structured manner. The WordPress REST API utilizes JSON Schema to handle the structuring of its data. You can implement endpoints without using a schema, but you will be missing out on a lot of things. It is up to you to decide what suits you best.

JSON

First, let’s talk about JSON a bit. JSON is a human readable data format that resembles JavaScript objects. JSON stands for JavaScript Object Notation. JSON is growing wildly in popularity and seems to be taking the world of data structure by storm. The WordPress REST API uses a special specification for JSON known as JSON schema. To learn more about JSON Schema please check out the JSON Schema website and this easier to understand introduction to JSON Schema. Schema affords us many benefits: improved testing, discoverability, and overall better structure. Let’s look at a JSON blob of data.

{
    "shouldBeArray": 'LOL definitely not an array',
    "shouldBeInteger": ['lolz', 'you', 'need', 'schema'],
    "shouldBeString": 123456789
}

A JSON parser will go through that data no problem and won’t complain about anything, because it is valid JSON. The clients and servers know nothing about the data and what to expect they just see the JSON. By implementing schema we can actually simplify our codebase. Schema will help structure our data better so our applications can more easily reason about our interactions with the WordPress REST API. The WordPress REST API does not force you to use schema, but it is encouraged. There are two ways in which schema data is incorporated into the API; schema for resources and schema for our registered arguments.

Resource Schema

The schema for a resource indicates what fields are present for a particular object. When we register our routes we can also specify the resource schema for the route. Let’s look at what a simple comment schema might look like in a PHP representation of JSON schema.

// Register our routes.
function prefix_register_my_comment_route() {
    register_rest_route( 'my-namespace/v1', '/comments', array(
        // Notice how we are registering multiple endpoints the 'schema' equates to an OPTIONS request.
        array(
            'methods'  => 'GET',
            'callback' => 'prefix_get_comment_sample',
        ),
        // Register our schema callback.
        'schema' => 'prefix_get_comment_schema',
    ) );
}

add_action( 'rest_api_init', 'prefix_register_my_comment_route' );

/**
 * Grabs the five most recent comments and outputs them as a rest response.
 *
 * @param WP_REST_Request $request Current request.
 */
function prefix_get_comment_sample( $request ) {
    $args = array(
        'number' => 5,
    );
    $comments = get_comments( $args );

    $data = array();

    if ( empty( $comments ) ) {
        return rest_ensure_response( $data );
    }

    foreach ( $comments as $comment ) {
        $response = prefix_rest_prepare_comment( $comment, $request );
        $data[] = prefix_prepare_for_collection( $response );
    }

    // Return all of our comment response data.
    return rest_ensure_response( $data );
}

/**
 * Matches the comment data to the schema we want.
 *
 * @param WP_Comment $comment The comment object whose response is being prepared.
 */
function prefix_rest_prepare_comment( $comment, $request ) {
    $comment_data = array();

    $schema = prefix_get_comment_schema();

    // We are also renaming the fields to more understandable names.
    if ( isset( $schema['properties']['id'] ) ) {
        $comment_data['id'] = (int) $comment->comment_ID;
    }

    if ( isset( $schema['properties']['author'] ) ) {
        $comment_data['author'] = (int) $comment->user_id;
    }

    if ( isset( $schema['properties']['content'] ) ) {
        $comment_data['content'] = apply_filters( 'comment_text', $comment->comment_content, $comment );
    }

    return rest_ensure_response( $comment_data );
}

/**
 * Prepare a response for inserting into a collection of responses.
 *
 * This is copied from WP_REST_Controller class in the WP REST API v2 plugin.
 *
 * @param WP_REST_Response $response Response object.
 * @return array Response data, ready for insertion into collection data.
 */
function prefix_prepare_for_collection( $response ) {
    if ( ! ( $response instanceof WP_REST_Response ) ) {
        return $response;
    }

    $data  = (array) $response->get_data();
    $links = rest_get_server()::get_compact_response_links( $response );

    if ( ! empty( $links ) ) {
        $data['_links'] = $links;
    }

    return $data;
}

/**
 * Get our sample schema for comments.
 */
function prefix_get_comment_schema() {
    $schema = array(
        // This tells the spec of JSON Schema we are using which is draft 4.
        '$schema'              => 'http://json-schema.org/draft-04/schema#',
        // The title property marks the identity of the resource.
        'title'                => 'comment',
        'type'                 => 'object',
        // In JSON Schema you can specify object properties in the properties attribute.
        'properties'           => array(
            'id' => array(
                'description'  => esc_html__( 'Unique identifier for the object.', 'my-textdomain' ),
                'type'         => 'integer',
                'context'      => array( 'view', 'edit', 'embed' ),
                'readonly'     => true,
            ),
            'author' => array(
                'description'  => esc_html__( 'The id of the user object, if author was a user.', 'my-textdomain' ),
                'type'         => 'integer',
            ),
            'content' => array(
                'description'  => esc_html__( 'The content for the object.', 'my-textdomain' ),
                'type'         => 'string',
            ),
        ),
    );

    return $schema;
}

If you notice, each comment resource now matches up to our schema that we specified. We made this switch in prefix_rest_prepare_comment(). By creating schema for our resources, we can now view this schema by making OPTIONS requests. Why is this useful? If we wanted other languages, JavaScript for example, to interpret our data and validate the data from our endpoint, JavaScript would need to know how our data is structured. When we provide schema, we open the doors for other authors, and ourselves, to build on top of our endpoints in a consistent manner. Schema provides machine readable data, so potentially anything that can read JSON can understand what kind of data it is looking at. When we look at the API index by making a GET request to https://ourawesomesite.com/wp-json/`, we are returned the schema of our API, enabling others to write client libraries to interpret our data. This process of reading schema data is known as discovery. When we have provided schema for a resource we make that resource discoverable viaOPTIONS` requests to that route. Exposing resource schema is only one part of our schema puzzle. We also want to use schema for our registered arguments.

Argument Schema

When we register request arguments for an endpoint, we can also use JSON Schema to provide us data about what the arguments should be. This enables us to write validation libraries that can be reused as our endpoints expand. Schema is more work upfront, but if you are going to write a production application that will grow, you should definitely consider using schema. Let’s look at an example of using argument schema and validation.

// Register our routes.
function prefix_register_my_arg_route() {
    register_rest_route( 'my-namespace/v1', '/schema-arg', array(
        // Here we register our endpoint.
        array(
            'methods'  => 'GET',
            'callback' => 'prefix_get_item',
            'args' => prefix_get_endpoint_args(),
        ),
    ) );
}

// Hook registration into 'rest_api_init' hook.
add_action( 'rest_api_init', 'prefix_register_my_arg_route' );

/**
 * Returns the request argument `my-arg` as a rest response.
 *
 * @param WP_REST_Request $request Current request.
 */
function prefix_get_item( $request ) {
    // If we didn't use required in the schema this would throw an error when my arg is not set.
    return rest_ensure_response( $request['my-arg'] );
}

/**
 * Get the argument schema for this example endpoint.
 */
function prefix_get_endpoint_args() {
    $args = array();

    // Here we add our PHP representation of JSON Schema.
    $args['my-arg'] = array(
        'description'       => esc_html__( 'This is the argument our endpoint returns.', 'my-textdomain' ),
        'type'              => 'string',
        'validate_callback' => 'prefix_validate_my_arg',
        'sanitize_callback' => 'prefix_sanitize_my_arg',
        'required'          => true,
    );

    return $args;
}

/**
 * Our validation callback for `my-arg` parameter.
 *
 * @param mixed           $value   Value of the my-arg parameter.
 * @param WP_REST_Request $request Current request object.
 * @param string          $param   The name of the parameter in this case, 'my-arg'.
 * @return true|WP_Error True if the data is valid, WP_Error otherwise.
 */
function prefix_validate_my_arg( $value, $request, $param ) {
    $attributes = $request->get_attributes();

    if ( isset( $attributes['args'][ $param ] ) ) {
        $argument = $attributes['args'][ $param ];
        // Check to make sure our argument is a string.
        if ( 'string' === $argument['type'] && ! is_string( $value ) ) {
            return new WP_Error( 'rest_invalid_param', sprintf( esc_html__( '%1$s is not of type %2$s', 'my-textdomain' ), $param, 'string' ), array( 'status' => 400 ) );
        }
    } else {
        // This code won't execute because we have specified this argument as required.
        // If we reused this validation callback and did not have required args then this would fire.
        return new WP_Error( 'rest_invalid_param', sprintf( esc_html__( '%s was not registered as a request argument.', 'my-textdomain' ), $param ), array( 'status' => 400 ) );
    }

    // If we got this far then the data is valid.
    return true;
}

/**
 * Our sanitization callback for `my-arg` parameter.
 *
 * @param mixed           $value   Value of the my-arg parameter.
 * @param WP_REST_Request $request Current request object.
 * @param string          $param   The name of the parameter in this case, 'my-arg'.
 * @return mixed|WP_Error The sanitize value, or a WP_Error if the data could not be sanitized.
 */
function prefix_sanitize_my_arg( $value, $request, $param ) {
    $attributes = $request->get_attributes();

    if ( isset( $attributes['args'][ $param ] ) ) {
        $argument = $attributes['args'][ $param ];
        // Check to make sure our argument is a string.
        if ( 'string' === $argument['type'] ) {
            return sanitize_text_field( $value );
        }
    } else {
        // This code won't execute because we have specified this argument as required.
        // If we reused this validation callback and did not have required args then this would fire.
        return new WP_Error( 'rest_invalid_param', sprintf( esc_html__( '%s was not registered as a request argument.', 'my-textdomain' ), $param ), array( 'status' => 400 ) );
    }

    // If we got this far then something went wrong don't use user input.
    return new WP_Error( 'rest_api_sad', esc_html__( 'Something went terribly wrong.', 'my-textdomain' ), array( 'status' => 500 ) );
}

In the example above we have abstracted away from using the 'my-arg' name. We can use these validation and sanitizing functions for any other argument that should be a string we have specified schema for. As your codebase and endpoints grow, schema will help keep your code lightweight and maintainable. Without schema you can validate and sanitize, however it will be more difficult to keep track of which functions should be validating what. By adding schema to request arguments we can also expose our argument schema to clients, so validation libraries can be built client side which can help performance by preventing invalid requests from ever being sent to the API.

If you are uncomfortable with using schema, it is still possible to have validate/sanitize callbacks for each of your arguments, and in some cases it will make the most sense to do a custom validation.

Summary

Schema can seem silly at points and possibly like unnecessary work, but if you want maintainable, discoverable, and easily extensible endpoints, it is essential to use schema. Schema also helps to self document your endpoints both for humans and computers!

JSON Schema Basics

WordPress implements a validator that uses a subset of the JSON Schema Version 4 specification. The RFC is recommended reading to gain a deeper understanding of how JSON Schema works, but this article will describe the basics of JSON Schema and what features WordPress supports.

API

The REST API defines two main functions for using JSON Schema: rest_validate_value_from_schema and rest_sanitize_value_from_schema. Both functions accept the request data as the first parameter, the parameter’s schema definition as the second parameter, and optionally the parameter’s name as the third parameter. The validate function returns either true or a WP_Error instance depending on if the data successfully validates against the schema. The sanitize function returns a sanitized form of the data passed to the function, or a WP_Error instance if the data cannot be safely sanitized. When calling these functions, you should take care to always first validate the data using rest_validate_value_from_schema, and then if that function returns true, sanitize the data using rest_sanitize_value_from_schema. Not using both can open up your endpoint to security vulnerabilities. If your endpoint is implemented using a subclass of WP_REST_Controller, the WP_REST_Controller::get_endpoint_args_for_item_schema method will automatically mark your arguments as using the built-in validate and sanitize callbacks. As such, there is no need to manually specify the callbacks. If your endpoint does not follow the controller class pattern, args returned from WP_REST_Controller::get_collection_params(), or any other instance where callbacks are not specified, the WP_REST_Request object will apply sanitization and validation using the rest_parse_request_arg function. Importantly, this is only applied when the sanitize_callback is not defined. As such, if you specify a custom sanitize_callback for your argument definition, the built-in JSON Schema validation will not apply. If you need this validation, you should manually specify rest_validate_request_arg as the validate_callback in your argument definition.

Caching Schema

Schema may be complex, and can take time to generate. You should consider caching generated schema in your plugin’s custom endpoints to avoid repeatedly generating the same schema object. If you are defining your endpoint using a a subclass of WP_REST_Controller, that might look like this:


    /**
     * Retrieves the attachment's schema, conforming to JSON Schema.
     *
     * @return array Item schema as an array.
     */
    public function get_item_schema() {
        // Returned cached copy whenever available.
        if ( $this->schema ) {
            return $this->add_additional_fields_schema( $this->schema );
        }

        $schema = parent::get_item_schema();
        // Add endpoint-specific properties to Schema.
        $schema['properties']['field_name'] = array( /* ... */ );
        $schema['properties']['etcetera'] = array( /* ... */ );

        // Cache generated schema on endpoint instance.
        $this->schema = $schema;

        return $this->add_additional_fields_schema( $this->schema );
    }

This pattern was introduced into WordPress core in version 5.3 in #47871, and yielded up to 40% speed improvement when generating some API responses.

Schema Documents

A basic schema document consists of a few properties.

Primitive Types

JSON Schema defines a list of seven allowed primitive types.

A value’s primitive type is specified using the type keyword. For example, this is how you would define a string value with JSON Schema.

array(
    'type' => 'string',
);

JSON Schema allows for defining values that can be multiple types. For example, this is how you would define a value that can be either a string or a boolean.

array(
    'type' => array( 'boolean', 'string' ),  
);

Type Juggling

Because the WordPress REST API accepts URL form encoded data both in the POST body or as the query portion of the URL, many primtive types perform type juggling to convert these string values into their proper native types.

When using multiple types, types will be evaluated in the order they are specified. This can have an impact on the sanitized data received by your REST API endpoint. For instance, in the previous example, if the value submitted was "1", it would be sanitized to the boolean true value. However, if the order was flipped, the value would remain as the string "1".

The JSON Schema specification allows for defining schemas without a type field. The WordPress implementation however requires a type to be defined, and will issue a _doing_it_wrong notice if a type is ommitted.

Format

The seven primitive types are just that, primitive, so how do you define more complex value types? One of the ways to do that is using the format keyword. The format keyword allows for defining additional semantic-level validation of values that have a well-defined structure. For example, to require a date value, you would use the date-time format.

array(
    'type'   => 'string',
    'format' => 'date-time',
);

WordPress supports the following formats:

A value must match its format even if the value is an empty string. If allowing an “empty” value is desired, add null as a possible type. For example, the following schema would allow 127.0.0.1 or null as possible values.

array(
    'type'   => array( 'string', 'null' ),
    'format' => 'ip',
);

Strings

The string types supports three additional keywords.

minLength and maxLength

The minLength and maxLength keywords can be used to constrain the acceptable length of a string. Importantly multi-byte characters are counted as a single character and bounds are inclusive. For instance, given the following schema, ab, abc, and abcd are valid, while a, and abcde are invalid.

array(
    'type'      => 'string',
    'minLength' => 2,
    'maxLength' => 4,
);

The exclusiveMinimum and exclusiveMaximum keywords do not apply, they are only valid for numbers.

pattern

The JSON Schema keyword pattern can be used to validate that a string field matches a regular expression. For instance, given the following schema, #123 would be valid, but #abc would not.

array(
    'type'    => 'string',
    'pattern' => '#[0-9]+',
);

The regex is not automatically anchored. Regex flags, for instance /i to make the match case insensitive are not supported. The JSON Schema RFC recommends limiting yourself to the following regex features so the schema can be interoperable between as many different programming languages as possible.

The pattern should be valid according to the ECMA 262 regex dialect.

Numbers

The number and integer types support four additional keywords.

minimum and maximum

The minimum and maximum keyword allow constraining the range of acceptable numbers. For example, 2 would be valid according to this schema, but 0 and 4 would not be.

array(
    'type' => 'integer',
    'minimum' => 1,
    'maximum' => 3,
);

JSON Schema also allows using the exclusiveMinimum and exclusiveMaximum keywords to denote that the value cannot equal the defined minimum or maximum respectively. For example, in this case only 2 would be an acceptable value.

array(
    'type'             => 'integer',
    'minimum'          => 1,
    'exclusiveMinimum' => true,
    'maximum'          => 3,
    'exclusiveMaximum' => true,
);

multipleOf

The multipleOf keyword allows for asserting an integer or number type is a multiple of the given number. For example, this schema will only accept even integers.

array(
    'type'       => 'integer',
    'multipleOf' => 2,
);

multipleOf also supports decimals. For example, this schema could be used to accept a percentage with a maximum of 1 decimal point.

array(
    'type'       => 'number',
    'minimum'    => 0,
    'maximum'    => 100,
    'multipleOf' => 0.1,
);

Arrays

Specifying a type of array requires data to be an array, but that is only half the validation story. You’ll also want to enforce the format of each item in the array. This is done by specifying a JSON Schema that each array item must conform to using the items keyword. For example, the following schema requires an array of IP addresses.

array(
    'type'  => 'array',
    'items' => array(
        'type'   => 'string',
        'format' => 'ip',
    ),
);

This would pass validation.

[ "127.0.0.1", "255.255.255.255" ]

While this would fail validation.

[ "127.0.0.1", 5 ]

The items schema can be any schema, it could even be an array itself!

array(
    'type'  => 'array',
    'items' => array(
        'type'  => 'array',
        'items' => array(
            'type'   => 'string',
            'format' => 'hex-color',
        ),
    ),
);

This would pass validation.

[
  [ "#ff6d69", "#fecc50" ],
  [ "#0be7fb" ]
]

While this would fail validation.

[
  [ "#ff6d69", "#fecc50" ],
  "george"
]

minItems and maxItems

The minItems and maxItems keywords can be used to constrain the acceptable number of items included in the array. For instance, given the following schema, [ "a" ] and [ "a", "b" ] are valid, while [] and [ "a", "b", "c" ] are invalid.

array(
    'type'     => 'array',
    'minItems' => 1,
    'maxItems' => 2,
    'items'    => array(
        'type' => 'string',
    ),
);

The exclusiveMinimum and exclusiveMaximum keywords do not apply, they are only valid for the number and integer types.

uniqueItems

The uniqueItems keyword can be used to require that all items in the array are unique. For instance, given the following schema, [ "a", "b" ] is valid, while [ "a", "a" ] is not.

array(
    'type'        => 'array',
    'uniqueItems' => true,
    'items'       => array(
        'type' => 'string',
    ),
);
Uniqueness

Items of different types are considered unique, for instance, "1", 1 and 1.0 are different values. When arrays are compared, the order of items matters. So the given array is considered to have all unique items.

[
  [ "a", "b" ],
  [ "b", "a" ]
]

When objects are compared, the order the members appear in does not matter. So the given array is considered to have duplicate items since the values are the same, they just appear in a different order.

[
  { 
    "a": 1,
    "b": 2
  },
  {
    "b": 2,
    "a": 1
  }
]

Uniqueness is checked in both rest_validate_value_from_schema and rest_sanitize_value_from_schema. This is to prevent instances where items would be considered unique before sanitization is applied, but after sanitization the items would converge to identical values. Take for instance the following schema:

array(
    'type' => 'array',
    'uniqueItems' => true,
    'items' => array(
        'type' => 'string',
        'format' => 'uri',
    ),
);

A request with [ "https://example.org/hello world", "https://example.org/hello%20world" ] would pass validation because each string value is different. However, after esc_url_raw converted the space in the first url to %20 the values would be identical. In this case rest_sanitize_value_from_schema would return an error. As such, you should always validate and sanitize parameters.

Objects

Specifying a type of object requires data to be an object, but that is only half the validation story. You’ll also want to enforce the format of each object’s property. This is done by specifying a map of property names to JSON Schemas that object members must conform to using the properties keyword. For example, the following schema requires an object where the property name is a string and color is a hex color.

array(
    'type'       => 'object',
    'properties' => array(
        'name'  => array(
            'type' => 'string',
        ),
        'color' => array(
            'type'   => 'string',
            'format' => 'hex-color',        
        ),
    ),
);

This would pass validation.

{
  "name": "Primary",
  "color": "#ff6d69"
}

While this would fail validation.

{
  "name": "Primary",
  "color": "orange"
}

Required Properties

By default, any properties listed for an object are optional, so while it might be unexpected, the following would also pass validation for the previous schema.

{
  "name": "Primary"
}

There are two mechanisms for requiring a property to be provided.

Version 3 Syntax

While WordPress mostly follows JSON Schema Version 4, one way that it doesn’t is with the syntax for defining required properties. The predominant way is using JSON Schema Version 3 syntax by adding the required keyword to each property’s definition.

array(
    'type'       => 'object',
    'properties' => array(
        'name'  => array(
            'type'     => 'string',
            'required' => true,
        ),
        'color' => array(
            'type'     => 'string',
            'format'   => 'hex-color',
            'required' => true,        
        ),
    ),
);
Version 4 syntax

WordPress also supports JSON Schema Version 4 required property syntax where the list of required properties for an object is defined as an array of property names. This can be particularly helpful when specifying that a meta value has a list of required properties. Given the following meta field.

register_post_meta( 'post', 'fixed_in', array(
    'type'         => 'object',
    'show_in_rest' => array(
        'single' => true,
        'schema' => array(
            'required'   => array( 'revision', 'version' ),
            'type'       => 'object',
            'properties' => array(
                'revision' => array(
                    'type' => 'integer',
                ),
                'version'  => array(
                    'type' => 'string',
                ),
            ),
        ),
    ),
) );

The following request would fail validation.

{
    "title": "Check required properties",
    "content": "We should check that required properties are provided",
    "meta": {
        "fixed_in": {
            "revision": 47089
        }
    }
}

If the fixed_in meta field was omitted entirely, no error would be generated. An object that defines a list of required properties does not indicate that the object itself is required to be submitted. Just that if the object is included, that the listed properties must also be included as well. Version 4 syntax is not supported for an endpoint’s top level schema in WP_REST_Controller::get_item_schema(). Given the following schema, a user could successfully submit a request without the title or content properties. This is because the schema document is not itself used for validation, but instead transformed to a list of parameter definitions.

array(
    '$schema'    => 'http://json-schema.org/draft-04/schema#',
    'title'      => 'my-endpoint',
    'type'       => 'object',
    'required'   => array( 'title', 'content' ),
    'properties' => array(
        'title'   => array(
            'type' => 'string',
        ),
        'content' => array(
            'type' => 'string',
        ),
    ),
);

additionalProperties

Perhaps unintuitively, by default JSON Schema also allows providing additional properties that are not specified in the schema. As such, the following would pass validation.

{
  "name": "Primary",
  "color": "#ff6d69",
  "description": "The primary color to use in the theme."
}

This can be customized using the additionalProperties keyword. Setting additionalProperties to false will reject data that has unknown properties.

array(
    'type'                 => 'object',
    'additionalProperties' => false,
    'properties'           => array(
        'name'  => array(
            'type' => 'string',
        ),
        'color' => array(
            'type'   => 'string',
            'format' => 'hex-color',        
        ),
    ),
);

The additionalProperties keyword can also be set to a schema of its own. This would require that the values for any unknown properties match the given schema. One way this can be helpful is when you want to accept a list of values that each have their own unique key. For example:

array(
    'type'                 => 'object',
    'properties'           => array(),
    'additionalProperties' => array(
        'type'       => 'object',
        'properties' => array(
            'name'  => array(
                'type'     => 'string',
                'required' => true,
            ),
            'color' => array(
                'type'     => 'string',
                'format'   => 'hex-color',
                'required' => true,        
            ),
        ),    
    ),
);

This would pass validation.

{
  "primary": {
    "name": "Primary",
    "color": "#ff6d69"
  },
  "secondary": {
    "name": "Secondary",
    "color": "#fecc50"
  }
}

While this would fail validation.

{
  "primary": {
    "name": "Primary",
    "color": "#ff6d69"
  },
  "secondary": "#fecc50"
}

patternProperties

The patternProperties keyword is similar to the additionalProperties keyword, but allows for asserting the property matches a regex pattern. The keyword is an object where each property is a regex pattern and its value is the JSON Schema used to validate properties that match that pattern. For example, this schema requires that each value is a hex color and the property must only contain “word” characters.

array(
  'type'                 => 'object',
  'patternProperties'    => array(
    '^\\w+$' => array(
      'type'   => 'string',
      'format' => 'hex-color',
    ),
  ),
  'additionalProperties' => false,
);

This would pass validation.

{
  "primary": "#ff6d69",
  "secondary": "#fecc50"
}

While this would fail validation.

{
  "primary": "blue",
  "$secondary": "#fecc50"
}

When the REST API validates the patternProperties schema, if a property doesn’t match any of the patterns, the property will be allowed and not have any validation applied to its contents. While this may be confusing, it behaves the same as the properties keyword. If this logic isn’t desired, add additionalProperties to the schema to disallow non-matching properties.

minProperties and maxProperties

The minItems and maxItems keywords can be used for the array type. The minProperties and maxProperties introduces this same functionality for the object type. This can be helpful when using additionalProperties to have a list of objects with unique keys.

array(
  'type'                 => 'object',
  'additionalProperties' => array(
    'type'   => 'string',
    'format' => 'hex-color',
  ),
  'minProperties'        => 1,
  'maxProperties'        => 3,
);

This would pass validation.

{
  "primary": "#52accc",
  "secondary": "#096484"
}

While this would fail validation.

{
  "primary": "#52accc",
  "secondary": "#096484",
  "tertiary": "#07526c"
}

The exclusiveMinimum and exclusiveMaximum keywords do not apply, they are only valid for the number and integer types.

Type agnostic keywords

oneOf and anyOf

These are advanced keywords that allow for the JSON Schema validator to choose one of many schemas to use when validating a value. The anyOf keyword allows for a value to match at least one of the given schemas. Whereas, the oneOf keyword requires the value match exactly one schema. For example, this schema allows for submitting an array of “operations” to an endpoint. Each operation can either be a “crop” or a “rotation”.

array(
    'type'  => 'array',
    'items' => array(
        'oneOf' => array(
            array(
                'title'      => 'Crop',
                'type'       => 'object',
                'properties' => array(
                    'operation' => array(
                        'type' => 'string',
                        'enum' => array(
                            'crop',
                        ),
                    ),
                    'x'         => array(
                        'type' => 'integer',
                    ),
                    'y'         => array(
                        'type' => 'integer',
                    ),
                ),
            ),
            array(
                'title'      => 'Rotation',
                'type'       => 'object',
                'properties' => array(
                    'operation' => array(
                        'type' => 'string',
                        'enum' => array(
                            'rotate',
                        ),
                    ),
                    'degrees'   => array(
                        'type'    => 'integer',
                        'minimum' => 0,
                        'maximum' => 360,
                    ),
                ),
            ),
        ),
    ),
);

The REST API will loop over each schema specified in the oneOf array and look for a match. If exactly one schema matches, then validation will succeed. If more than one schema matches, validation will fail. If no schemas match, then the validator will try to find the closest matching schema and return an appropriate error message.

operations[0] is not a valid Rotation. Reason: operations[0][degrees] must be between 0 (inclusive) and 360 (inclusive)

To generate more helpful error messages, it is highly recommended to give each oneOf or anyOf schema a title property.

Changelog

WordPress 5.6

WordPress 5.5

WordPress 5.4

WordPress 5.3

WordPress 4.9

Adding REST API Support For Custom Content Types

The REST API can create routes for custom post types and custom taxonomies inside of the wp/v2 namespace, using the same controllers as the default post type or taxonomy term controllers. Alternatively, you can use your own controllers and namespace. This document will cover using the default controllers for your custom content type’s API routes. This is the easiest way and ensures the highest chance of compatibility with third parties.

Registering A Custom Post Type With REST API Support

When registering a custom post type, if you want it to be available via the REST API you should set 'show_in_rest' => true in the arguments passed to register_post_type. Setting this argument to true will add a route in the wp/v2 namespace.

/**
 * Register a book post type, with REST API support
 *
 * Based on example at: https://developer.wordpress.org/reference/functions/register_post_type
 */
add_action( 'init', 'my_book_cpt' );
function my_book_cpt() {
    $args = array(
      'public'       => true,
      'show_in_rest' => true,
      'label'        => 'Books'
    );
    register_post_type( 'book', $args );
}

You can optionally set the rest_base argument to change the base url, which will otherwise default to the post type’s name. In the example below, “books” is used as the value of rest_base. This will make the URL for the route wp-json/wp/v2/books instead of wp-json/wp/v2/book/, which would have been the default.

In addition, you can pass an argument for rest_controller_class. This class must be a subclass of WP_REST_Controller. By default, WP_REST_Posts_Controller is used as the controller. If you are using a custom controller, then you likely will not be within the wp/v2 namespace.

Here is an example of registering a post type, with full labels, support for the REST API, a customized rest_base, and explicit registry of the default controller:

/**
 * Register a book post type, with REST API support
 *
 * Based on example at: https://developer.wordpress.org/reference/functions/register_post_type
 */
add_action( 'init', 'my_book_cpt' );
function my_book_cpt() {
  $labels = array(
    'name'               => _x( 'Books', 'post type general name', 'your-plugin-textdomain' ),
    'singular_name'      => _x( 'Book', 'post type singular name', 'your-plugin-textdomain' ),
    'menu_name'          => _x( 'Books', 'admin menu', 'your-plugin-textdomain' ),
    'name_admin_bar'     => _x( 'Book', 'add new on admin bar', 'your-plugin-textdomain' ),
    'add_new'            => _x( 'Add New', 'book', 'your-plugin-textdomain' ),
    'add_new_item'       => __( 'Add New Book', 'your-plugin-textdomain' ),
    'new_item'           => __( 'New Book', 'your-plugin-textdomain' ),
    'edit_item'          => __( 'Edit Book', 'your-plugin-textdomain' ),
    'view_item'          => __( 'View Book', 'your-plugin-textdomain' ),
    'all_items'          => __( 'All Books', 'your-plugin-textdomain' ),
    'search_items'       => __( 'Search Books', 'your-plugin-textdomain' ),
    'parent_item_colon'  => __( 'Parent Books:', 'your-plugin-textdomain' ),
    'not_found'          => __( 'No books found.', 'your-plugin-textdomain' ),
    'not_found_in_trash' => __( 'No books found in Trash.', 'your-plugin-textdomain' )
  );

  $args = array(
    'labels'             => $labels,
    'description'        => __( 'Description.', 'your-plugin-textdomain' ),
    'public'             => true,
    'publicly_queryable' => true,
    'show_ui'            => true,
    'show_in_menu'       => true,
    'query_var'          => true,
    'rewrite'            => array( 'slug' => 'book' ),
    'capability_type'    => 'post',
    'has_archive'        => true,
    'hierarchical'       => false,
    'menu_position'      => null,
    'show_in_rest'       => true,
    'rest_base'          => 'books',
    'rest_controller_class' => 'WP_REST_Posts_Controller',
    'supports'           => array( 'title', 'editor', 'author', 'thumbnail', 'excerpt', 'comments' )
  );

  register_post_type( 'book', $args );
}

If you are using a custom rest_controller_class, then the REST API is unable to automatically determine the route for a given post. In this case, you can use the rest_route_for_post filter to provide this information. This allows for your custom post type to be properly formatted in the Search endpoint and enables automated discovery links.

function my_plugin_rest_route_for_post( $route, $post ) {
    if ( $post->post_type === 'book' ) {
        $route = '/wp/v2/books/' . $post->ID;
    }

    return $route;
}
add_filter( 'rest_route_for_post', 'my_plugin_rest_route_for_post', 10, 2 );

Registering A Custom Taxonomy With REST API Support

Registering a custom taxonomy with REST API support is very similar to registering a custom post type: pass 'show_in_rest' => true in the arguments passed to register_taxonomy. You may optionally pass rest_base to change the base url for the taxonomy’s routes.

The default controller for taxonomies is WP_REST_Terms_Controller. You may modify this with the rest_controller_class if you choose to use a custom controller.

Here is an example of how to register a custom taxonomy with REST API support:

/**
 * Register a genre post type, with REST API support
 *
 * Based on example at: https://developer.wordpress.org/reference/functions/register_taxonomy/
 */
add_action( 'init', 'my_book_taxonomy', 30 );
function my_book_taxonomy() {

  $labels = array(
    'name'              => _x( 'Genres', 'taxonomy general name' ),
    'singular_name'     => _x( 'Genre', 'taxonomy singular name' ),
    'search_items'      => __( 'Search Genres' ),
    'all_items'         => __( 'All Genres' ),
    'parent_item'       => __( 'Parent Genre' ),
    'parent_item_colon' => __( 'Parent Genre:' ),
    'edit_item'         => __( 'Edit Genre' ),
    'update_item'       => __( 'Update Genre' ),
    'add_new_item'      => __( 'Add New Genre' ),
    'new_item_name'     => __( 'New Genre Name' ),
    'menu_name'         => __( 'Genre' ),
  );

  $args = array(
    'hierarchical'          => true,
    'labels'                => $labels,
    'show_ui'               => true,
    'show_admin_column'     => true,
    'query_var'             => true,
    'rewrite'               => array( 'slug' => 'genre' ),
    'show_in_rest'          => true,
    'rest_base'             => 'genre',
    'rest_controller_class' => 'WP_REST_Terms_Controller',
  );

  register_taxonomy( 'genre', array( 'book' ), $args );

}

If you are using a custom rest_controller_class, then the REST API is unable to automatically determine the route for a given term. In this case, you can use the rest_route_for_term filter to provide this information. This allows for your custom taxonomy to be properly formatted in the Search endpoint and enables automated discovery links.

function my_plugin_rest_route_for_term( $route, $term ) {
    if ( $term->taxonomy === 'genre' ) {
        $route = '/wp/v2/genre/' . $term->term_id;
    }

    return $route;
}
add_filter( 'rest_route_for_term', 'my_plugin_rest_route_for_term', 10, 2 );

Adding REST API Support To Existing Content Types

If you need to add REST API support for a custom post type or custom taxonomy you do not control, for example a theme or plugin you are using, you can use the register_post_type_args filter hook that exists since WordPress version 4.6.0.

/**
 * Add REST API support to an already registered post type.
 */
add_filter( 'register_post_type_args', 'my_post_type_args', 10, 2 );

function my_post_type_args( $args, $post_type ) {

    if ( 'book' === $post_type ) {
        $args['show_in_rest'] = true;

        // Optionally customize the rest_base or rest_controller_class
        $args['rest_base']             = 'books';
        $args['rest_controller_class'] = 'WP_REST_Posts_Controller';
    }

    return $args;
}

For custom taxonomies it is almost the same. You can use the register_taxonomy_args filter that exists since WordPress version 4.4.0.

/**
 * Add REST API support to an already registered taxonomy.
 */
add_filter( 'register_taxonomy_args', 'my_taxonomy_args', 10, 2 );

function my_taxonomy_args( $args, $taxonomy_name ) {

    if ( 'genre' === $taxonomy_name ) {
        $args['show_in_rest'] = true;

        // Optionally customize the rest_base or rest_controller_class
        $args['rest_base']             = 'genres';
        $args['rest_controller_class'] = 'WP_REST_Terms_Controller';
    }

    return $args;
}

Taxonomies & custom post types have a built-in association within WordPress, but what if you want to establish a link between two custom post types? This is not supported formally within WordPress itself, but we can create our own connections between arbitrary content types using the _link relation.

Modifying Responses

The default endpoints of the WordPress REST API are designed to return data by default that provides for the majority of sites and use cases, but there are often situations where you will need to access or expose additional data in the responses for various object types.

As with the rest of WordPress, the REST API is designed to be highly extensible to fit these needs. This guide details how to add additional data to the responses of default endpoints using the register_rest_field and register_meta functions. You can use these functions to add fields to any of the object types supported by the REST API. These custom fields can support both get and update operations.

Important Note about Changing Responses

Changing or removing data from core REST API endpoint responses can break plugins or WordPress core behavior, and should be avoided wherever possible.

The API exposes many fields on API responses, including things you might not need, or which might not fit into how your site works. While it’s tempting to modify or remove fields from REST API responses, this will cause problems with API clients that expect standard responses. This includes mobile clients, third party tools to help you manage your site, or wp-admin itself.

You may only need a small amount of data, but it’s important to keep in mind that the API is about exposing an interface to all clients, not just the feature you’re working on. Changing responses is dangerous.

Adding fields is not dangerous, so if you need to modify data, it’s much better to duplicate the field instead with your modified data. Removing fields is never encouraged; if you need to get back a smaller subset of data, use the _fields parameter or work with contexts instead.

If you must remove fields from an existing context you should ensure that the behavior is opt-in, for example by providing a custom query parameter to trigger the field removal.

The API cannot prevent you from changing responses, but the code is structured to strongly discourage doing so. Internally, field registration is powered by filters, and these can be used if you absolutely have no other choice.

Using register_rest_field vs register_meta

There are two methods which can be used to add data to WordPress REST API responses, register_rest_field and register_meta.

register_rest_field may be used to add arbitrary fields to any REST API response, and can be used to both read and write data using the API. To register a new REST field you must provide your own callback functions to get or set the field’s value, as well as manually specify your own schema definition for the field.

register_meta is used to whitelist an existing custom meta value for access through the REST API. By setting a meta field’s show_in_rest parameter to true, that field’s value will be exposed on a .meta key in the endpoint response, and WordPress will handle setting up the callbacks for reading and writing to that meta key. This is much simpler than register_rest_field, with one caveat:


Prior to WordPress 4.9.8, meta fields set to show_in_rest using register_meta are registered for all objects of a given type. If one custom post type shows a meta field, all custom post types will show that meta field. 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.\

Prior to WordPress 5.3, register_meta could only support scalar values (string, integer, number and boolean). WordPress 5.3 adds support for the object and array types.

Adding Custom Fields to API Responses

Using register_rest_field

The register_rest_field function is the most flexible way to add fields to REST API response objects. It accepts three parameters:

  1. $object_type: The name of the object, as a string, or an array of the names of objects for which the field is being registered. This may be a core type like “post”, “terms”, “meta”, “user” or “comment”, but can also be the string name of a custom post type.
  2. $attribute: The name of the field. This name will be used to define the key in the response object.
  3. $args: An array with keys that define the callback functions used to retrieve the value of the field (‘get_callback’), to update the value of the field (‘update_callback’), and to define its schema (‘schema’).

Each of the keys of the $args array is optional, but if not used, that capability will not be added. This means that you may specify a callback function for reading the value and omit the update callback to make that field read-only if desired.

Fields should be registered at the rest_api_init action. Using this action rather than init will prevent the field registration from happening during requests to WordPress that do not use the REST API.

Examples

Read and write an extra field in comment responses

<?php
add_action( 'rest_api_init', function () {
    register_rest_field( 'comment', 'karma', array(
        'get_callback' => function( $comment_arr ) {
            $comment_obj = get_comment( $comment_arr['id'] );
            return (int) $comment_obj->comment_karma;
        },
        'update_callback' => function( $karma, $comment_obj ) {
            $ret = wp_update_comment( array(
                'comment_ID'    => $comment_obj->comment_ID,
                'comment_karma' => $karma
            ) );
            if ( false === $ret ) {
                return new WP_Error(
                  'rest_comment_karma_failed',
                  __( 'Failed to update comment karma.' ),
                  array( 'status' => 500 )
                );
            }
            return true;
        },
        'schema' => array(
            'description' => __( 'Comment karma.' ),
            'type'        => 'integer'
        ),
    ) );
} );

This example illustrates adding a field called karma to the response for posts. It works because the comment_karma field exists, but is unused by core. Note that an actual implementation of comment karma would need to use a separate endpoint.

This is a basic example; carefully consider what permissions checks or error handling may be required for your specific field.

How register_rest_field Works

The global variable $wp_rest_additional_fields is used internally by the REST API infrastructure to hold the response fields to be added to each object type. The REST API provides register_rest_field as a utility function for adding to this global variable. Adding to the global variable directly should be avoided to ensure forward-compatibility.

For each object type — posts, or users, terms, comments, etc. — $wp_rest_additional_fields contains an array of field definitions containing the callbacks used to retrieve or update the field’s value.

Working with registered meta in the REST API

The register_meta function simplifies the process of defining a meta field for a particular object type. By setting 'show_in_rest' => true when registering a new meta key, that key will be accessible through the REST API.

Read and write a post meta field in post responses

<?php
// The object type. For custom post types, this is 'post';
// for custom comment types, this is 'comment'. For user meta,
// this is 'user'.
$object_type = 'post';
$meta_args = array( // Validate and sanitize the meta value.
    // Note: currently (4.7) one of 'string', 'boolean', 'integer',
    // 'number' must be used as 'type'. The default is 'string'.
    'type'         => 'string',
    // Shown in the schema for the meta key.
    'description'  => 'A meta key associated with a string meta value.',
    // Return a single value of the type.
    'single'       => true,
    // Show in the WP REST API response. Default: false.
    'show_in_rest' => true,
);
register_meta( $object_type, 'my_meta_key', $meta_args );

This example shows how to allow reading and writing of a post meta field. This will allow that field to be updated via a POST request to wp-json/wp/v2/posts/<post-id> or created along with a post via a POST request to wp-json/wp/v2/posts/.

Note that for meta fields registered on custom post types, the post type must have custom-fields support. Otherwise the meta fields will not appear in the REST API.

Post Type Specific Meta

WordPress 4.9.8 adds support for registering meta for a specific post type or taxonomy by using the register_post_meta and register_term_meta functions. They follow the same rules as register_meta but accept a post type or taxonomy as their first parameter instead of an object type. The following code would register the my_meta_key example above, but only for the page custom post type.

$meta_args = array(
    'type'         => 'string',
    'description'  => 'A meta key associated with a string meta value.',
    'single'       => true,
    'show_in_rest' => true,
);
register_post_meta( 'page', 'my_meta_key', $meta_args );

Object Meta Type

WordPress 5.3 adds support for using the object type when registering meta. Importantly object refers to a JSON object, this is equivalent to an associative array in PHP.

When registering object meta, setting the type to object is not sufficient, you also need to inform WordPress of what properties to allow. This is done by writing a JSON Schema when registering the metadata.

For instance, the following code sample registers a post meta field called “release” that accepts the given JSON data.

{
  "meta": {
    "release": {
      "version": "5.2",
      "artist": "Jaco"
    }
  }
}
register_post_meta(
    'post',
    'release',
    array(
        'single'       => true,
        'type'         => 'object',
        'show_in_rest' => array(
            'schema' => array(
                'type'       => 'object',
                'properties' => array(
                    'version' => array(
                        'type' => 'string',
                    ),
                    'artist'  => array(
                        'type' => 'string',
                    ),
                ),
            ),
        ),
    )
);

Notice that show_in_rest becomes an array instead of true and a Json Schema is specified for the schema key. Each property is then listed in the properties array. At a minimum, each property must specify a type, but any JSON Schema keyword that rest_validate_value_from_schema understands can be used as well.

Additional Properties

By default, the list of properties is a strict whitelist. If a property is sent in the request that is not listed, the REST API will return an error: your_property is not a valid property of Object.. If you don’t know the property names ahead of time the additionalProperties keyword can be used. additionalProperties accepts a JSON Schema that is used to validate the unknown properties. For instance, to enforce that any additional properties are numbers, the following code can be used.

{
  "meta": {
    "release": {
      "version": "5.2",
      "artist": "Jaco",
      "unknown_field": 5.3
    }
  }
}
register_post_meta(
    'post',
    'version',
    array(
        'single'       => true,
        'type'         => 'object',
        'show_in_rest' => array(
            'schema' => array(
                'type'                 => 'object',
                'properties'           => array(
                    'version' => array(
                        'type' => 'string',
                    ),
                    'artist'  => array(
                        'type' => 'string',
                    ),
                ),
                'additionalProperties' => array(
                    'type' => 'number',
                ),
            ),
        ),
    )
);

additionalProperties can be set to true to allow unknown properties of any format, but this is not recommended.

Array Meta Type

WordPress 5.3 also adds support for using the array type. Importantly array refers to a JSON array, this is equivalent to a numeric array in PHP.

When registering array meta, setting the type to array is not sufficient, you need to inform WordPress of what the expected format is of the items in the array. This is done by writing a JSON Schema entry when registering the metadata.

If you do not provide this value, register_meta will return false and issue the following warning: When registering an "array" meta type to show in the REST API, you must specify the schema for each array item in "show_in_rest.schema.items".

The following code sample registers a post meta field called “projects” that contains a list of project names. It accepts the given JSON data.

{
  "meta": {
    "projects": [
      "WordPress",
      "BuddyPress"
    ]
  }
}
register_post_meta(
    'post',
    'projects',
    array(
        'single'       => true,
        'type'         => 'array',
        'show_in_rest' => array(
            'schema' => array(
                'type'  => 'array',
                'items' => array(
                    'type' => 'string',
                ),
            ),
        ),
    )
);

Notice that again show_in_rest becomes an array instead of true and a JSON Schema is specified for the schema key.
The items keyword is used to define the JSON schema to validate each array member against. It can be a scalar type like string or a complex type like object.

For instance, to accept the given JSON data, the following meta registration would be used.

{
  "meta": {
    "projects": [
      {
        "name": "WordPress",
        "website": "https://wordpress.org"
      },
      {
        "name": "BuddyPress",
        "website": "https://buddypress.org"
      }
    ]
  }
}
register_post_meta(
    'post',
    'projects',
    array(
        'single'       => true,
        'type'         => 'array',
        'show_in_rest' => array(
            'schema' => array(
                'items' => array(
                    'type'       => 'object',
                    'properties' => array(
                        'name'    => array(
                            'type' => 'string',
                        ),
                        'website' => array(
                            'type'   => 'string',
                            'format' => 'uri',
                        ),
                    ),
                ),
            ),
        ),
    )
);

The array type enforces that the array keys are sequential integers starting from 0. The array will be reindexed using array_values.

Non-Single Metadata

Non-single meta fields have an array of values per object, instead of one value per object. Each of those values is stored in a separate row in the meta table.

The array and object types can be used with non-single meta fields as well. For example, if the “release” meta key from earlier had single set to false, the following JSON data could be accepted.

{
  "meta": {
    "release": [
      {
        "version": "5.2",
        "artist": "Jaco"
      },
      {
        "version": "5.1",
        "artist": "Betty"
      }
    ]
  }
}

This would result in two meta database rows. The first containing { "version": "5.2", "artist": "Jaco" } and the second containing { "version": "5.1", "artist": "Betty" }.

Similarly, the following data would be accepted for the “projects” example if it had set single to false.

{
  "meta": {
    "projects": [
      [
        "WordPress",
        "BuddyPress"
      ],
      [
        "bbPress"
      ]
    ]
  }
}

This would result in two meta database rows. The first containing [ "WordPress", "BuddyPress" ] and the second containing [ "bbPress" ].

Invalid Stored Values

If the existing value for a meta field does not validate against the registered type and schema, the value for that meta field will be returned as null. If that null value is passed back to the API when doing an update request, you’ll receive a rest_invalid_stored_value error: The %s property has an invalid stored value, and cannot be updated to null.. To fix this, either update the meta key with a valid value or omit that property from your request.

Default Metadata Values

WordPress 5.5 adds official support for specifying a default value for metadata if no value is defined. For example, with this code snippet the price meta field will be set to 0.00 in the REST API response if a value is not yet.

register_post_meta(
     'product',
     'price',
     array(
         'single'  => true,
         'type'    => 'string',
         'default' => '0.00',
     )
 );

WordPress generates a list of links associated with the queried resource to make it easier to navigate to related resources.

{
 "_links": {
    "self": [
      {
        "href": "https://make.wordpress.org/core/wp-json/wp/v2/posts/28312"
      }
    ],
    "collection": [
      {
        "href": "https://make.wordpress.org/core/wp-json/wp/v2/posts"
      }
    ],
    "author": [
      {
        "embeddable": true,
        "href": "https://make.wordpress.org/core/wp-json/wp/v2/users/8670591"
      }
    ],
    "replies": [
      {
        "embeddable": true,
        "href": "https://make.wordpress.org/core/wp-json/wp/v2/comments?post=28312"
      }
    ],
    "wp:term": [
      {
        "taxonomy": "category",
        "embeddable": true,
        "href": "https://make.wordpress.org/core/wp-json/wp/v2/categories?post=28312"
      },
      {
        "taxonomy": "post_tag",
        "embeddable": true,
        "href": "https://make.wordpress.org/core/wp-json/wp/v2/tags?post=28312"
      }
    ]
  }
}
<?php
$response->add_link( 'author', rest_url( "/wp/v2/users/{$post->post_author}" ) );

$response->add_link( 'https://api.w.org/term', add_query_arg( 'post', $post->ID, rest_url( "/wp/v2/{$tax_base}" ) ) );

author is a registered link relation described as “the context’s author”, we use that to point to the WordPress user who wrote the post. No link relation exists that describes the terms associated with a post, so WordPress uses the https://api.w.org/term` URL. This is transformed towp:term` when generating the response by using a CURIE.

The third parameter of add_link() is a list of custom attributes. The embeddable attribute can be used to include the linked resource appears in the _embedded section of the repsonse when using the _embed query parameter. If multiple links are added with the same relation, the embedded responses will be in the same order the links were added in.

<?php
$response->add_link( 'author', rest_url( "/wp/v2/users/{$post->post_author}" ), array(
    'embeddable' => true,
) );
$response->add_link( 'author', rest_url( "/wp/v2/users/{$additional_author}" ), array(
    'embeddable' => true,
) );

A sample implementation of linking to multi-author posts.

{
  "_links": {
    "author": [
      {
        "embeddable": true,
        "href": "https://yourwebsite.com/wp-json/wp/v2/users/1"
      },
      {
        "embeddable": true,
        "href": "https://yourwebsite.com/wp-json/wp/v2/users/2"
      }
    ]
  },
  "_embedded": {
    "author": [
      {
        "id": 1,
        "name": "Primary Author"
      },
      {
        "id": 2,
        "name": "Secondary Author"
      }
    ]
  }
}

Registering a CURIE

WordPress version 4.5 introduced support for Compact URIs, or CURIEs. This makes it possible to reference links by a much simpler identifier than the full URL which could easily be quite lengthy.

A CURIE is registered using the rest_response_link_curies filter. For example.

<?php
function my_plugin_prefix_register_curie( $curies ) {

    $curies[] = array(
        'name'      => 'my_plugin',
        'href'      => 'https://api.mypluginurl.com/{rel}',
        'templated' => true,
    );

    return $curies;
}

This will convert link URLs from https://api.mypluginurl.com/my_link` tomy_plugin:my_linkin the API response. The full URL must still be used when adding links usingWP_REST_Response::add_link() `.

Adding Custom Endpoints

The WordPress REST API is more than just a set of default routes. It is also a tool for creating custom routes and endpoints. The WordPress front-end provides a default set of URL mappings, but the tools used to create them (e.g. the Rewrites API, as well as the query classes: WP_Query, WP_User, etc) are also available for creating your own URL mappings, or custom queries.

This document details how to create a new and completely custom route with its own endpoints. We’ll first work through a short example and then expand it out to the full controller pattern as used internally.

Bare Basics

So you want to add custom endpoints to the API? Fantastic! Let’s get started with a simple example.
Let’s start with a simple function that looks like this:

<?php
/**
 * Grab latest post title by an author!
 *
 * @param array $data Options for the function.
 * @return string|null Post title for the latest,
 * or null if none.
 */
function my_awesome_func( $data ) {
  $posts = get_posts( array(
    'author' => $data['id'],
  ) );

  if ( empty( $posts ) ) {
    return null;
  }

  return $posts[0]->post_title;
}

To make this available via the API, we need to register a route. This tells the API to respond to a given request with our function. We do this through a function called register_rest_route, which should be called in a callback on rest_api_init to avoid doing extra work when the API isn’t loaded.

We need to pass in three things to register_rest_route: the namespace, the route we want, and the options. We’ll come back to the namespace in a bit, but for now, let’s pick myplugin/v1. We’re going to have the route match anything with /author/{id}, where {id} is an integer.

<?php
add_action( 'rest_api_init', function () {
  register_rest_route( 'myplugin/v1', '/author/(?P<id>\d+)', array(
    'methods' => 'GET',
    'callback' => 'my_awesome_func',
  ) );
} );

Right now, we’re only registering the one endpoint for the route. The term “route” refers to the URL, whereas “endpoint” refers to the function behind it that corresponds to a method and a URL (for more information, see the Glossary).

For example, if your site domain is example.com and you’ve kept the API path of wp-json, then the full URL would be `http://example.com/wp-json/myplugin/v1/author/(?P\d+)`.

On sites without pretty permalinks, the route is instead added to the URL as the rest_route parameter. For the above example, the full URL would then be http://example.com/?rest_route=/myplugin/v1/author/(?P\d+)

Each route can have any number of endpoints, and for each endpoint, you can define the HTTP methods allowed, a callback function for responding to the request and a permissions callback for creating custom permissions. In addition you can define allowed fields in the request and for each field specify a default value, a sanitization callback, a validation callback, and whether the field is required.

Namespacing

Namespaces are the first part of the URL for the endpoint. They should be used as a vendor/package prefix to prevent clashes between custom routes. Namespaces allows for two plugins to add a route of the same name, with different functionality.

Namespaces in general should follow the pattern of vendor/v1, where vendor is typically your plugin or theme slug, and v1 represents the first version of the API. If you ever need to break compatibility with new endpoints, you can then bump this to v2.

The above scenario, two routes with the same name, from two different plugins, requires all vendors to use a unique namespace. Failing to do so is analogous to a failure to use a vendor function prefix, class prefix and/ or class namespace in a theme or plugin, which is very very bad.

An added benefit of using namespaces is that clients can detect support for your custom API. The API index lists out the available namespaces on a site:

{
  "name": "WordPress Site",
  "description": "Just another WordPress site",
  "url": "http://example.com/",
  "namespaces": [
    "wp/v2",
    "vendor/v1",
    "myplugin/v1",
    "myplugin/v2",
  ]
}

If a client wants to check that your API exists on a site, they can check against this list. (For more information, see the Discovery guide.)

Arguments

By default, routes receive all arguments passed in from the request. These are merged into a single set of parameters, then added to the Request object, which is passed in as the first parameter to your endpoint:

<?php
function my_awesome_func( WP_REST_Request $request ) {
  // You can access parameters via direct array access on the object:
  $param = $request['some_param'];

  // Or via the helper method:
  $param = $request->get_param( 'some_param' );

  // You can get the combined, merged set of parameters:
  $parameters = $request->get_params();

  // The individual sets of parameters are also available, if needed:
  $parameters = $request->get_url_params();
  $parameters = $request->get_query_params();
  $parameters = $request->get_body_params();
  $parameters = $request->get_json_params();
  $parameters = $request->get_default_params();

  // Uploads aren't merged in, but can be accessed separately:
  $parameters = $request->get_file_params();
}

(To find out exactly how parameters are merged, check the source of WP_REST_Request::get_parameter_order(); the basic order is body, query, URL, then defaults.)

Normally, you’ll get every parameter brought in unaltered. However, you can register your arguments when registering your route, which allows you to run sanitization and validation on these.

If the request has the Content-type: application/json header set and valid JSON in the body, get_json_params() will return the parsed JSON body as an associative array.

Arguments are defined as a map in the key args for each endpoint (next to your callback option). This map uses the name of the argument of the key, with the value being a map of options for that argument. This array can contain a key for default, required, sanitize_callback and validate_callback.

Using sanitize_callback and validate_callback allows the main callback to act only to process the request, and prepare data to be returned using the WP_REST_Response class. By using these two callbacks, you will be able to safely assume your inputs are valid and safe when processing.

Taking our previous example, we can ensure the parameter passed in is always a number:

<?php
add_action( 'rest_api_init', function () {
  register_rest_route( 'myplugin/v1', '/author/(?P<id>\d+)', array(
    'methods' => 'GET',
    'callback' => 'my_awesome_func',
    'args' => array(
      'id' => array(
        'validate_callback' => function($param, $request, $key) {
          return is_numeric( $param );
        }
      ),
    ),
  ) );
} );

You could also pass in a function name to validate_callback, but passing certain functions like is_numeric directly will not only throw a warning about having extra parameters passed to it, but will also return NULL causing the callback function to be called with invalid data. We hope to eventually solve this problem in WordPress core.

We could also use something like 'sanitize_callback' => 'absint' instead, but validation will throw an error, allowing clients to understand what they’re doing wrong. Sanitization is useful when you would rather change the data being input rather than throwing an error (such as invalid HTML).

Return Value

After your callback is called, the return value is then converted to JSON, and returned to the client. This allows you to return basically any form of data. In our example above, we’re returning either a string or null, which are automatically handled by the API and converted to JSON.

Like any other WordPress function, you can also return a WP_Error instance. This error information will be passed along to the client, along with a 500 Internal Service Error status code. You can further customise your error by setting the status option in the WP_Error instance data to a code, such as 400 for bad input data.
Taking our example from before, we can now return an error instance:

<?php
/**
 * Grab latest post title by an author!
 *
 * @param array $data Options for the function.
 * @return string|null Post title for the latest,
 * or null if none.
 */
function my_awesome_func( $data ) {
  $posts = get_posts( array(
    'author' => $data['id'],
  ) );

  if ( empty( $posts ) ) {
    return new WP_Error( 'no_author', 'Invalid author', array( 'status' => 404 ) );
  }

  return $posts[0]->post_title;
}

When an author doesn’t have any posts belonging to them, this will return a 404 Not Found error to the client:

HTTP/1.1 404 Not Found

[{
   "code": "no_author",
   "message": "Invalid author",
   "data": { "status": 404 }
}]

For more advanced usage, you can return a WP_REST_Response object. This object “wraps” normal body data, but allows you to return a custom status code, or custom headers. You can also add links to your response. The quickest way to use this is via the constructor:

<?php
$data = array( 'some', 'response', 'data' );

// Create the response object
$response = new WP_REST_Response( $data );

// Add a custom status code
$response->set_status( 201 );

// Add a custom header
$response->header( 'Location', 'http://example.com/' );

When wrapping existing callbacks, you should always use rest_ensure_response() on the return value. This will take raw data returned from an endpoint and automatically turn it into a WP_REST_Response for you. (Note that WP_Error is not converted to a WP_REST_Response to allow proper error handling.)

Importantly, a REST API route’s callback should always return data; it shouldn’t attempt to send the response body itself. This ensures that the additional processing that the REST API server does, like handling linking/embedding, sending headers, etc… takes place. In other words, don’t call die( wp_json_encode( $data ) ); or wp_send_json( $data ). As of WordPress 5.5, a _doing_it_wrong notice is issued if the wp_send_json() family of functions is used during a REST API request.

Return a WP_REST_Response or WP_Error object from your callback when using the REST API.

Permissions Callback

You must also register a permissions callback for the endpoint. This is a function that checks if the user can perform the action (reading, updating, etc) before the real callback is called. This allows the API to tell the client what actions they can perform on a given URL without needing to attempt the request first.

This callback can be registered as permission_callback, again in the endpoint options next to your callback option. This callback should return a boolean or a WP_Error instance. If this function returns true, the response will be processed. If it returns false, a default error message will be returned and the request will not proceed with processing. If it returns a WP_Error, that error will be returned to the client.

The permissions callback is run after remote authentication, which sets the current user. This means you can use current_user_can to check if the user that has been authenticated has the appropriate capability for the action, or any other check based on current user ID. Where possible, you should always use current_user_can; instead of checking if the user is logged in (authentication), check whether they can perform the action (authorization).

Once you register a permission_callback, you will need to authenticate your requests (for example by including a nonce parameter) or you will receive a rest_forbidden error. See Authentication for more details.

Continuing with our previous example, we can make it so that only editors or above can view this author data. We can check a number of different capabilities here, but the best is edit_others_posts, which is really the core of what an editor is. To do this, we just need a callback here:

<?php
add_action( 'rest_api_init', function () {
  register_rest_route( 'myplugin/v1', '/author/(?P<id>\d+)', array(
    'methods' => 'GET',
    'callback' => 'my_awesome_func',
    'args' => array(
      'id' => array(
        'validate_callback' => 'is_numeric'
      ),
    ),
    'permission_callback' => function () {
      return current_user_can( 'edit_others_posts' );
    }
  ) );
} );

Note that the permission callback also receives the Request object as the first parameter, so you can do checks based on request arguments if you need to.

As of WordPress 5.5, if a permission_callback is not provided, the REST API will issue a _doing_it_wrong notice.

The REST API route definition for myplugin/v1/author is missing the required permission_callback argument. For REST API routes that are intended to be public, use __return_true as the permission callback.

If your REST API endpoint is public, you can use __return_true as the permission callback.

<?php
add_action( 'rest_api_init', function () {
  register_rest_route( 'myplugin/v1', '/author/(?P<id>\d+)', array(
    'methods' => 'GET',
    'callback' => 'my_awesome_func',
    'permission_callback' => '__return_true',
  ) );
} );

Discovery

If you’d like to enable Resource Discovery for your custom endpoint, you can do so using the rest_queried_resource_route filter. For example, consider a custom query var my-route that contains the id of your custom resource. The following code snippet would add a discovery link whenever the my-route query var is used.

function my_plugin_rest_queried_resource_route( $route ) {
    $id = get_query_var( 'my-route' );
    if ( ! $route && $id ) {
        $route = '/my-ns/v1/items/' . $id;
    }

    return $route;
}
add_filter( 'rest_queried_resource_route', 'my_plugin_rest_queried_resource_route' );

Note: If your endpoint is describing a custom post type or custom taxonomy you will most likely want to be using the rest_route_for_post or rest_route_for_term filters instead.

The Controller Pattern

The controller pattern is a best practice for working with complex endpoints with the API.

At their core, controllers are nothing more than a set of commonly named methods to match up with REST conventions, along with some handy helpers. Controllers register their routes in a register_routes method, respond to requests with get_items, get_item, create_item, update_item and delete_item, and have similarly named permission check methods. Following this pattern will ensure you don’t miss any steps or functionality in your endpoints.

To use controllers, you first need to subclass the base controller. This gives you a base set of methods, ready for you to add your own behaviour into.

Once we’ve subclassed the controller, we need to instantiate the class to get it working. This should be done inside of a callback hooked into rest_api_init, which ensures we only instantiate the class when we need to. The normal controller pattern is to call $controller->register_routes() inside this callback, where the class can then register its endpoints.

Examples

The following is a “starter” custom route:

<?php

class Slug_Custom_Route extends WP_REST_Controller {

  /**
   * Register the routes for the objects of the controller.
   */
  public function register_routes() {
    $version = '1';
    $namespace = 'vendor/v' . $version;
    $base = 'route';
    register_rest_route( $namespace, '/' . $base, array(
      array(
        'methods'             => WP_REST_Server::READABLE,
        'callback'            => array( $this, 'get_items' ),
        'permission_callback' => array( $this, 'get_items_permissions_check' ),
        'args'                => array(

        ),
      ),
      array(
        'methods'             => WP_REST_Server::CREATABLE,
        'callback'            => array( $this, 'create_item' ),
        'permission_callback' => array( $this, 'create_item_permissions_check' ),
        'args'                => $this->get_endpoint_args_for_item_schema( true ),
      ),
    ) );
    register_rest_route( $namespace, '/' . $base . '/(?P<id>[\d]+)', array(
      array(
        'methods'             => WP_REST_Server::READABLE,
        'callback'            => array( $this, 'get_item' ),
        'permission_callback' => array( $this, 'get_item_permissions_check' ),
        'args'                => array(
          'context' => array(
            'default' => 'view',
          ),
        ),
      ),
      array(
        'methods'             => WP_REST_Server::EDITABLE,
        'callback'            => array( $this, 'update_item' ),
        'permission_callback' => array( $this, 'update_item_permissions_check' ),
        'args'                => $this->get_endpoint_args_for_item_schema( false ),
      ),
      array(
        'methods'             => WP_REST_Server::DELETABLE,
        'callback'            => array( $this, 'delete_item' ),
        'permission_callback' => array( $this, 'delete_item_permissions_check' ),
        'args'                => array(
          'force' => array(
            'default' => false,
          ),
        ),
      ),
    ) );
    register_rest_route( $namespace, '/' . $base . '/schema', array(
      'methods'  => WP_REST_Server::READABLE,
      'callback' => array( $this, 'get_public_item_schema' ),
    ) );
  }

  /**
   * Get a collection of items
   *
   * @param WP_REST_Request $request Full data about the request.
   * @return WP_Error|WP_REST_Response
   */
  public function get_items( $request ) {
    $items = array(); //do a query, call another class, etc
    $data = array();
    foreach( $items as $item ) {
      $itemdata = $this->prepare_item_for_response( $item, $request );
      $data[] = $this->prepare_response_for_collection( $itemdata );
    }

    return new WP_REST_Response( $data, 200 );
  }

  /**
   * Get one item from the collection
   *
   * @param WP_REST_Request $request Full data about the request.
   * @return WP_Error|WP_REST_Response
   */
  public function get_item( $request ) {
    //get parameters from request
    $params = $request->get_params();
    $item = array();//do a query, call another class, etc
    $data = $this->prepare_item_for_response( $item, $request );

    //return a response or error based on some conditional
    if ( 1 == 1 ) {
      return new WP_REST_Response( $data, 200 );
    } else {
      return new WP_Error( 'code', __( 'message', 'text-domain' ) );
    }
  }

  /**
   * Create one item from the collection
   *
   * @param WP_REST_Request $request Full data about the request.
   * @return WP_Error|WP_REST_Response
   */
  public function create_item( $request ) {
    $item = $this->prepare_item_for_database( $request );

    if ( function_exists( 'slug_some_function_to_create_item' ) ) {
      $data = slug_some_function_to_create_item( $item );
      if ( is_array( $data ) ) {
        return new WP_REST_Response( $data, 200 );
      }
    }

    return new WP_Error( 'cant-create', __( 'message', 'text-domain' ), array( 'status' => 500 ) );
  }

  /**
   * Update one item from the collection
   *
   * @param WP_REST_Request $request Full data about the request.
   * @return WP_Error|WP_REST_Response
   */
  public function update_item( $request ) {
    $item = $this->prepare_item_for_database( $request );

    if ( function_exists( 'slug_some_function_to_update_item' ) ) {
      $data = slug_some_function_to_update_item( $item );
      if ( is_array( $data ) ) {
        return new WP_REST_Response( $data, 200 );
      }
    }

    return new WP_Error( 'cant-update', __( 'message', 'text-domain' ), array( 'status' => 500 ) );
  }

  /**
   * Delete one item from the collection
   *
   * @param WP_REST_Request $request Full data about the request.
   * @return WP_Error|WP_REST_Response
   */
  public function delete_item( $request ) {
    $item = $this->prepare_item_for_database( $request );

    if ( function_exists( 'slug_some_function_to_delete_item' ) ) {
      $deleted = slug_some_function_to_delete_item( $item );
      if ( $deleted ) {
        return new WP_REST_Response( true, 200 );
      }
    }

    return new WP_Error( 'cant-delete', __( 'message', 'text-domain' ), array( 'status' => 500 ) );
  }

  /**
   * Check if a given request has access to get items
   *
   * @param WP_REST_Request $request Full data about the request.
   * @return WP_Error|bool
   */
  public function get_items_permissions_check( $request ) {
    //return true; <--use to make readable by all
    return current_user_can( 'edit_something' );
  }

  /**
   * Check if a given request has access to get a specific item
   *
   * @param WP_REST_Request $request Full data about the request.
   * @return WP_Error|bool
   */
  public function get_item_permissions_check( $request ) {
    return $this->get_items_permissions_check( $request );
  }

  /**
   * Check if a given request has access to create items
   *
   * @param WP_REST_Request $request Full data about the request.
   * @return WP_Error|bool
   */
  public function create_item_permissions_check( $request ) {
    return current_user_can( 'edit_something' );
  }

  /**
   * Check if a given request has access to update a specific item
   *
   * @param WP_REST_Request $request Full data about the request.
   * @return WP_Error|bool
   */
  public function update_item_permissions_check( $request ) {
    return $this->create_item_permissions_check( $request );
  }

  /**
   * Check if a given request has access to delete a specific item
   *
   * @param WP_REST_Request $request Full data about the request.
   * @return WP_Error|bool
   */
  public function delete_item_permissions_check( $request ) {
    return $this->create_item_permissions_check( $request );
  }

  /**
   * Prepare the item for create or update operation
   *
   * @param WP_REST_Request $request Request object
   * @return WP_Error|object $prepared_item
   */
  protected function prepare_item_for_database( $request ) {
    return array();
  }

  /**
   * Prepare the item for the REST response
   *
   * @param mixed $item WordPress representation of the item.
   * @param WP_REST_Request $request Request object.
   * @return mixed
   */
  public function prepare_item_for_response( $item, $request ) {
    return array();
  }

  /**
   * Get the query params for collections
   *
   * @return array
   */
  public function get_collection_params() {
    return array(
      'page'     => array(
        'description'       => 'Current page of the collection.',
        'type'              => 'integer',
        'default'           => 1,
        'sanitize_callback' => 'absint',
      ),
      'per_page' => array(
        'description'       => 'Maximum number of items to be returned in result set.',
        'type'              => 'integer',
        'default'           => 10,
        'sanitize_callback' => 'absint',
      ),
      'search'   => array(
        'description'       => 'Limit results to those matching a string.',
        'type'              => 'string',
        'sanitize_callback' => 'sanitize_text_field',
      ),
    );
  }
}