Search by

pollora / wp-rest

pollora

WordPress REST API routes declared with PHP attributes: a controller class, #[WpRestRoute] and #[Method], permissions as classes. Runs with or without Laravel.

Package info

github.com/Pollora/wp-rest

Homepage

pkg:composer/pollora/wp-rest

Statistics

Installs: 421

Dependents: 1

Suggesters: 0

Stars: 0

Open Issues: 0

v0.1.0 2026-10-13 08:04 UTC

This package is auto-updated.

Last update: 2026-10-13 08:05:11 UTC


README

Pollora WP REST: WordPress REST API routes declared with PHP attributes

Latest version Total downloads Tests License

WordPress REST API routes written as a controller class: #[WpRestRoute] on the class gives the namespace and route, #[Method] on a method gives its HTTP verbs, and a permission class decides who may call it. No register_rest_route() call, no rest_api_init callback to write.

The controller is built with its constructor dependencies, its methods receive the route parameters they name and the WP_REST_Request when they ask for it.

Part of Pollora, the Laravel framework for WordPress, where it is installed and wired for you: see REST API. It runs without Laravel too, in a WordPress plugin, a Bedrock site or any PHP project.

Installation

composer require pollora/wp-rest

Requires PHP 8.3+. It builds on pollora/attributes and pollora/discovery.

Declaring routes

use Pollora\Attributes\WpRestRoute;
use Pollora\Attributes\WpRestRoute\Method;
use Pollora\WpRest\Permissions\Can;
use Pollora\WpRest\Permissions\IsLoggedIn;

#[WpRestRoute('app/v1', 'documents/(?P<documentId>\\d+)', permissionCallback: IsLoggedIn::class)]
final class DocumentApi
{
    public function __construct(private readonly DocumentRepository $documents) {}

    #[Method('GET')]
    public function show(int $documentId): array
    {
        return $this->documents->find($documentId);
    }

    #[Method('DELETE', permissionCallback: new Can('delete_post', parameter: 'documentId'))]
    public function destroy(WP_REST_Request $request, int $documentId): array
    {
        return ['deleted' => $this->documents->delete($documentId)];
    }
}
  • GET wp-json/app/v1/documents/18 calls show(18). A parameter typed WP_REST_Request receives the request; the others are read from the route by name.
  • #[Method] accepts GET, POST, PUT, DELETE and PATCH, alone or as a list; with any other verb the route is not registered, and the logger says why.
  • A method's permission replaces the route's. Without either, the route is public.

Permissions

Class Allows
IsLoggedIn any logged-in user
IsAdmin users who can manage_options
new Can('edit_posts') users with a capability; parameter: passes a request parameter for a meta capability such as edit_post

A permission class of your own implements Pollora\Attributes\WpRestRoute\Permission: allow(WP_REST_Request $request): bool|WP_Error.

Wiring it outside Pollora

Point the discovery engine at your code and add WpRestDiscovery; routes are registered on rest_api_init.

use Pollora\Discovery\Domain\Models\DiscoveryLocation;
use Pollora\Discovery\Infrastructure\Services\DiscoveryEngine;
use Pollora\WpRest\Infrastructure\Services\WpRestDiscovery;

(new DiscoveryEngine)
    ->addLocation(new DiscoveryLocation('MyPlugin\\', __DIR__.'/src'))
    ->addDiscovery('wp_rest_routes', new WpRestDiscovery)
    ->run();

Controllers are built by the engine's instance resolver: by reflection by default (constructor parameters typed with a class are built in turn), by your container if you give the engine a ContainerInstanceResolver (PSR-11). WpRestDiscovery takes a PSR-3 logger, which records the routes it could not register.

Testing

composer test   # unit tests, PHPStan, Pint

License

MIT. See LICENSE.