WordPress REST API¶
Learn to interact with WordPress data using the REST API, create custom endpoints, and build headless WordPress applications.
WordPress REST API Study Plan¶
This comprehensive 3-week study plan is based on the official WordPress REST API Handbook. Follow this structured approach to master the WordPress REST API.
Table of Contents¶
- Week 1: REST API Fundamentals
- Week 2: Using the REST API
- Week 3: Extending the REST API
- Additional Resources
Week 1: REST API Fundamentals¶
Goal: Understand what REST APIs are and how the WordPress REST API works
Day 1: Introduction to REST API¶
📖 Reading:
📝 Topics:
- What is REST (REpresentational State Transfer)
- JSON (JavaScript Object Notation) format
- HTTP methods (GET, POST, PUT, DELETE)
- How WordPress REST API works
- REST API vs other WordPress APIs
✏️ Practice:
- Access your site's REST API root:
https://yoursite.com/wp-json/ - Explore available endpoints
- View JSON responses in browser or Postman
Day 2: API Structure & Resources¶
📖 Reading:
📝 Core Resources:
- Posts (
/wp/v2/posts) - Pages (
/wp/v2/pages) - Categories (
/wp/v2/categories) - Tags (
/wp/v2/tags) - Users (
/wp/v2/users) - Comments (
/wp/v2/comments) - Media (
/wp/v2/media)
✏️ Practice:
- Test each core endpoint using browser or cURL
- Understand the JSON structure of responses
- Identify common fields across resources
Day 3: Discovery & Global Parameters¶
📖 Reading:
📝 Topics:
- API discovery mechanism
_fieldsparameter (field filtering)contextparameter (view, embed, edit)_embedparameter (embedding resources)- Error responses and status codes
✏️ Practice:
- Use
_fieldsto request specific fields only - Test different
contextvalues - Use
_embedto include related resources - Handle error responses
Day 4-5: Pagination & Linking¶
📖 Reading:
📝 Topics:
- Pagination parameters (
per_page,page) - Pagination headers (
X-WP-Total,X-WP-TotalPages) - HATEOAS (Hypermedia as the Engine of Application State)
_linksin responses- Embedded resources
🔍 Pagination Parameters:
per_page- Number of items per request (max 100)page- Current page numberoffset- Number of items to skiporderby- Field to sort byorder- Sort direction (asc/desc)
✏️ Practice:
- Implement pagination in API requests
- Parse pagination headers
- Use
_embedfor efficient data fetching - Navigate through
_linksrelationships
Day 6-7: Weekend Project¶
Project: Create a "Blog Post Viewer" web page
Requirements:
- ✅ Fetch and display posts from WordPress REST API
- ✅ Implement pagination (next/previous)
- ✅ Show post title, excerpt, date, author
- ✅ Display featured image using
_embed - ✅ Filter by category or tag
- ✅ Handle loading and error states
- ✅ Use vanilla JavaScript or your preferred framework
Deliverable: A working web page that consumes WordPress REST API data.
Week 2: Using the REST API¶
Goal: Master API authentication, querying, and client-side implementation
Day 1-2: Authentication¶
📖 Reading:
📝 Authentication Methods:
- Cookie Authentication - For same-origin requests
- Application Passwords - For external applications
- OAuth Authentication - For third-party apps
- JWT (JSON Web Tokens) - Via plugins
⚙️ Cookie Authentication:
// Add nonce to requests
fetch('/wp-json/wp/v2/posts', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-WP-Nonce': wpApiSettings.nonce
},
body: JSON.stringify({
title: 'My Post',
content: 'Post content',
status: 'publish'
})
});
🔐 Application Passwords:
# Basic Auth with Application Password
curl -u "username:xxxx xxxx xxxx xxxx xxxx xxxx" \
https://example.com/wp-json/wp/v2/users/me
✏️ Practice:
- Create application passwords
- Make authenticated requests
- Implement cookie authentication in JavaScript
- Test different authentication methods
Day 3: Client Libraries¶
📖 Reading:
📚 Popular Libraries:
- Backbone.js (built-in WordPress)
- wpapi (Node.js)
- wordpress-rest-api-oauth (OAuth)
- Language-specific clients (PHP, Python, Ruby, etc.)
✏️ Practice:
- Use wp-api Backbone.js models
- Try a REST API client library
- Compare raw fetch vs client library
Day 4-5: Working with Resources¶
📖 Reading:
🔧 CRUD Operations:
Create:
// Create a post
fetch('/wp-json/wp/v2/posts', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-WP-Nonce': nonce
},
body: JSON.stringify({
title: 'New Post',
content: 'Post content',
status: 'publish'
})
});
Update:
// Update a post
fetch('/wp-json/wp/v2/posts/123', {
method: 'POST', // or PUT
headers: {
'Content-Type': 'application/json',
'X-WP-Nonce': nonce
},
body: JSON.stringify({
title: 'Updated Title'
})
});
Delete:
// Delete a post
fetch('/wp-json/wp/v2/posts/123', {
method: 'DELETE',
headers: {
'X-WP-Nonce': nonce
}
});
✏️ Practice:
- Create posts via API
- Update existing posts
- Delete posts
- Upload media files
- Create and manage comments
- Work with users endpoint
Day 6-7: Weekend Project¶
Project: Create a "Simple CMS Dashboard"
Requirements:
- ✅ Authentication:
- Login with application passwords or cookies
- Show authenticated user info
- ✅ Post Management:
- List all posts with pagination
- Create new posts
- Edit existing posts
- Delete posts
- Publish/draft status control
- ✅ Media Management:
- Upload images
- Insert images in posts
- ✅ Categories & Tags:
- Assign categories and tags to posts
- ✅ User Experience:
- Loading states
- Error handling
- Success notifications
Deliverable: A functional content management interface using REST API.
Week 3: Extending the REST API¶
Goal: Create custom endpoints and extend existing resources
Day 1-2: Custom Endpoints¶
📖 Reading:
📝 Topics:
register_rest_route()function- Namespace and route patterns
- HTTP methods and callbacks
- Permission callbacks
- Arguments and validation
⚙️ Basic Custom Endpoint:
add_action('rest_api_init', function () {
register_rest_route('myplugin/v1', '/author/(?P<id>\d+)', array(
'methods' => 'GET',
'callback' => 'myplugin_get_author',
'permission_callback' => '__return_true',
'args' => array(
'id' => array(
'validate_callback' => function($param) {
return is_numeric($param);
}
),
),
));
});
function myplugin_get_author($request) {
$author = get_user_by('id', $request['id']);
if (!$author) {
return new WP_Error('no_author', 'Invalid author', array('status' => 404));
}
return array(
'id' => $author->ID,
'name' => $author->display_name,
'email' => $author->user_email
);
}
✏️ Practice:
- Create a simple GET endpoint
- Create a POST endpoint with data validation
- Implement permission callbacks
- Return proper error responses
Day 3: Controller Classes¶
📖 Reading:
📝 Topics:
- Extending
WP_REST_Controller - Standard CRUD methods
- Index, create, update, delete patterns
- Schema definitions
- Consistent API design
⚙️ Controller Example:
class My_REST_Controller extends WP_REST_Controller {
public function register_routes() {
register_rest_route('myplugin/v1', '/items', array(
array(
'methods' => WP_REST_Server::READABLE,
'callback' => array($this, 'get_items'),
'permission_callback' => array($this, 'get_items_permissions_check'),
),
array(
'methods' => WP_REST_Server::CREATABLE,
'callback' => array($this, 'create_item'),
'permission_callback' => array($this, 'create_item_permissions_check'),
),
));
}
public function get_items($request) {
// Implementation
}
public function create_item($request) {
// Implementation
}
}
✏️ Practice:
- Create a custom controller class
- Implement CRUD operations
- Define schema for your resource
Day 4: Adding REST Support to Custom Content¶
📖 Reading:
📝 Topics:
- Enable REST API for custom post types
- Enable REST API for custom taxonomies
- Custom meta fields in REST API
show_in_restparameterrest_baseparameter- Schema definitions
⚙️ Custom Post Type with REST API:
register_post_type('book', array(
'public' => true,
'label' => 'Books',
'show_in_rest' => true,
'rest_base' => 'books',
'rest_controller_class' => 'WP_REST_Posts_Controller',
'supports' => array('title', 'editor', 'custom-fields'),
));
// Register custom meta in REST API
register_post_meta('book', 'isbn', array(
'show_in_rest' => true,
'single' => true,
'type' => 'string',
));
✏️ Practice:
- Add REST API support to custom post type
- Add REST API support to custom taxonomy
- Register custom meta fields
- Test custom endpoints
Day 5: Modifying Responses¶
📖 Reading:
📝 Topics:
register_rest_field()function- Adding custom fields to responses
- Modifying existing fields
- Get and update callbacks
- Schema for custom fields
⚙️ Add Custom Field:
add_action('rest_api_init', function () {
register_rest_field('post', 'custom_field', array(
'get_callback' => function($post) {
return get_post_meta($post['id'], 'custom_field', true);
},
'update_callback' => function($value, $post) {
return update_post_meta($post->ID, 'custom_field', $value);
},
'schema' => array(
'description' => 'Custom field description',
'type' => 'string',
),
));
});
✏️ Practice:
- Add custom fields to posts endpoint
- Add computed fields (e.g., reading time)
- Modify user endpoint responses
- Add custom fields with proper schema
Day 6-7: Weekend Project¶
Project: Create a "Portfolio REST API Plugin"
Requirements:
- ✅ Custom Post Type:
- Register "Portfolio" custom post type
- Enable REST API support
- Custom fields: client, project_url, technologies
- ✅ Custom Taxonomy:
- Register "Project Type" taxonomy
- Enable REST API support
- ✅ Custom Endpoints:
/myplugin/v1/portfolio/featured- Get featured projects/myplugin/v1/portfolio/stats- Get portfolio statistics/myplugin/v1/portfolio/search- Custom search endpoint- ✅ Extended Responses:
- Add custom fields to portfolio endpoint
- Add related projects field
- Add project metadata
- ✅ Controller Class:
- Use proper controller pattern
- Implement all CRUD operations
- Define proper schema
- ✅ Documentation:
- Document all endpoints
- Provide usage examples
Deliverable: A complete plugin with custom REST API implementation.
Additional Resources¶
Official Documentation¶
- WordPress REST API Handbook - Complete REST API documentation
- REST API Reference - All available endpoints
- REST API Glossary - Key terms and concepts
Tools & Testing¶
- Postman - API testing tool
- Insomnia - REST client
- WP REST API Console - WordPress plugin for testing
- REST API Handbook Console - Online testing
Client Libraries¶
- node-wpapi - Node.js client
- wordpress-rest-api-oauth - OAuth plugin
- Backbone.js - Built-in WordPress client
Learning Resources¶
- REST API Handbook - Official guide
- WP REST API FAQ - Common questions
- WordPress TV - Video tutorials
Security¶
- REST API Authentication - Security guide
- Application Passwords - Authentication method
- REST API Security Best Practices - Security guidelines
Detailed Learning Content¶
Below you'll find detailed explanations and code examples for working with the WordPress REST API.
What is REST API?¶
The WordPress REST API provides an interface for applications to interact with your WordPress site by sending and receiving data as JSON objects. It allows you to access WordPress data from outside WordPress, making it possible to build decoupled applications.
Benefits of REST API¶
- Decoupled Architecture - Separate frontend from backend
- Mobile Applications - Build native mobile apps
- Single Page Applications - Create SPAs with React, Vue, etc.
- Integration - Connect with external services
- Flexibility - Use any programming language
- Modern Development - Build with modern JavaScript frameworks
REST API Basics¶
API Endpoint Structure¶
Components:
wp-json- REST API basewp/v2- Namespace and version{endpoint}- Resource (posts, pages, users, etc.)
Core Endpoints¶
/wp/v2/posts # Posts
/wp/v2/pages # Pages
/wp/v2/categories # Categories
/wp/v2/tags # Tags
/wp/v2/users # Users
/wp/v2/comments # Comments
/wp/v2/media # Media
/wp/v2/taxonomies # Taxonomies
/wp/v2/types # Post types
/wp/v2/statuses # Post statuses
Making API Requests¶
GET Requests (Retrieve Data)¶
Retrieve All Posts¶
# cURL
curl https://example.com/wp-json/wp/v2/posts
# With parameters
curl "https://example.com/wp-json/wp/v2/posts?per_page=5&orderby=date&order=desc"
// JavaScript (Fetch API)
fetch('https://example.com/wp-json/wp/v2/posts')
.then(response => response.json())
.then(data => {
console.log(data);
})
.catch(error => console.error('Error:', error));
// With async/await
async function getPosts() {
try {
const response = await fetch('https://example.com/wp-json/wp/v2/posts?per_page=10');
const posts = await response.json();
return posts;
} catch (error) {
console.error('Error fetching posts:', error);
}
}
// WordPress (wp_remote_get)
$response = wp_remote_get('https://example.com/wp-json/wp/v2/posts');
if (is_wp_error($response)) {
$error_message = $response->get_error_message();
echo "Error: $error_message";
} else {
$body = wp_remote_retrieve_body($response);
$posts = json_decode($body);
foreach ($posts as $post) {
echo $post->title->rendered;
}
}
Retrieve Single Post¶
# By ID
curl https://example.com/wp-json/wp/v2/posts/123
# By slug
curl "https://example.com/wp-json/wp/v2/posts?slug=hello-world"
// JavaScript
async function getPost(postId) {
const response = await fetch(`https://example.com/wp-json/wp/v2/posts/${postId}`);
const post = await response.json();
return post;
}
POST Requests (Create Data)¶
Create a Post¶
# cURL with authentication
curl -X POST https://example.com/wp-json/wp/v2/posts \
-H "Authorization: Bearer YOUR_TOKEN_HERE" \
-H "Content-Type: application/json" \
-d '{
"title": "My New Post",
"content": "This is the post content.",
"status": "publish"
}'
// JavaScript with authentication
async function createPost(title, content) {
const response = await fetch('https://example.com/wp-json/wp/v2/posts', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': 'Bearer ' + authToken
},
body: JSON.stringify({
title: title,
content: content,
status: 'publish'
})
});
const newPost = await response.json();
return newPost;
}
PUT/PATCH Requests (Update Data)¶
# Update post
curl -X POST https://example.com/wp-json/wp/v2/posts/123 \
-H "Authorization: Bearer YOUR_TOKEN_HERE" \
-H "Content-Type: application/json" \
-d '{
"title": "Updated Title"
}'
// JavaScript
async function updatePost(postId, updates) {
const response = await fetch(`https://example.com/wp-json/wp/v2/posts/${postId}`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': 'Bearer ' + authToken
},
body: JSON.stringify(updates)
});
return await response.json();
}
DELETE Requests (Delete Data)¶
# Delete post (move to trash)
curl -X DELETE https://example.com/wp-json/wp/v2/posts/123 \
-H "Authorization: Bearer YOUR_TOKEN_HERE"
# Force delete (permanent)
curl -X DELETE "https://example.com/wp-json/wp/v2/posts/123?force=true" \
-H "Authorization: Bearer YOUR_TOKEN_HERE"
// JavaScript
async function deletePost(postId, force = false) {
const url = `https://example.com/wp-json/wp/v2/posts/${postId}${force ? '?force=true' : ''}`;
const response = await fetch(url, {
method: 'DELETE',
headers: {
'Authorization': 'Bearer ' + authToken
}
});
return await response.json();
}
Query Parameters¶
Common Parameters¶
?per_page=10 # Number of items per page (default: 10, max: 100)
?page=2 # Page number
?search=keyword # Search posts
?orderby=date # Order by (date, id, title, slug, etc.)
?order=desc # Order direction (asc, desc)
?status=publish # Post status
?categories=5,6 # Filter by categories
?tags=10,11 # Filter by tags
?author=1 # Filter by author
?before=2023-12-31 # Posts before date
?after=2023-01-01 # Posts after date
?slug=post-slug # Filter by slug
?include=1,2,3 # Include specific IDs
?exclude=4,5,6 # Exclude specific IDs
Example Queries¶
// Get 20 published posts
fetch('https://example.com/wp-json/wp/v2/posts?per_page=20&status=publish')
// Search posts
fetch('https://example.com/wp-json/wp/v2/posts?search=wordpress')
// Get posts from specific category
fetch('https://example.com/wp-json/wp/v2/posts?categories=5')
// Get recent posts
fetch('https://example.com/wp-json/wp/v2/posts?orderby=date&order=desc&per_page=5')
// Get posts with embedded data
fetch('https://example.com/wp-json/wp/v2/posts?_embed')
Authentication¶
Authentication Methods¶
1. Application Passwords (Recommended)¶
WordPress 5.6+ supports application passwords for REST API authentication.
Generate Application Password:
- Go to Users → Profile
- Scroll to "Application Passwords"
- Enter name and click "Add New Application Password"
- Copy the generated password
Use with Basic Auth:
const username = 'your_username';
const appPassword = 'xxxx xxxx xxxx xxxx xxxx xxxx';
const credentials = btoa(`${username}:${appPassword}`);
fetch('https://example.com/wp-json/wp/v2/posts', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': 'Basic ' + credentials
},
body: JSON.stringify({
title: 'New Post',
content: 'Post content',
status: 'publish'
})
})
.then(response => response.json())
.then(data => console.log(data));
2. OAuth Authentication¶
For third-party applications, use OAuth 1.0a or OAuth 2.0.
Install OAuth plugin:
3. Cookie Authentication¶
For requests from the same domain (e.g., JavaScript in your theme):
// Add nonce to requests
fetch('https://example.com/wp-json/wp/v2/posts', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-WP-Nonce': wpApiSettings.nonce // WordPress provides this
},
body: JSON.stringify({
title: 'New Post',
content: 'Post content',
status: 'publish'
})
})
Localize nonce in theme:
function mytheme_enqueue_scripts() {
wp_enqueue_script('my-script', get_template_directory_uri() . '/js/script.js', array(), '1.0', true);
wp_localize_script('my-script', 'wpApiSettings', array(
'root' => esc_url_raw(rest_url()),
'nonce' => wp_create_nonce('wp_rest')
));
}
add_action('wp_enqueue_scripts', 'mytheme_enqueue_scripts');
Creating Custom REST API Endpoints¶
Basic Custom Endpoint¶
/**
* Register custom REST API endpoint.
*/
function myplugin_register_api_endpoints() {
register_rest_route('myplugin/v1', '/data', array(
'methods' => 'GET',
'callback' => 'myplugin_get_data',
'permission_callback' => '__return_true', // Allow public access
));
}
add_action('rest_api_init', 'myplugin_register_api_endpoints');
/**
* Endpoint callback.
*/
function myplugin_get_data($request) {
$data = array(
'message' => 'Hello from custom endpoint!',
'timestamp' => time(),
);
return new WP_REST_Response($data, 200);
}
Access endpoint:
Endpoint with Parameters¶
/**
* Register endpoint with parameters.
*/
function myplugin_register_user_endpoint() {
register_rest_route('myplugin/v1', '/user/(?P<id>\d+)', array(
'methods' => 'GET',
'callback' => 'myplugin_get_user_data',
'permission_callback' => '__return_true',
'args' => array(
'id' => array(
'validate_callback' => function($param, $request, $key) {
return is_numeric($param);
}
),
),
));
}
add_action('rest_api_init', 'myplugin_register_user_endpoint');
/**
* Get user data.
*/
function myplugin_get_user_data($request) {
$user_id = $request['id'];
$user = get_user_by('id', $user_id);
if (!$user) {
return new WP_Error('user_not_found', 'User not found', array('status' => 404));
}
$data = array(
'id' => $user->ID,
'name' => $user->display_name,
'email' => $user->user_email,
);
return new WP_REST_Response($data, 200);
}
Access endpoint:
POST Endpoint with Authentication¶
/**
* Register POST endpoint.
*/
function myplugin_register_post_endpoint() {
register_rest_route('myplugin/v1', '/submit', array(
'methods' => 'POST',
'callback' => 'myplugin_handle_submission',
'permission_callback' => function() {
return current_user_can('edit_posts');
},
'args' => array(
'title' => array(
'required' => true,
'type' => 'string',
'sanitize_callback' => 'sanitize_text_field',
),
'content' => array(
'required' => true,
'type' => 'string',
'sanitize_callback' => 'sanitize_textarea_field',
),
),
));
}
add_action('rest_api_init', 'myplugin_register_post_endpoint');
/**
* Handle submission.
*/
function myplugin_handle_submission($request) {
$title = $request->get_param('title');
$content = $request->get_param('content');
// Create post
$post_id = wp_insert_post(array(
'post_title' => $title,
'post_content' => $content,
'post_status' => 'publish',
'post_type' => 'post',
));
if (is_wp_error($post_id)) {
return new WP_Error('post_creation_failed', $post_id->get_error_message(), array('status' => 500));
}
return new WP_REST_Response(array(
'id' => $post_id,
'message' => 'Post created successfully',
), 201);
}
Complete CRUD Endpoint¶
/**
* Register CRUD endpoints.
*/
function myplugin_register_crud_endpoints() {
$namespace = 'myplugin/v1';
$base = 'items';
// GET all items
register_rest_route($namespace, '/' . $base, array(
'methods' => 'GET',
'callback' => 'myplugin_get_items',
'permission_callback' => '__return_true',
));
// GET single item
register_rest_route($namespace, '/' . $base . '/(?P<id>\d+)', array(
'methods' => 'GET',
'callback' => 'myplugin_get_item',
'permission_callback' => '__return_true',
));
// POST create item
register_rest_route($namespace, '/' . $base, array(
'methods' => 'POST',
'callback' => 'myplugin_create_item',
'permission_callback' => function() {
return current_user_can('edit_posts');
},
));
// PUT/POST update item
register_rest_route($namespace, '/' . $base . '/(?P<id>\d+)', array(
'methods' => array('POST', 'PUT', 'PATCH'),
'callback' => 'myplugin_update_item',
'permission_callback' => function() {
return current_user_can('edit_posts');
},
));
// DELETE item
register_rest_route($namespace, '/' . $base . '/(?P<id>\d+)', array(
'methods' => 'DELETE',
'callback' => 'myplugin_delete_item',
'permission_callback' => function() {
return current_user_can('delete_posts');
},
));
}
add_action('rest_api_init', 'myplugin_register_crud_endpoints');
Custom Post Type REST API Support¶
Enable REST API for Custom Post Type¶
/**
* Register custom post type with REST API support.
*/
function myplugin_register_book_post_type() {
register_post_type('book', array(
'labels' => array(
'name' => 'Books',
'singular_name' => 'Book',
),
'public' => true,
'show_in_rest' => true, // Enable REST API
'rest_base' => 'books', // Custom endpoint name
'rest_controller_class' => 'WP_REST_Posts_Controller',
));
}
add_action('init', 'myplugin_register_book_post_type');
Access custom post type:
Add Custom Fields to REST API¶
/**
* Add custom field to REST API response.
*/
function myplugin_register_custom_fields() {
register_rest_field('post', 'custom_field', array(
'get_callback' => 'myplugin_get_custom_field',
'update_callback' => 'myplugin_update_custom_field',
'schema' => array(
'description' => 'Custom field data',
'type' => 'string',
'context' => array('view', 'edit'),
),
));
}
add_action('rest_api_init', 'myplugin_register_custom_fields');
/**
* Get custom field value.
*/
function myplugin_get_custom_field($object, $field_name, $request) {
return get_post_meta($object['id'], '_custom_field', true);
}
/**
* Update custom field value.
*/
function myplugin_update_custom_field($value, $object, $field_name) {
if (!$value || !is_string($value)) {
return;
}
return update_post_meta($object->ID, '_custom_field', sanitize_text_field($value));
}
Practical Example: Building a React Frontend¶
Display Posts with React¶
import React, { useState, useEffect } from 'react';
function BlogPosts() {
const [posts, setPosts] = useState([]);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
useEffect(() => {
fetch('https://example.com/wp-json/wp/v2/posts?_embed')
.then(response => {
if (!response.ok) {
throw new Error('Network response was not ok');
}
return response.json();
})
.then(data => {
setPosts(data);
setLoading(false);
})
.catch(error => {
setError(error.message);
setLoading(false);
});
}, []);
if (loading) return <div>Loading...</div>;
if (error) return <div>Error: {error}</div>;
return (
<div className="blog-posts">
<h1>Blog Posts</h1>
{posts.map(post => (
<article key={post.id}>
<h2 dangerouslySetInnerHTML={{ __html: post.title.rendered }} />
{post._embedded && post._embedded['wp:featuredmedia'] && (
<img
src={post._embedded['wp:featuredmedia'][0].source_url}
alt={post.title.rendered}
/>
)}
<div dangerouslySetInnerHTML={{ __html: post.excerpt.rendered }} />
<a href={post.link}>Read More</a>
</article>
))}
</div>
);
}
export default BlogPosts;
Practical Exercises¶
Exercise 1: Fetch and Display Posts¶
Create a simple HTML page that fetches and displays posts from your WordPress site using vanilla JavaScript.
Exercise 2: Custom Endpoint¶
Create a custom REST API endpoint that returns: - Total number of posts - Total number of pages - Total number of users - Site statistics
Exercise 3: Protected Endpoint¶
Create a protected endpoint that requires authentication and allows users to submit contact form data.
Exercise 4: React Application¶
Build a simple React application that: - Displays a list of posts - Shows single post view - Implements search functionality - Handles pagination
Key Takeaways¶
- REST API enables decoupled architecture
- Authentication is crucial for write operations
- Use query parameters for filtering data
- Custom endpoints extend functionality
- Enable REST API support for custom post types
- Validate and sanitize all inputs
- Handle errors properly with WP_Error
- Use proper HTTP status codes
- Document your custom endpoints
- Test API endpoints thoroughly
Next Steps¶
Continue with WP-CLI to learn command-line WordPress management.
Resources: