A Practical Guide to Custom WordPress REST API Endpoints

The default WordPress REST API endpoints are verbose. A single post request returns dozens of fields you probably do not need, and getting related data often requires multiple round trips. Custom endpoints solve both problems.
Registering a Custom Endpoint
Use register_rest_route in the rest_api_init hook. I always namespace my endpoints to avoid collisions:
add_action("rest_api_init", function () {
register_rest_route("mytheme/v1", "/projects", [
"methods" => "GET",
"callback" => "get_projects_handler",
"permission_callback" => "__return_true",
"args" => [
"per_page" => [
"default" => 10,
"sanitize_callback" => "absint",
],
],
]);
});
Shaping the Response
The callback function is where you control exactly what data gets returned. Instead of sending the entire post object, cherry-pick the fields your frontend actually uses:
function get_projects_handler(WP_REST_Request $request) {
$posts = get_posts([
"post_type" => "project",
"posts_per_page" => $request->get_param("per_page"),
"post_status" => "publish",
]);
$items = array_map(function ($post) {
$thumb_id = get_post_thumbnail_id($post->ID);
return [
"id" => $post->ID,
"title" => get_the_title($post),
"slug" => $post->post_name,
"description" => get_the_excerpt($post),
"image" => $thumb_id ? wp_get_attachment_image_url($thumb_id, "large") : null,
"url" => get_post_meta($post->ID, "live_url", true) ?: null,
];
}, $posts);
return new WP_REST_Response($items, 200);
}
Why This Matters
Custom endpoints reduce payload size, eliminate multiple API calls, and give you full control over data shape. For headless WordPress projects, they are essential. One well-designed endpoint can replace three or four default API calls.
Written by
Adrian Saycon
A developer with a passion for emerging technologies, Adrian Saycon focuses on transforming the latest tech trends into great, functional products.


