morningtrain / wp-route
A simple route service for WordPress
Installs: 1 590
Dependents: 1
Suggesters: 0
Security: 0
Stars: 3
Watchers: 5
Forks: 1
Open Issues: 0
Requires
- php: ^8.0
- illuminate/container: ^8|^9
- illuminate/pipeline: ^8|^9
- illuminate/support: ^8|^9
- morningtrain/php-loader: ^0.3.0
- symfony/http-foundation: ^6
Requires (Dev)
- brain/monkey: ~2.0.0
- pestphp/pest: ^1.21
README
A Route Service for WordPress that uses the WordPress rewrite engine and adds Laravel syntax to it.
Table of Contents
Introduction
A Route is an address or endpoint in the application. Routes are defined in the /routes
directory of your project,
unless otherwise specified.
All files in this directory are loaded by the framework while it is booting up.
Note that the Route API imitates Laravel Route
Routes MUST call a Controller as callback!
Getting Started
To get started install the package as described below in Installation.
To use the tool have a look at Usage
Installation
Install with composer
composer require morningtrain/wp-route
Dependencies
morningtrain/php-loader
PHP Loader is used to load and initialize all Hooks
illuminate/pipeline
Symfony HTTP Foundation
Usage
Setup
Initialize the package with Route::setup($path)
or, if the package is already initialized, load a directory of routes
with Route::loadDir($path)
use Morningtrain\WP\Route\Route; Route::setup(__DIR__ . '/routes');
Adding a route
// /routes/myroute.php use \Morningtrain\WP\Facades\Route; // Set up a route on the /myroute URL and call MyrouteController::myRoute as callback Route::get('/myroute','MyrouteController::myRoute'); // /Controllers/MyrouteController.php class MyrouteController extends \Morningtrain\WP\Route\Abstracts\AbstractController{ public static function myRoute(){ // Validate request & send http status code // Fetch data // Render view } }
A route with arguments
// /routes/kittens.php use \Morningtrain\WP\Facades\Route; // Set up a route on the /kitten/1 URL and call KittenController::kittenById as callback Route::get('/kitten/{kitten_id}','KittenController::kittenById'); // /Controllers/KittenController.php class KittenController extends \Morningtrain\WP\Route\Abstracts\AbstractController{ public static function kittenById(\Symfony\Component\HttpFoundation\Request $request){ // Validate request & send http status code // Fetch data $kitten_id = $request->query->get('kitten_id'); // Render view } }
Using named routes
// /routes/kittens.php use \Morningtrain\WP\Facades\Route; // Set up a route on the /kitten/1 URL and call KittenController::kitten as callback Route::get('/kitten/{kitten_id}','KittenController::kitten')->name('kitten'); // /Controllers/KittenController.php class KittenController extends \Morningtrain\WP\Route\Abstracts\AbstractController{ public static function kitten(\Symfony\Component\HttpFoundation\Request $request){ // Validate request & send http status code // Fetch data $kitten_id = $request->query->get('kitten_id'); // Render view } } // In some template or hook you can now get and check for the named route // Get Url for Kittens Route $url = Route::route('kittens',['kitten_id' => 1]); // Would return /kitten/1 // Check if currently on kitten route $bool = Route::current()->getName() === 'kitten';
Grouping Routes
You may group a set of routes to apply a shared prefix to all of them or to apply shared middleware.
With prefix
use \Morningtrain\WP\Facades\Route; Route::prefix('my-prefix')->group(function(){ Route::get('foo',FooController::class); // url will be /my-prefix/foo Route::get('bar',BarController::class); // url will be /my-prefix/bar })
With middleware
use \Morningtrain\WP\Facades\Route; // Users must now be logged in to view these two routes Route::middleware('auth')->group(function(){ Route::get('foo',FooController::class); Route::get('bar',BarController::class); })
With both prefix and middleware
use \Morningtrain\WP\Facades\Route; Route::prefix('my-prefix') ->middleware('auth') ->group(function(){ Route::get('foo',FooController::class); Route::get('bar',BarController::class); })
Accessing WP Query Vars
WordPress query vars are added to the Request class as query data. So you can access them like so:
use Symfony\Component\HttpFoundation\Request; // Controller class FooController extends \Morningtrain\WP\Route\Abstracts\AbstractController{ public function __invoke(Request $request){ // Do something here $post = $request->query->get('post'); } } // Middleware function(Request $request, $next){ if($request->query->has('post')){ // Do something here $post = $request->query->get('post'); } return $next($request); }
Middleware
Middleware are functions called for a route after it has been matched against a url, but before its callback is called.
Middleware are useful for validating a group of routes, validating a users permissions or hijacking a request.
Read more about them here: Laravel Docs - Middleware
A quick example
Middleware are function that receive a request object and a closure that represents the next middleware in the pipeline.
It is important to always return $next($request);
at the end of a valid middleware.
In the example below we create a middleware that stops the pipeline if the current user is not logged in and returns a response with status 404. If the user is logged in the middleware pipeline continues and eventually lets the route call its controller.
A middleware is allowed to either continue the pipeline, return a Response or throw an exception. Responses must
be \Symfony\Component\HttpFoundation\Response
and will be sent automatically. Exceptions are caught and converted into
custom \Morningtrain\WP\Route\Responses\WPErrorResponse
that are then displayed using wp_die()
use Morningtrain\WP\Facades\Route; use \Symfony\Component\HttpFoundation\Request; Route::middleware([function(Request $request, $next){ if(!\is_user_logged_in()){ // Returns a Response object return \Morningtrain\WP\Route\Classes\Response::with404(); } // Continues the middleware pipeline return $next($request); }]) ->group(function(){ Route::get('my-account',MyAccountController::class); });
Rest
You can also register rest endpoints using the same syntax! Behind the scenes all Rest routes are registered using register_rest_route
use Morningtrain\WP\Facades\Rest; Rest::get('products', [ProductRestController::class, 'getAllProducts'])->public(); // Will register an endpoint like /wp-json/mtwp/v1/products that accepts GET requests
Options
You can use middleware, prefix, groups and names on Rest routes the same way as you can on rewrite routes!!
Note: Middleware is applied AFTER WordPress has identified the route and passed through all other verifications such
as permission_callback
, but before the controller or supplied callback is called.
Public
To make an endpoint public chain public()
on either the route or its group. This simply sets the permission_callback
to __return_true
. This defaults to __return_false
.
Expose
You can expose the endpoint URL to the DOM by chaining expose()
onto the route or its group. This outputs the url to a
JavaScript object similar to the
way localize_script would.
The exposed url can be accessed like so:
const fooEndpointUrl = window.mtwpRestRoutes.foo; // /wp-json/mtwp/v1/foo
Note: to expose an endpoint it has to be named.
Changing the namespace
You can set the namespace the same way you would a prefix.
use Morningtrain\WP\Facades\Rest; Rest::namespace('foo/v1')->group(function(){ Rest::get('foo',FooController::class); // /wp-json/foo/v1/foo });
This can be combined with prefixes
use Morningtrain\WP\Facades\Rest; Rest::namespace('foo/v1')->prefix('bar')->group(function(){ Rest::get('foo',FooController::class); // /wp-json/foo/bar/v1/foo }); // -- or -- Rest::namespace('foo/v1')->group(function(){ Rest::prefix('bar')->group(function(){ Rest::get('foo',FooController::class); // /wp-json/foo/bar/v1/foo Rest::get('baz',FooController::class); // /wp-json/foo/bar/v1/baz }); });
Credits
Testing
composer test
License
The MIT License (MIT). Please see License File for more information.