PHPackages                             morningtrain/wp-route - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Framework](/categories/framework)
4. /
5. morningtrain/wp-route

ActiveLibrary[Framework](/categories/framework)

morningtrain/wp-route
=====================

A simple route service for WordPress

v0.7.1(3y ago)32.0k11MITPHPPHP ^8.0

Since Oct 22Pushed 3y ago4 watchersCompare

[ Source](https://github.com/Morning-Train/wp-route)[ Packagist](https://packagist.org/packages/morningtrain/wp-route)[ RSS](/packages/morningtrain-wp-route/feed)WikiDiscussions master Synced 3w ago

READMEChangelogDependencies (7)Versions (13)Used By (1)

WP Route
========

[](#wp-route)

A Route Service for WordPress that uses the WordPress rewrite engine and adds Laravel syntax to it.

Table of Contents
-----------------

[](#table-of-contents)

- [Introduction](#introduction)
- [Getting Started](#getting-started)
    - [Installation](#installation)
- [Dependencies](#dependencies)
    - [morningtrain/php-loader](#morningtrainphp-loader)
    - [illuminate/pipeline](#illuminatepipeline)
    - [Symfony HTTP Foundation](#symfony-http-foundation)
- [Usage](#usage)
    - [Setup](#setup)
    - [Adding a route](#adding-a-route)
    - [A route with arguments](#a-route-with-arguments)
    - [Using named routes](#using-named-routes)
    - [Grouping Routes](#grouping-routes)
    - [Accessing WP Query Vars](#accessing-wp-query-vars)
- [Middleware](#middleware)
    - [A quick example](#a-quick-example)
- [REST](#rest)
    - [Options](#options)
    - [Public](#public)
    - [Expose](#expose)
    - [Changing the namespace](#changing-the-namespace)
- [Credits](#credits)
- [Testing](#testing)
- [License](#license)

Introduction
------------

[](#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](https://laravel.com/docs/routing)

Routes MUST call a Controller as callback!

Getting Started
---------------

[](#getting-started)

To get started install the package as described below in [Installation](#installation).

To use the tool have a look at [Usage](#usage)

### Installation

[](#installation)

Install with composer

```
composer require morningtrain/wp-route
```

Dependencies
------------

[](#dependencies)

### morningtrain/php-loader

[](#morningtrainphp-loader)

[PHP Loader](https://github.com/Morning-Train/php-loader) is used to load and initialize all Hooks

### illuminate/pipeline

[](#illuminatepipeline)

[Illuminate Pipeline](https://packagist.org/packages/illuminate/pipeline)

### Symfony HTTP Foundation

[](#symfony-http-foundation)

[Symfony Http Foundation](https://symfony.com/doc/current/components/http_foundation.html)

Usage
-----

[](#usage)

### Setup

[](#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

[](#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

[](#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

[](#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

[](#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

[](#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

[](#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

[](#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

[](#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)

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](https://laravel.com/docs/middleware)

#### A quick example

[](#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

[](#rest)

You can also register rest endpoints using the same syntax! Behind the scenes all Rest routes are registered using [register\_rest\_route](https://developer.wordpress.org/reference/functions/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

[](#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

[](#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

[](#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](https://developer.wordpress.org/reference/functions/wp_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

[](#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
-------

[](#credits)

- [Mathias Munk](https://github.com/mrmoeg)
- [All Contributors](../../contributors)

Testing
-------

[](#testing)

```
composer test
```

License
-------

[](#license)

The MIT License (MIT). Please see [License File](LICENSE) for more information.

###  Health Score

29

—

LowBetter than 57% of packages

Maintenance20

Infrequent updates — may be unmaintained

Popularity22

Limited adoption so far

Community13

Small or concentrated contributor base

Maturity52

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 100% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~52 days

Recently: every ~25 days

Total

11

Last Release

1183d ago

### Community

Maintainers

![](https://avatars.githubusercontent.com/u/278725?v=4)[morningtrain](/maintainers/morningtrain)[@morningtrain](https://github.com/morningtrain)

![](https://avatars.githubusercontent.com/u/5990117?v=4)[Mathias Munk](/maintainers/mrmoeg)[@mrmoeg](https://github.com/mrmoeg)

---

Top Contributors

[![mrmoeg](https://avatars.githubusercontent.com/u/5990117?v=4)](https://github.com/mrmoeg "mrmoeg (80 commits)")

---

Tags

wordpressroutemorningtrain

###  Code Quality

TestsPest

### Embed Badge

![Health badge](/badges/morningtrain-wp-route/health.svg)

```
[![Health](https://phpackages.com/badges/morningtrain-wp-route/health.svg)](https://phpackages.com/packages/morningtrain-wp-route)
```

###  Alternatives

[illuminate/routing

The Illuminate Routing package.

1239.0M2.8k](/packages/illuminate-routing)[larastan/larastan

Larastan - Discover bugs in your code without running it. A phpstan/phpstan extension for Laravel

6.4k51.0M7.5k](/packages/larastan-larastan)[laravel/ai

The official AI SDK for Laravel.

9782.1M161](/packages/laravel-ai)[laravel/mcp

Rapidly build MCP servers for your Laravel applications.

76518.2M118](/packages/laravel-mcp)[illuminate/queue

The Illuminate Queue package.

20432.2M1.5k](/packages/illuminate-queue)[illuminate/validation

The Illuminate Validation package.

18837.7M1.6k](/packages/illuminate-validation)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
