WordPress is capable of powering anything from small personal blogs to large-scale enterprise solutions. One key factor in this evolution is the WordPress REST API, which exposes WordPress data as JSON, making it easy to integrate with external applications, mobile apps, and modern JavaScript frameworks.
In this article, we’ll dive deep into what the WordPress REST API is, why it’s important, and how you can create custom endpoints or modify existing ones. Whether you’re building a headless CMS, integrating WordPress content into a mobile app, or customizing how third-party services interact with your site, understanding the REST API is crucial.
The WordPress REST API provides a standardized way to access and manipulate WordPress content using HTTP requests and JSON responses. Instead of only interacting with your site via PHP templates and server-side rendering, the REST API lets you query and update content programmatically.
Key points about the REST API:
Why It Matters:
The REST API enables building headless WordPress sites where the front end is powered by React, Vue, Angular, or a mobile app, while WordPress remains the content repository. This decoupling offers flexibility, scalability, and a better developer experience.

Before you create custom endpoints, it’s helpful to understand what WordPress provides out of the box. By default, you can access the REST API at:
https://yoursite.com/wp-json/
From there, you’ll see a discovery endpoint listing available namespaces and routes. For example:
Example: Fetching Posts via REST API:
curl https://yoursite.com/wp-json/wp/v2/posts
This Curl URL returns a JSON array of posts with fields like id, title, content, and excerpt.
Query Parameters:
You can pass query parameters (e.g., ?per_page=5 or ?search=keyword) to filter results. This query makes it easy to integrate WordPress content into any JavaScript front end.
While the default endpoints are powerful, sometimes you need custom logic. For example, you might want an endpoint that returns a combination of posts and custom fields or integrates data from external APIs.
Key Function: register_rest_route()
To create custom endpoints, you use the register_rest_route() function inside an action hook, typically rest_api_init. The function signature:
register_rest_route(
string $namespace,
string $route,
array $args = []
);

Example: Custom Endpoint for Latest Posts from a Specific Category
add_action( 'rest_api_init', 'myplugin_register_routes' );
function myplugin_register_routes() {
register_rest_route( 'myplugin/v1', '/latest-posts/(?P<category>\d+)', [
'methods' => 'GET',
'callback' => 'myplugin_get_latest_posts',
'permission_callback' => '__return_true'
] );
}
function myplugin_get_latest_posts( $request ) {
$category_id = $request->get_param( 'category' );
$posts = get_posts([
'category' => $category_id,
'numberposts' => 5
]);
$data = [];
foreach ( $posts as $post ) {
$data[] = [
'id' => $post->ID,
'title' => get_the_title( $post ),
'link' => get_permalink( $post )
];
}
return $data;
}
What This Does:

Testing the Endpoint:
curl https://yoursite.com/wp-json/myplugin/v1/latest-posts/3
If category 3 exists, you get a JSON array of posts.
You can specify which HTTP methods your endpoint supports. Common methods include:
For example, if you need to create a POST endpoint:
register_rest_route( 'myplugin/v1', '/add-post', [
'methods' => 'POST',
'callback' => 'myplugin_add_post',
'permission_callback' => 'myplugin_can_edit_posts'
]);
Then, define myplugin_add_post to handle input from $request->get_json_params() and insert a post into the database. Ensure myplugin_can_edit_posts checks user capabilities to prevent unauthorized creations.

Security is crucial. You want everyone to create or delete your site’s content. That’s why REST endpoints have a permission_callback that decides if the current user (or request) is allowed to act.
Example:
function myplugin_can_edit_posts( $request ) {
return current_user_can( 'edit_posts' );
}
It ensures only logged-in users with edit_posts capability can access that endpoint. If authentication is not provided or fails, the endpoint returns a 401 Unauthorized or 403 Forbidden response.

What if you need to tweak existing endpoints? The WordPress REST API is highly extensible. You can add fields or filter responses without creating entirely new endpoints.
Use register_rest_field() to add custom fields to responses. For example, add a word_count field to post responses:
add_action( 'rest_api_init', 'myplugin_register_post_fields' );
function myplugin_register_post_fields() {
register_rest_field( 'post', 'word_count', [
'get_callback' => 'myplugin_get_word_count',
'update_callback' => null,
'schema' => [
'description' => 'Number of words in the post content',
'type' => 'integer'
]
]);
}
function myplugin_get_word_count( $post_arr ) {
$content = $post_arr['content']['rendered'] ?? '';
return str_word_count( wp_strip_all_tags( $content ) );
}
Now, when you fetch a post via wp/v2/posts, the word_count field appears in the JSON response.

