The WordPress REST API has completely changed what you can do with WordPress. You can now use WordPress as a headless CMS, build mobile apps that connect to your WordPress site, or integrate WordPress with other services. In this guide, I'll show you everything you need to know to master the WordPress REST API.
What is the WordPress REST API?
The REST API is a way for applications to talk to WordPress using HTTP requests. Instead of loading WordPress's PHP templates and themes, you can request data in JSON format and use it however you want - in a React app, mobile app, or any other application.
It's been part of WordPress core since version 4.7, so if you're running a modern WordPress site, the API is already enabled and ready to use. No plugins needed!
Making Your First API Request
Let's start simple. Open your browser and go to yoursite.com/wp-json/wp/v2/posts. You'll see a JSON response with all your published posts. That's it - you just made your first API request!
// Example response structure
{
"id": 123,
"date": "2026-01-12T10:00:00",
"title": {
"rendered": "My Blog Post"
},
"content": {
"rendered": "<p>Post content here...</p>"
},
"excerpt": {
"rendered": "<p>Brief excerpt...</p>"
},
"author": 1,
"featured_media": 456
}Understanding API Endpoints
The REST API has different endpoints for different types of content. Here are the most useful ones:
/wp-json/wp/v2/posts- Blog posts/wp-json/wp/v2/pages- Pages/wp-json/wp/v2/categories- Categories/wp-json/wp/v2/tags- Tags/wp-json/wp/v2/media- Media files/wp-json/wp/v2/users- Users/wp-json/wp/v2/comments- Comments
To get a specific post, add the ID: /wp-json/wp/v2/posts/123
Fetching Posts in JavaScript
Let's fetch some posts using JavaScript. Here's a simple example:
async function getPosts() {
try {
const response = await fetch(
'https://yoursite.com/wp-json/wp/v2/posts?per_page=10'
)
const posts = await response.json()
posts.forEach(post => {
console.log(post.title.rendered)
console.log(post.excerpt.rendered)
})
} catch (error) {
console.error('Error fetching posts:', error)
}
}
getPosts()Filtering and Querying Data
The API supports URL parameters to filter results. This is incredibly powerful:
// Get 5 posts per page
/wp-json/wp/v2/posts?per_page=5
// Get page 2
/wp-json/wp/v2/posts?page=2
// Get posts from a specific category (ID 5)
/wp-json/wp/v2/posts?categories=5
// Search posts
/wp-json/wp/v2/posts?search=react
// Order by date descending (newest first)
/wp-json/wp/v2/posts?orderby=date&order=desc
// Get posts by a specific author (ID 2)
/wp-json/wp/v2/posts?author=2
// Combine multiple parameters
/wp-json/wp/v2/posts?per_page=10&categories=5&orderby=date&order=descEmbedding Related Data
By default, the API returns IDs for related content like authors and featured images. To get full data in one request, use the _embed parameter:
// Get posts with author info and featured images
const response = await fetch(
'https://yoursite.com/wp-json/wp/v2/posts?_embed'
)
const posts = await response.json()
posts.forEach(post => {
// Access author name
const authorName = post._embedded.author[0].name
// Access featured image
const featuredImage = post._embedded['wp:featuredmedia']?.[0]?.source_url
console.log(post.title.rendered)
console.log('By:', authorName)
console.log('Image:', featuredImage)
})Using _embed reduces the number of API requests you need to make, which improves performance significantly.Authentication and Creating Content
Reading public data doesn't require authentication, but creating, updating, or deleting content does. WordPress supports several authentication methods:
1. Application Passwords (Easiest)
WordPress 5.6+ includes application passwords. Go to your user profile in WordPress admin, scroll down to "Application Passwords," create a new one, and use it for authentication:
const username = 'your-username'
const appPassword = 'your-app-password'
const credentials = btoa(`${username}:${appPassword}`)
const response = await fetch('https://yoursite.com/wp-json/wp/v2/posts', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': `Basic ${credentials}`
},
body: JSON.stringify({
title: 'New Post via API',
content: 'This post was created using the REST API!',
status: 'publish'
})
})2. JWT Authentication (For Apps)
For more secure authentication in apps, use JWT tokens. You'll need a plugin like "JWT Authentication for WP REST API."
Creating a Headless WordPress Site with Next.js
Here's a practical example - building a blog with Next.js and WordPress:
// lib/wordpress.js
const WP_API_URL = 'https://yoursite.com/wp-json/wp/v2'
export async function getPosts(limit = 10) {
const res = await fetch(
`${WP_API_URL}/posts?per_page=${limit}&_embed`
)
return res.json()
}
export async function getPost(slug) {
const res = await fetch(
`${WP_API_URL}/posts?slug=${slug}&_embed`
)
const posts = await res.json()
return posts[0]
}
// app/blog/page.jsx
import { getPosts } from '@/lib/wordpress'
export default async function BlogPage() {
const posts = await getPosts()
return (
<div>
<h1>Blog</h1>
{posts.map(post => (
<article key={post.id}>
<h2>{post.title.rendered}</h2>
<div dangerouslySetInnerHTML={{
__html: post.excerpt.rendered
}} />
<a href={`/blog/${post.slug}`}>Read More</a>
</article>
))}
</div>
)
}Custom Post Types and Fields
To expose custom post types via the API, register them with show_in_rest:
// In your theme's functions.php
register_post_type('projects', [
'labels' => [
'name' => 'Projects',
],
'public' => true,
'show_in_rest' => true, // This makes it available via API
'rest_base' => 'projects', // Custom endpoint name
]);
// Now accessible at:
// /wp-json/wp/v2/projectsFor custom fields, use Advanced Custom Fields (ACF) plugin with REST API support, or register fields manually:
register_rest_field('post', 'custom_field', [
'get_callback' => function($post) {
return get_post_meta($post['id'], 'custom_field', true);
},
'schema' => [
'type' => 'string',
'context' => ['view', 'edit']
]
]);Handling Pagination
The API returns pagination info in response headers:
const response = await fetch(
'https://yoursite.com/wp-json/wp/v2/posts?per_page=10'
)
const posts = await response.json()
const totalPages = response.headers.get('X-WP-TotalPages')
const totalPosts = response.headers.get('X-WP-Total')
console.log(`Total pages: ${totalPages}`)
console.log(`Total posts: ${totalPosts}`)Optimizing API Requests
To improve performance:
- Use
_embedto reduce requests - Cache responses (use Next.js ISR or your own caching)
- Only request fields you need with
_fieldsparameter - Use pagination wisely - don't request too many posts at once
// Only get specific fields
/wp-json/wp/v2/posts?_fields=id,title,excerpt,date
// Much smaller response, faster loading!CORS Issues and Solutions
If you're accessing the API from a different domain, you might hit CORS issues. Add this to your WordPress theme's functions.php:
add_action('rest_api_init', function() {
remove_filter('rest_pre_serve_request', 'rest_send_cors_headers');
add_filter('rest_pre_serve_request', function($value) {
header('Access-Control-Allow-Origin: *');
header('Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS');
header('Access-Control-Allow-Credentials: true');
return $value;
});
}, 15);Be careful with CORS - only allow origins you trust, especially for authenticated endpoints.
Creating Custom Endpoints
Sometimes you need custom functionality. Create your own endpoints:
add_action('rest_api_init', function() {
register_rest_route('my-api/v1', '/popular-posts', [
'methods' => 'GET',
'callback' => function() {
$posts = get_posts([
'numberposts' => 5,
'meta_key' => 'views',
'orderby' => 'meta_value_num',
'order' => 'DESC'
]);
return $posts;
},
'permission_callback' => '__return_true'
]);
});
// Access at: /wp-json/my-api/v1/popular-postsSecurity Best Practices
Keep your API secure:
- Never expose admin credentials in client-side code
- Use application passwords instead of main password
- Implement rate limiting to prevent abuse
- Validate and sanitize all input data
- Use HTTPS always
- Set proper permission callbacks for custom endpoints
Final Thoughts
The WordPress REST API opens up endless possibilities. You can build modern JavaScript frameworks on top of WordPress, create mobile apps, integrate with other services, or build headless CMS solutions. The key is understanding the basics and then experimenting with what works for your specific needs.
Start simple - fetch some posts, display them on a page. Then gradually add more complex features like authentication, custom endpoints, and advanced querying. The documentation is comprehensive, and the community is helpful when you get stuck.