PHPwordpressintermediate
Create Custom WordPress REST API Endpoint
Add custom REST API endpoints to extend WordPress functionality
Faisal Yaqoob
November 14, 2025
#wordpress#rest-api#api#endpoints#json
Code
php
1 // Register custom REST API endpoint 2 function register_custom_api_endpoint() { 3 register_rest_route('custom/v1', '/posts', array( 4 'methods' => 'GET', 5 'callback' => 'get_custom_posts', 6 'permission_callback' => '__return_true', // Public endpoint 7 )); 8
9 register_rest_route('custom/v1', '/posts/(?P<id>\d+)', array( 10 'methods' => 'GET', 11 'callback' => 'get_custom_post_by_id', 12 'permission_callback' => '__return_true', 13 'args' => array( 14 'id' => array( 15 'validate_callback' => function($param) { 16 return is_numeric($param); 17 } 18 ), 19 ), 20 )); 21
22 register_rest_route('custom/v1', '/posts', array( 23 'methods' => 'POST', 24 'callback' => 'create_custom_post', 25 'permission_callback' => 'check_admin_permission', 26 )); 27
28 register_rest_route('custom/v1', '/search', array( 29 'methods' => 'GET', 30 'callback' => 'search_content', 31 'permission_callback' => '__return_true', 32 'args' => array( 33 'query' => array( 34 'required' => true, 35 'sanitize_callback' => 'sanitize_text_field', 36 ), 37 ), 38 )); 39 } 40 add_action('rest_api_init', 'register_custom_api_endpoint'); 41
42 // Get custom posts 43 function get_custom_posts($request) { 44 $args = array( 45 'post_type' => 'post', 46 'posts_per_page' => 10, 47 'post_status' => 'publish', 48 ); 49
50 $posts = get_posts($args); 51 $data = array(); 52
53 foreach ($posts as $post) { 54 $data[] = array( 55 'id' => $post->ID, 56 'title' => $post->post_title, 57 'content' => apply_filters('the_content', $post->post_content), 58 'excerpt' => $post->post_excerpt, 59 'date' => $post->post_date, 60 'author' => get_the_author_meta('display_name', $post->post_author), 61 'thumbnail' => get_the_post_thumbnail_url($post->ID, 'large'), 62 'categories' => wp_get_post_categories($post->ID, array('fields' => 'names')), 63 'tags' => wp_get_post_tags($post->ID, array('fields' => 'names')), 64 ); 65 } 66
67 return new WP_REST_Response($data, 200); 68 } 69
70 // Get single post by ID 71 function get_custom_post_by_id($request) { 72 $post_id = $request['id']; 73 $post = get_post($post_id); 74
75 if (empty($post) || $post->post_status !== 'publish') { 76 return new WP_Error('not_found', 'Post not found', array('status' => 404)); 77 } 78
79 $data = array( 80 'id' => $post->ID, 81 'title' => $post->post_title, 82 'content' => apply_filters('the_content', $post->post_content), 83 'excerpt' => $post->post_excerpt, 84 'date' => $post->post_date, 85 'author' => array( 86 'name' => get_the_author_meta('display_name', $post->post_author), 87 'avatar' => get_avatar_url($post->post_author), 88 ), 89 'thumbnail' => get_the_post_thumbnail_url($post->ID, 'large'), 90 'categories' => wp_get_post_categories($post->ID, array('fields' => 'names')), 91 'tags' => wp_get_post_tags($post->ID, array('fields' => 'names')), 92 'meta' => get_post_meta($post->ID), 93 ); 94
95 return new WP_REST_Response($data, 200); 96 } 97
98 // Create new post 99 function create_custom_post($request) { 100 $params = $request->get_json_params(); 101
102 $post_data = array( 103 'post_title' => sanitize_text_field($params['title']), 104 'post_content' => wp_kses_post($params['content']), 105 'post_status' => 'draft', 106 'post_type' => 'post', 107 ); 108
109 $post_id = wp_insert_post($post_data); 110
111 if (is_wp_error($post_id)) { 112 return new WP_Error('creation_failed', 'Failed to create post', array('status' => 500)); 113 } 114
115 return new WP_REST_Response(array( 116 'id' => $post_id, 117 'message' => 'Post created successfully', 118 ), 201); 119 } 120
121 // Search content 122 function search_content($request) { 123 $query = $request->get_param('query'); 124
125 $args = array( 126 's' => $query, 127 'post_type' => 'post', 128 'posts_per_page' => 20, 129 'post_status' => 'publish', 130 ); 131
132 $search_query = new WP_Query($args); 133 $results = array(); 134
135 if ($search_query->have_posts()) { 136 while ($search_query->have_posts()) { 137 $search_query->the_post(); 138
139 $results[] = array( 140 'id' => get_the_ID(), 141 'title' => get_the_title(), 142 'excerpt' => get_the_excerpt(), 143 'url' => get_permalink(), 144 'thumbnail' => get_the_post_thumbnail_url(get_the_ID(), 'medium'), 145 ); 146 } 147 wp_reset_postdata(); 148 } 149
150 return new WP_REST_Response($results, 200); 151 } 152
153 // Permission callback 154 function check_admin_permission() { 155 return current_user_can('edit_posts'); 156 }
Create Custom WordPress REST API Endpoint
Create custom REST API endpoints to expose custom data, handle external requests, or build headless WordPress applications.
// Register custom REST API endpoint
function register_custom_api_endpoint() {
register_rest_route('custom/v1', '/posts', array(
'methods' => 'GET',
'callback' => 'get_custom_posts',
'permission_callback' => '__return_true', // Public endpoint
));
register_rest_route('custom/v1', '/posts/(?P<id>\d+)', array(
'methods' => 'GET',
'callback' => 'get_custom_post_by_id',
'permission_callback' => '__return_true',
'args' => array(
'id' => array(
'validate_callback' => function($param) {
return is_numeric($param);
}
),
),
));
register_rest_route('custom/v1', '/posts', array(
'methods' => 'POST',
'callback' => 'create_custom_post',
'permission_callback' => 'check_admin_permission',
));
register_rest_route('custom/v1', '/search', array(
'methods' => 'GET',
'callback' => 'search_content',
'permission_callback' => '__return_true',
'args' => array(
'query' => array(
'required' => true,
'sanitize_callback' => 'sanitize_text_field',
),
),
));
}
add_action('rest_api_init', 'register_custom_api_endpoint');
// Get custom posts
function get_custom_posts($request) {
$args = array(
'post_type' => 'post',
'posts_per_page' => 10,
'post_status' => 'publish',
);
$posts = get_posts($args);
$data = array();
foreach ($posts as $post) {
$data[] = array(
'id' => $post->ID,
'title' => $post->post_title,
'content' => apply_filters('the_content', $post->post_content),
'excerpt' => $post->post_excerpt,
'date' => $post->post_date,
'author' => get_the_author_meta('display_name', $post->post_author),
'thumbnail' => get_the_post_thumbnail_url($post->ID, 'large'),
'categories' => wp_get_post_categories($post->ID, array('fields' => 'names')),
'tags' => wp_get_post_tags($post->ID, array('fields' => 'names')),
);
}
return new WP_REST_Response($data, 200);
}
// Get single post by ID
function get_custom_post_by_id($request) {
$post_id = $request['id'];
$post = get_post($post_id);
if (empty($post) || $post->post_status !== 'publish') {
return new WP_Error('not_found', 'Post not found', array('status' => 404));
}
$data = array(
'id' => $post->ID,
'title' => $post->post_title,
'content' => apply_filters('the_content', $post->post_content),
'excerpt' => $post->post_excerpt,
'date' => $post->post_date,
'author' => array(
'name' => get_the_author_meta('display_name', $post->post_author),
'avatar' => get_avatar_url($post->post_author),
),
'thumbnail' => get_the_post_thumbnail_url($post->ID, 'large'),
'categories' => wp_get_post_categories($post->ID, array('fields' => 'names')),
'tags' => wp_get_post_tags($post->ID, array('fields' => 'names')),
'meta' => get_post_meta($post->ID),
);
return new WP_REST_Response($data, 200);
}
// Create new post
function create_custom_post($request) {
$params = $request->get_json_params();
$post_data = array(
'post_title' => sanitize_text_field($params['title']),
'post_content' => wp_kses_post($params['content']),
'post_status' => 'draft',
'post_type' => 'post',
);
$post_id = wp_insert_post($post_data);
if (is_wp_error($post_id)) {
return new WP_Error('creation_failed', 'Failed to create post', array('status' => 500));
}
return new WP_REST_Response(array(
'id' => $post_id,
'message' => 'Post created successfully',
), 201);
}
// Search content
function search_content($request) {
$query = $request->get_param('query');
$args = array(
's' => $query,
'post_type' => 'post',
'posts_per_page' => 20,
'post_status' => 'publish',
);
$search_query = new WP_Query($args);
$results = array();
if ($search_query->have_posts()) {
while ($search_query->have_posts()) {
$search_query->the_post();
$results[] = array(
'id' => get_the_ID(),
'title' => get_the_title(),
'excerpt' => get_the_excerpt(),
'url' => get_permalink(),
'thumbnail' => get_the_post_thumbnail_url(get_the_ID(), 'medium'),
);
}
wp_reset_postdata();
}
return new WP_REST_Response($results, 200);
}
// Permission callback
function check_admin_permission() {
return current_user_can('edit_posts');
}
Endpoint with Authentication
// Endpoint requiring API key
function register_authenticated_endpoint() {
register_rest_route('custom/v1', '/secure-data', array(
'methods' => 'GET',
'callback' => 'get_secure_data',
'permission_callback' => 'verify_api_key',
));
}
add_action('rest_api_init', 'register_authenticated_endpoint');
// API key verification
function verify_api_key($request) {
$api_key = $request->get_header('X-API-Key');
if (!$api_key) {
return new WP_Error('no_api_key', 'API key is missing', array('status' => 401));
}
$valid_key = get_option('custom_api_key');
if ($api_key !== $valid_key) {
return new WP_Error('invalid_api_key', 'Invalid API key', array('status' => 403));
}
return true;
}
// Secure data endpoint
function get_secure_data($request) {
return new WP_REST_Response(array(
'message' => 'This is secure data',
'data' => array(/* your secure data */),
), 200);
}
Pagination Support
// Endpoint with pagination
function get_paginated_posts($request) {
$page = $request->get_param('page') ?: 1;
$per_page = $request->get_param('per_page') ?: 10;
$args = array(
'post_type' => 'post',
'posts_per_page' => $per_page,
'paged' => $page,
'post_status' => 'publish',
);
$query = new WP_Query($args);
$posts = array();
if ($query->have_posts()) {
while ($query->have_posts()) {
$query->the_post();
$posts[] = array(
'id' => get_the_ID(),
'title' => get_the_title(),
'url' => get_permalink(),
);
}
wp_reset_postdata();
}
$response = new WP_REST_Response($posts, 200);
// Add pagination headers
$response->header('X-WP-Total', $query->found_posts);
$response->header('X-WP-TotalPages', $query->max_num_pages);
return $response;
}
Update and Delete Endpoints
// Update post endpoint
function register_update_delete_endpoints() {
register_rest_route('custom/v1', '/posts/(?P<id>\d+)', array(
'methods' => 'PUT',
'callback' => 'update_custom_post',
'permission_callback' => 'check_admin_permission',
));
register_rest_route('custom/v1', '/posts/(?P<id>\d+)', array(
'methods' => 'DELETE',
'callback' => 'delete_custom_post',
'permission_callback' => 'check_admin_permission',
));
}
add_action('rest_api_init', 'register_update_delete_endpoints');
// Update post
function update_custom_post($request) {
$post_id = $request['id'];
$params = $request->get_json_params();
$post_data = array(
'ID' => $post_id,
'post_title' => sanitize_text_field($params['title']),
'post_content' => wp_kses_post($params['content']),
);
$result = wp_update_post($post_data);
if (is_wp_error($result)) {
return new WP_Error('update_failed', 'Failed to update post', array('status' => 500));
}
return new WP_REST_Response(array(
'id' => $post_id,
'message' => 'Post updated successfully',
), 200);
}
// Delete post
function delete_custom_post($request) {
$post_id = $request['id'];
$result = wp_delete_post($post_id, true);
if (!$result) {
return new WP_Error('delete_failed', 'Failed to delete post', array('status' => 500));
}
return new WP_REST_Response(array(
'message' => 'Post deleted successfully',
), 200);
}
Usage Examples
// GET request
fetch('https://yoursite.com/wp-json/custom/v1/posts')
.then(response => response.json())
.then(data => console.log(data));
// POST request
fetch('https://yoursite.com/wp-json/custom/v1/posts', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
title: 'New Post',
content: 'Post content here',
}),
})
.then(response => response.json())
.then(data => console.log(data));
// With API key
fetch('https://yoursite.com/wp-json/custom/v1/secure-data', {
headers: {
'X-API-Key': 'your-api-key-here',
},
})
.then(response => response.json())
.then(data => console.log(data));
Features
- Custom Endpoints: Create unlimited API endpoints
- CRUD Operations: Full create, read, update, delete support
- Authentication: Support for API keys and permissions
- Pagination: Built-in pagination support
- Validation: Parameter validation and sanitization
- Error Handling: Proper HTTP status codes and error messages
Related Snippets
WordPress Custom Breadcrumbs
Create SEO-friendly breadcrumb navigation without plugins
PHPwordpressintermediate
phpPreview
// Display breadcrumbs
function custom_breadcrumbs() {
// Settings
$separator = ' » ';
...#wordpress#breadcrumbs#navigation+2
11/15/2025
View
WordPress Custom Menu Walker
Create custom navigation menu HTML structure with a custom walker class
PHPwordpressadvanced
phpPreview
// Custom Walker Class for Bootstrap 5
class Bootstrap_5_Walker_Nav_Menu extends Walker_Nav_Menu {
/**
...#wordpress#menu#navigation+2
11/13/2025
View
Configure WordPress SMTP Email
Set up SMTP for reliable WordPress email delivery using PHPMailer
PHPwordpressintermediate
phpPreview
// Configure SMTP settings for WordPress
function configure_smtp_settings($phpmailer) {
$phpmailer->isSMTP();
$phpmailer->Host = 'smtp.gmail.com'; // Your SMTP server
...#wordpress#email#smtp+2
11/12/2025
View