If you need to alter data right before it’s returned, WordPress provides filters for each post type. For posts, rest_prepare_post fires before sending the response:
add_filter( 'rest_prepare_post', 'myplugin_modify_post_response', 10, 3 );
function myplugin_modify_post_response( $response, $post, $request ) {
// Modify the response data
$data = $response->get_data();
$data['custom_note'] = 'This post was modified by our plugin.';
$response->set_data( $data );
return $response;
}
This filter adds a custom_note field to every post response without registering a new field.

rest_pre_dispatch runs before the default handler processes a request. You could use it to log requests, cache responses, or even return a custom response early:
add_filter( 'rest_pre_dispatch', 'myplugin_pre_dispatch', 10, 3 );
function myplugin_pre_dispatch( $result, $server, $request ) {
// For instance, block requests to the posts endpoint if a certain condition is met
if ( $request->get_route() === '/wp/v2/posts' && ! current_user_can( 'read' ) ) {
return new WP_Error( 'forbidden', 'You cannot access posts', [ 'status' => 403 ] );
}
return $result;
}

To modify or create content via the REST API, you need authentication. Options include:
Select the method that satisfies your security conditions. For most modern integrations, Application Passwords or JWT tokens are popular and straightforward.
When developing custom endpoints, test thoroughly using tools like:
Check response codes (200 for success, 404 if the route doesn’t exist, 401/403 if unauthorized) and ensure the JSON structure matches your expectations.
Debugging Tips:
When you register a route, you specify a namespace. It will help organize your endpoints and allow versioning:
Versioning is critical for forward compatibility. If you change the endpoint’s response format, clients can still use the old version until they update their code.
The REST API supports custom post types and taxonomies out-of-the-box if show_in_rest is set to true when registering them.
Example:
register_post_type( 'movie', [
'label' => 'Movies',
'public' => true,
'show_in_rest' => true
]);
This function creates the wp/v2/movies endpoint. You can then query or manipulate movie posts just like standard posts.
For taxonomies, similarly set show_in_rest => true when using register_taxonomy().

REST API responses should be consistent and structured. The WordPress REST API uses WP_Error and WP_REST_Response classes:
Example: Returning an Error:
if ( ! $post ) {
return new WP_Error( 'not_found', 'Post not found', [ 'status' => 404 ] );
}
Example: Using WP_REST_Response:
$response = new WP_REST_Response( $data );
$response->set_status( 200 );
$response->header( 'X-Custom-Header', 'MyValue' );
return $response;
This level of control ensures your API behaves predictably for clients.

Sometimes, you may need your endpoint to interact with external APIs. For example, fetch data from a third-party service and merge it with WordPress posts before returning JSON.
Example:
function myplugin_get_external_data( $request ) {
$response = wp_remote_get( 'https://api.example.com/data' );
if ( is_wp_error( $response ) ) {
return new WP_Error( 'external_error', 'Could not fetch data', [ 'status' => 500 ] );
}
$body = wp_remote_retrieve_body( $response );
$external_data = json_decode( $body, true );
// Combine external_data with local posts
$posts = get_posts(['numberposts' => 3]);
return [
'posts' => $posts,
'external' => $external_data
];
}
Tip: Implement caching for external requests to avoid slow responses. Use set_transient() to store results temporarily.

The WordPress REST API transforms WordPress from a monolithic CMS into a flexible, API-driven platform. By understanding how to create custom endpoints and modify existing ones, you gain fine-grained control over the data your site exposes. Enables headless architectures, mobile app integrations, and complex external services to work seamlessly with your WordPress content.
From simple read-only GET endpoints to complex authenticated POST requests that manage site content, the REST API’s potential is vast. With proper authentication, versioning, and caching, you can build robust integrations that stand the test of time.
God willing, this guide helps you take full advantage of the WordPress REST API in your projects, opening doors to new front-end technologies, mobile solutions, and third-party integrations that enhance the WordPress ecosystem.

Hassan Tahir wrote this article, drawing on his experience to clarify WordPress concepts and enhance developer understanding. Through his work, he aims to help both beginners and professionals refine their skills and tackle WordPress projects with greater confidence.