WordPress Custom REST Endpoint
Register a custom REST API endpoint in WordPress with proper authentication and validation.
<?php
/**
* Register a custom REST API endpoint.
*
* Usage: GET /wp-json/my-plugin/v1/items?per_page=10&page=1
*/
add_action( 'rest_api_init', function () {
register_rest_route( 'my-plugin/v1', '/items', array(
'methods' => WP_REST_Server::READABLE,
'callback' => 'my_plugin_get_items',
'permission_callback' => 'my_plugin_items_permission',
'args' => array(
'per_page' => array(
'type' => 'integer',
'default' => 10,
'minimum' => 1,
'maximum' => 100,
'sanitize_callback' => 'absint',
),
'page' => array(
'type' => 'integer',
'default' => 1,
'minimum' => 1,
'sanitize_callback' => 'absint',
),
),
) );
} );
/**
* Permission callback — require authentication.
*/
function my_plugin_items_permission( WP_REST_Request $request ): bool {
return current_user_can( 'read' );
}
/**
* Endpoint callback — return paginated items.
*/
function my_plugin_get_items( WP_REST_Request $request ): WP_REST_Response {
$per_page = $request->get_param( 'per_page' );
$page = $request->get_param( 'page' );
// Example: fetch from a custom table.
global $wpdb;
$table = $wpdb->prefix . 'my_items';
$offset = ( $page - 1 ) * $per_page;
$total = (int) $wpdb->get_var( "SELECT COUNT(*) FROM {$table}" );
$items = $wpdb->get_results(
$wpdb->prepare(
"SELECT * FROM {$table} ORDER BY created_at DESC LIMIT %d OFFSET %d",
$per_page,
$offset
)
);
$response = rest_ensure_response( $items );
$response->header( 'X-WP-Total', $total );
$response->header( 'X-WP-TotalPages', ceil( $total / $per_page ) );
return $response;
}