How to Load JavaScript and CSS in a WordPress Plugin
When a WordPress plugin adds a feature to a page, the browser needs the plugin’s JavaScript and CSS files. WordPress’s enqueue functions…
When you add a custom endpoint to a WordPress site, you create a URL that lets other code request or change site data through the REST API. A permission check tells WordPress whether a request may run the endpoint’s main callback, the function that handles the request. Without that check, a route that returns private information can expose it, and a route that changes content can allow unwanted actions.
Register the route on WordPress’s rest_api_init hook, then give it a permission_callback that checks the capability needed for the requested action. A capability is a specific permission, such as reading a post or managing site settings. The example below creates a read-only route for a post and allows access only when the current user can read that post.
WordPress uses a namespace, a name prefix, to distinguish one plugin’s endpoints from another’s. The namespace below, acme/v1, follows the common vendor-and-version pattern. The route accepts a post ID made of digits in the URL.
add_action( 'rest_api_init', 'acme_register_post_route' );
function acme_register_post_route() {
register_rest_route(
'acme/v1',
'/posts/(?P<id>\d+)',
array(
'methods' => WP_REST_Server::READABLE,
'callback' => 'acme_get_post',
'permission_callback' => 'acme_can_read_post',
)
);
}
function acme_can_read_post( WP_REST_Request $request ) {
$post = get_post( absint( $request['id'] ) );
return $post instanceof WP_Post
&& current_user_can( 'read_post', $post->ID );
}
function acme_get_post( WP_REST_Request $request ) {
$post = get_post( absint( $request['id'] ) );
if ( ! $post ) {
return new WP_Error(
'acme_post_not_found',
'Post not found.',
array( 'status' => 404 )
);
}
return array(
'id' => $post->ID,
'title' => get_the_title( $post ),
'status' => $post->post_status,
);
}
WordPress calls acme_register_post_route() during REST API setup. WP_REST_Server::READABLE restricts the route to a read request, and the route pattern captures the numeric URL segment as id. WordPress passes that value to each callback through a WP_REST_Request object.
The permission callback looks up the post, then checks whether the current user has the read_post capability for it. If the post does not exist or the user lacks that capability, WordPress does not run the main callback. The main callback returns only the post ID, title, and status, so include only fields the caller needs.
WordPress expects a permission_callback when you register a custom route. The REST API Handbook’s endpoint documentation covers route registration, callbacks, request arguments, and permission checks.
Choose a capability that grants the exact access the route needs. For example, a route that changes site settings might check current_user_can( 'manage_options' ). A route that updates a particular post should check a capability tied to that post, such as edit_post, rather than granting access to every logged-in user.
Authentication and authorization answer different questions. Authentication establishes who sent the request; authorization determines what that user is allowed to do. A permission callback that checks only whether someone is logged in does not establish that they may read a particular record or perform a particular action.
For a genuinely public route, use 'permission_callback' => '__return_true'. Keep the response limited to information intended for public access. For protected routes, do not use __return_true as a shortcut: the callback is the gate that decides whether WordPress runs the route’s main callback.
When a logged-in browser uses WordPress cookie authentication, the request must include a REST nonce. Send it in the X-WP-Nonce header or the _wpnonce request parameter. WordPress creates that nonce with wp_create_nonce( 'wp_rest' ). Without the nonce, WordPress treats the REST request as unauthenticated, so capability checks do not see the logged-in user. The nonce helps protect cookie-authenticated requests from cross-site request forgery, but it does not replace the capability check. See the discussion of REST nonces and user capabilities.
The example restricts its ID to digits in the route pattern and casts it to an integer before looking up the post. For routes that accept other input, register arguments with validation and sanitization callbacks so WordPress checks or cleans values before the main callback uses them. The endpoint documentation describes these argument options.
For a route that changes data, allow only the HTTP method it needs, validate every input on the server, and use HTTPS to protect credentials and data in transit. After registering the route, request /wp-json/acme/v1/posts/123 with a post ID that exists. Check that an authorized user receives only the intended fields and that a user without the required capability cannot access the callback’s response.
Give Vroni a GitHub issue, bug report, spec, or rough idea. It reads the repo, plans the change, writes code, runs checks, and works toward a review-ready pull request.
Take a look at vroni.com