The WordPress REST API, introduced in WordPress 4.7, lets you expose your data to JavaScript front-ends, mobile apps, and external services over HTTP. Registering a custom endpoint takes a handful of lines and works alongside all existing authentication and permission checks.
Problem: How do you register a custom route in the WordPress REST API that isn't tied to a built-in post type?
Solution: Use register_rest_route() inside a rest_api_init action hook to define your endpoint, its HTTP methods, callback, and permission callback.
The example below registers a public read endpoint and an authenticated write endpoint under the /wp-json/myplugin/v1/ namespace:
add_action( 'rest_api_init', 'register_my_rest_routes' );
function register_my_rest_routes() {
// Public GET endpoint
register_rest_route( 'myplugin/v1', '/posts/', [
'methods' => WP_REST_Server::READABLE,
'callback' => 'get_my_posts',
'permission_callback' => '__return_true', // public
'args' => [
'count' => [
'default' => 5,
'sanitize_callback' => 'absint',
'validate_callback' => function( $val ) {
return $val > 0 && $val <= 50;
},
],
],
] );
// Authenticated POST endpoint
register_rest_route( 'myplugin/v1', '/note/', [
'methods' => WP_REST_Server::CREATABLE,
'callback' => 'save_my_note',
'permission_callback' => function() {
return current_user_can( 'edit_posts' );
},
] );
}
function get_my_posts( WP_REST_Request $request ) {
$posts = get_posts( [
'posts_per_page' => $request->get_param( 'count' ),
'post_status' => 'publish',
] );
$data = array_map( function( $post ) {
return [
'id' => $post->ID,
'title' => $post->post_title,
'link' => get_permalink( $post ),
];
}, $posts );
return rest_ensure_response( $data );
}
function save_my_note( WP_REST_Request $request ) {
$note = sanitize_textarea_field( $request->get_param( 'note' ) );
update_option( 'my_saved_note', $note );
return rest_ensure_response( [ 'saved' => true ] );
}
NOTE: Never set permission_callback to __return_true on a write endpoint. Always check capabilities. Return errors as WP_Error objects — the REST API will convert them to proper JSON error responses with HTTP status codes.