PHPackages                             devio/permalink - 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. devio/permalink

ActiveLibrary[Framework](/categories/framework)

devio/permalink
===============

Permalink routing system for Laravel. Advanced database driven routes. Handle your permalinks + SEO parameters directly from database.

1.1.0(5y ago)654.7k13[1 issues](https://github.com/IsraelOrtuno/permalink/issues)[1 PRs](https://github.com/IsraelOrtuno/permalink/pulls)MITPHPCI failing

Since Jun 8Pushed 4y ago3 watchersCompare

[ Source](https://github.com/IsraelOrtuno/permalink)[ Packagist](https://packagist.org/packages/devio/permalink)[ RSS](/packages/devio-permalink/feed)WikiDiscussions master Synced 3d ago

READMEChangelog (10)Dependencies (9)Versions (17)Used By (0)

Advanced Laravel Permalinks and SEO Management from Database
============================================================

[](#advanced-laravel-permalinks-and-seo-management-from-database)

[![Build Status](https://camo.githubusercontent.com/915a37322f29625a9555c75a6a6a30c01d6ed1662d04dbec232ce5769d2b1e1a/68747470733a2f2f7472617669732d63692e636f6d2f49737261656c4f7274756e6f2f7065726d616c696e6b2e7376673f6272616e63683d6d6173746572)](https://travis-ci.com/IsraelOrtuno/permalink) [![Latest Stable Version](https://camo.githubusercontent.com/63dd0a403f692833c25cafb5fa77b20df3979a34775518247175e1087c1c2c7f/68747470733a2f2f706f7365722e707567782e6f72672f646576696f2f7065726d616c696e6b2f76657273696f6e)](https://packagist.org/packages/devio/permalink)

2021-08-25: Looking for maintainer
----------------------------------

[](#2021-08-25-looking-for-maintainer)

Despite it's pretty stable, I do not have time to keep maintaining this package for future Laravel releases and add more features so I am looking for anyone who found this useful and would like to maintain it. Feel free to contact!

---

This package allows to create dynamic routes right from database, just like WordPress and other CMS do.

**IMPORTANT** Despite the functionality of this package is not complex at all, there are a few things and good practices to consider. I really recommend to carefully read the entire documentation to deeply understand how this package works as you will be replacing the default Laravel Routing System and do not want to mess up with your URLs and SEO!

Roadmap
-------

[](#roadmap)

- [Resources for visual SEO management](https://github.com/IsraelOrtuno/permalink-form) (in progress)

Documentation
-------------

[](#documentation)

- [Getting the route for a resource](#getting-the-route-for-a-resource)
- [Automatic SEO generation](#automatic-seo-generation)

- [Installation](#installation)
- [Getting Started](#getting-started)
- [Replacing the Default Router](#replacing-the-default-router)
- [Creating a Permalink](#creating-permalinks)
- [Updating a Permalink](#updating-permalinks)
- [Binding Models to Permalinks](#binding-models-to-permalinks)
- [Automatically Handling Permalinks](#automatically-handling-permalinks)
- [Nesting Permalinks](#nesting-permalinks)
- [Deleting Permalinks](#deleting-permalinks)
- [Caching Permalinks](#caching.-permalinks)
- [Handling SEO Attributes](#handling-seo-attributes)

Installation
------------

[](#installation)

### Install the package

[](#install-the-package)

```
composer require devio/permalink
```

### Run the migrations

[](#run-the-migrations)

```
php artisan migrate
```

Getting started (PLEASE READ)
-----------------------------

[](#getting-started-please-read)

This package handles dynamic routing directly from our database. Nested routes are also supported, so we can easily create routes like this `/jobs/frontend-web-developer`.

Most of the solutions out there are totally bound to models with polymorphic relationships, however that's not flexible at all when dealing with routes without models. This package supports both, routes with bound models and regular routes.

Basically, the package stores routes in a `permalinks` table which contains information about every route:

- Slug
- Parent (parent route for nesting)
- Model (if any)
- Action (controller action or model default action)
- SEO options (title, metas...)

By default, this package will try to find if there's a a permalink in the `permalinks` table matching the current request path in a single SQL query. This is ok for most of the use cases. If for some reason you want to cache your permalinks information into the Laravel Routing Cache, please refer to the [Caching Permalinks](#caching) section.

### Example

[](#example)

Let check out a very basic example to understand how it internally works:

idslugparent\_idparent\_forentity\_typeentity\_idactionfinal\_path1usersNULLApp\\UserNULLNULLUserController@indexusers2israel-ortuno1NULLApp\\User1UserController@showusers/israel-ortunoIt will run the following (this example tries to be as explicit as possible, internally it uses eager loading and some other performance optimizations):

```
$router->get('users', 'UserController@index');
$router->get('users/israel-ortuno', 'UserController@show');

// Which will produce:
//    /users                UserController@index
//    /users/israel-ortuno
```

**NOTE:** The `show` method will receive the user as parameter `App\User::find(1)` the route is bound to that model.

Replacing the Default Router
----------------------------

[](#replacing-the-default-router)

This package has it's own router which extends the default Laravel router. To replace the default router for the one included in this package you have two options:

```
php artisan permalink:install {--default}
```

The console will propmpt you with 2 options:

```
  [0] Http/Kernel.php (Default & Recommended)
  [1] bootstrap/app.php (Advanced)
```

Select the one that fits your needs. For most cases I recommend going through `Http\Kernel.php`. Use the `--default` option to avoid blocking prompts (could also use the default Laravel command's flag `--no-interaction`).

Both of these methods will replace the default Laravel Router by an extended version provided by this package which contains the Permalink management logic.

**IMPORTANT:** Use either `Http\Kernel.php` or `bootstrap/app.php`. **Do not** use both as it may cause unexpected behaviour.

Creating Permalinks
-------------------

[](#creating-permalinks)

That's pretty much it for setting up the dynamic routing system. Let's create a Permalink record and test it out!

```
Permalink::create([
    'slug' => 'home',
    'action' => 'App\Http\Controllers\HomeController@index'
]);
// Then visit /home
```

If your permalink is bound to a model (read next section), you may create your permalink record as follows:

```
// Note: when using the User::create method, even if permalinkHandling (read more about it below)
// is disabled, it will create the permalink record.
$user = User::create([
    'name' => 'israel',
    'permalink' => [
        'slug' => 'israel-ortuno',
        'action' => 'user.show',
        'seo' => [...] // omit this attribute until you read more about it
    ]
]);

// Or

$user->createPermalink([...);
```

If you do not provide any data to the `permalink` key when using `User::create` or `createPermalink`, it will automatcally use the default data. Any existing key in the data array will override its default value when creating the permalink.

**NOTE:** This will only work if `permalinkHandling` has not been disabled, read more about it below.

Updating Peramlinks
-------------------

[](#updating-peramlinks)

You can easily update a permalink just like any other Eloquent model. **BE CAREFUL** when updating a permalink slug as the previous URL won't be available anymore and this package does not handle 301/302 redirections.

### Rebuilding Final Path (PLEASE READ)

[](#rebuilding-final-path-please-read)

When updating a slug, the package will recursively update its nested permalinks `final_url` attribute reemplacing the previous slug semgment with the new one. You can control this behaviour from the `rebuild_children_on_update` option in your `config/permalink.php` config file. Disable this option if you wish to handle this task manually (NOT RECOMMENDED).

Check out `Devio\Permalink\Services\PathBuilder` class to discover the methods available for performing the manual update.

**NOTE:** Make sure to rebuild childen's final path in the current request lifecycle.

Binding Models to Permalinks
----------------------------

[](#binding-models-to-permalinks)

You may want to bind a permalink to a model resource, so you can create a unique URL to access that particular resource. If you want to do so, you just have to use the tait `HasPermalinks` and implement the contract `Permalinkable` to your model.

```
class User extends Model implements \Devio\Permalink\Contracts\Permalinkable;
{
    use \Devio\Permalink\HasPermalinks;

    public function permalinkAction()
    {
        return UserController::class . '@show';
    }

    public function permalinkSlug(): array
    {
        return ['entity.name'];
    }
}
```

Once you have this setup, this package will generate a permalink for every new record of this model automatically.

Also, the `Permalinkable` interface will force you to define two simple methods:

**permalinkAction()**

This method will return the default controller action responsible for handling the request for this particular model. The model itself will be injected into the action (as Laravel usually does for route model binding).

```
public function show($user)
{
    return view('users.show', $user);
}
```

**NOTE:** This action will be overwritten by any existing value on the `action` column in your permalink record, so you could have multiple actions for the same model in case you need them.

**permalinkSlug()**

This method is a bit more tricky. Since all the slugging task is being handled by the brilliant [Sluggable](https://github.com/cviebrock/eloquent-sluggable) package, we do have to provide the info this package requires on its [sluggable](https://github.com/cviebrock/eloquent-sluggable#updating-your-eloquent-models) method.

The permalink model will expose an `entity` polymorphic relationship to this model. Since the slugging occurs in the `Permalink` model class, we do have to specify which is going to be the source for our slug. You can consider `entity` as `$this`, so in this case `entity.name` would be equivalent to `$this->name`. Return multiple items if you would like to concatenate multiple properties:

```
['entity.name', 'entity.city']

```

**NOTE:** This method should return an array compatible with the Sluggable package, please [check the package documentation](https://github.com/cviebrock/eloquent-sluggable#updating-your-eloquent-models) if you want to go deeper.

Automatically Handling Permalinks
---------------------------------

[](#automatically-handling-permalinks)

By default, this package takes care of creating/updating/deleting your permalinks based on the actions performed in the bound model. If you do not want this to happen and want to decide when decide the precise moment the permalink has to be created/updated/deleted for this particular model. You can disable the permalink handling in two ways:

```
// Temporally disable/enable:
$model->disablePermalinkHandling();
$model->enablePermalinkHandling();

// Permanent disable or return a condition.
// Create this method in you model:
public function permalinkHanlding()
{
    return false;
}
```

### Creating

[](#creating)

A permalink will be created automatically when your resource fires a `saved` event. It will be populate with the default data unless you have provided a `peramlink` key array to the creation array or used the `setPermalinkAttribute` mutator.

```
User::create(['name' => 'israel', 'permalink' => ['slug' => 'israel']]);
//
$user = new User;
$user->permalink = ['slug' => 'israel'];
$user->save();
```

If `permalinkHandling` is disabled, you will be able to decide when to create the permalink:

```
// Assume permalinkHanlding() returns false
$user = User::create(['name' => 'israel']);
// Perform other tasks...
$user->createPermalink(); // Array is optional, provide data to override default values
```

**NOTE:** Be aware that the permalink record will be still created if the data provided for creation contains a `permalink` key.

### Updating

[](#updating)

You can update your permalink right like creating:

```
$user = User::find(1);

$user->updatePermalink(['seo' => ['title' => 'changed']]);
```

**NOTE:** By default, if you update a permalink's slug, it will recursively update all its nested elements with the new segment. Read more about [updating permalinks](#updating-permalinks).

### Deleting

[](#deleting)

If you delete a resource which is bound to a permalink record, the package will automatically destroy the permalink for us. Again, if you do not want this to happen and want to handle this yourself, disable the permalink handling in your model.

### Support for SoftDeleting

[](#support-for-softdeleting)

SoftDeleting support comes out of the box, so if your resource is soft deleted, the permalink will be soft deleted too. If you restore your resource, it will be restored automatically too. Disable handling for dealing with this task manually.

**NOTE:** If you `forceDelete()` your resource, the permalink will also be deleted permanently.

Nesting Permalinks
------------------

[](#nesting-permalinks)

You may want to have a nested permalink structure, let's say, for your blog. Parent will be `/blog` and every post should be inside this path, so you can do things like:

```
/blog           -> Blog index, show all blog posts
/blog/post-1
/blog/post-2
...

```

This package handles this for you out of the box:

### Automatic Permalink Nesting

[](#automatic-permalink-nesting)

The `permalinks` table has a column for automatically nesting models: `parent_for`. This attribute should contain the FQN class name of the model you want it to be parent for. Once set, when you create a new permalink for the specified model, it will automatically nested to the given parent.

This will usually be a manual procedure you will do in you database so it may look like like the [example above](#example).

### Disable Automatic Nesting

[](#disable-automatic-nesting)

If you are deep into this package and want to manage the nesting of your permalinks manually (why would you do so? but just in case...), feel free to disable this feature from the config:

```
// Globally disable this feature for all models in your permalink.php config file
'nest_to_parent_on_create' => false
// or
config()->set('permalink.nest_to_parent_on_create', false);

// Disable this feature for a particular model. Define this method in your model class:
public function permalinkNestToParentOnCreate()
{
    return false;
}
```

### Manually Nesting

[](#manually-nesting)

If you wish to nest a permalink to other manually, all you have to do is to set the `id` of the parent permalink to the `parent_id` attribute on the child permalink:

```
Permalink::create(['slug' => 'my-article', 'parent_id' => 1, 'action' => '...']);
```

Permalink Actions
-----------------

[](#permalink-actions)

The `action` attribute on your permalink record will be providing the information about what's going to handle the request when that permalink matches the current request URI.

### Controllers as Actions

[](#controllers-as-actions)

Every permalink should have a action, specifically those which are not bound to models. You should specify a `controller@action` into the `action` column of your permalink record.

If there's a model bound to the permalink (entity), it will be passed as parameter to the controller action:

```
class UserController {
    public function show($user)
    {
        return view('users.show', compact('user'));
    }
}
```

### Views as Actions

[](#views-as-actions)

For simple use cases you could simply specify a view's path as an action for your permalink. The permalink entity (if bound to a model) will also be available in this view as mentioned above:

```
Permalink::create(['slug' => 'users', 'action' => 'users.index']);
```

If bound to a model...

```
Permalink::create(['slug' => 'israel-ortuno', 'entity_type' => User::class, 'entity_id' => 1, 'action' => 'users.show']);

// And then in users/show.blade.php
Welcome {{ $user->name }}
```

#### Using a Custom Controller for View Actions

[](#using-a-custom-controller-for-view-actions)

Under the hood, view actions are handled by a controller provided by this package `Devio\Permalink\Http\PermalinkController`. You can update this controller with your own implementation if needed. Maybe you want to apply some middleware, or resolve views in a different way...

All you have to do is to bind your implementation to the container in your `AppServiceProvider` (or other):

```
// In your AppServiceProvider.php
public function register()
{
    $this->bind('Devio\Permalink\Http\PermalinkController', YourController::class);
}

// And then...
class YourController
{
    use Devio\Permalink\Http\ResolvesPermalinkView;

    public function __construct()
    {
        // Do your stuff.
    }
}
```

This way, Laravel will now resolve your implementation out of the container.

If you wish to have your own implementation for resolving the views, do not use the `Devio\Permalink\Http\ResolvesPermalinkView` trait and create your own `view()` method.

### Default Actions (in Models)

[](#default-actions-in-models)

If you have a model bound to a permalink, you may define a default action in your model like this:

```
public function permalinkAction()
{
    return UserController::class . '@show'; // Or a view
}
```

This method is mandatory once you implement the `Permalinkable` interface.

### Overriding the Default Action

[](#overriding-the-default-action)

By default, the permalink will resolve the action based on the `permlainkAction` method of the permalink entity. However, if you specifiy a value to the `action` column in the permalink record, it will override the default action. For example:

```
class User extends Model
{
    use HasPermalinks;
    ...
    public function permalinkAction()
    {
        return UserController::class . '@index';
    }
    ...
}

// And then...
$user = User::create([
    'name' => 'israel',
    'permalink' => [
        'action' => 'user.show'
    ]
]);
// Or just update the action attribute as you like
```

When accessing the permalink for this particular entity, `user/show.blade.php` will be responsible for handling the request rather than the default controller. Isn't it cool?

Deleting Permalinks
-------------------

[](#deleting-permalinks)

By default, and if

### Support for SoftDeleting

[](#support-for-softdeleting-1)

Caching Permalinks (Read Carefully!)
------------------------------------

[](#caching-permalinks-read-carefully)

As mentioned above, this package will perform a single SQL query on every request in order to find a matching permalink for the current URI. This is quite performant and should be ok for most use cases. This query may also be cached for super-fast access if needed.

You may cache your permalink routes into the default Laravel Route Caching system, but be aware that it will generate a route for every single record in your `permalinks` table, so I **DO NOT** recommend it if you have a large amount of permalinks, as you may end up with a huge base64 encoded string in your `bootstrap/cache/routes.php` which may really slow down your application bootstrapping. Perform some tests to know if you are really improving performance for the amount of routes you pretend to cache.

In order to cache you permalinks, all you have to do is to load the entire `permalinks` dataset into the Router and then run the Route Caching command:

```
Router::loadPermalinks();
Artisan::call('route:cache');
```

You could create a command to perform this two actions or whatever you consider. From now on, you will have to manually update this cache every time a permalink record has been updated.

Handling SEO Attributes
-----------------------

[](#handling-seo-attributes)

This package wouldn't be complete if you could not configure your SEO attributes for every single permalink record, it would have been almost useless!

Automatic SEO generation
------------------------

[](#automatic-seo-generation)

For SEO tags generation [ARCANDEV/SEO-Helper](https://github.com/ARCANEDEV/SEO-Helper) is being used. This package offers a powerful set of tools to manage your SEO meta tags.

```
{
  "meta": {
    "title": "Specific title",                  // The
    "description": "The meta description",      // The page meta description
    "robots": "noindex,nofollow"                // Robots control
  },
  "opengraph":{
    "title": "Specific OG title",               // The og:title tag
    "description": "The og description",        // The og:description tag
    "image": "path/to/og-image.jpg"             // The og:image tag
  },
  "twitter":{
    "title": "Specific Twitter title",          // The twitter:title tag
    "description": "The twitter description",   // The twitter:description tag
    "image": "path/to/og-image.jpg"             // The twitter:image tag
  }
}

```

**NOTE:** This is just an example of the most common tags but you could any kind of tag supported (index, noindex...) by [ARCANDEV/SEO-Helper](https://github.com/ARCANEDEV/SEO-Helper), just make sure to nest it correctly.

In order to have all this content rendered in your HTML you should add the following you your ``:

```

    {!! seo_helper()->render() !!}

```

##### OR

[](#or)

```

    {{ seo_helper()->renderHtml() }}

```

Plase visit [SEO-Helper – Laravel Usage](https://github.com/ARCANEDEV/SEO-Helper/blob/master/_docs/3-Usage.md#4-laravel-usage) to know more about what and how to render.

### Understanding How it Works

[](#understanding-how-it-works)

Under the hood, this JSON structure is calling to the different SEO helpers (meta, opengraph and twitter). Let's understand:

```
{
  "title": "Generic title",
  "image": "path/to/image.jpg",
  "description": "Generic description",

  "meta": {
    "title": "Default title",
  },
  "opengraph": {
    "image": "path/to/og-image.jpg"
  }
}
```

This structure will allow you to set a base value for the `title` in all the builders plus changing exclusively the title for the *Meta* section. Same with the image, Twitter and OpenGraph will inherit the parent image but OpenGraph will replace its for the one on its builder. This way you will be able to display different information on every section!

This will call [setTitle](https://github.com/ARCANEDEV/SEO-Helper/blob/master/src/Contracts/SeoMeta.php#L127) from the `SeoMeta` helper and [setImage](https://github.com/ARCANEDEV/SEO-Helper/blob/master/src/Contracts/SeoOpenGraph.php#L78) from the `SeoOpenGraph` helper. Same would happen with Twitter. Take some time to review these three contracts in order to know all the methods available:

- [Metas](https://github.com/ARCANEDEV/SEO-Helper/blob/master/src/Contracts/SeoMeta.php)
- [OpenGraph](https://github.com/ARCANEDEV/SEO-Helper/blob/master/src/Contracts/SeoOpenGraph.php)
- [Twitter](https://github.com/ARCANEDEV/SEO-Helper/blob/master/src/Contracts/SeoTwitter.php)

In order to match any of the helper methods, every JSON option will be transformed to `studly_case` prefixed by `set` and `add`, so `title` will be converted to `setTitle` and `google_analytics` to `setGoogleAnalytics`. How cool is that?

All methods are called via `call_user_func_array`, so if an option contains an array, every key will be pased as parameter to the helper method. See `setTitle` or `addWebmaster` which allows multiple parameters.

### Populating SEO Attributes

[](#populating-seo-attributes)

You can specify the SEO attributes for your permalink by just passing an array of data to the `seo` attribute:

```
Peramlink::create([
  'slug' => 'foo',
  'seo' => [
    'title' => 'this is a title',
    'description' => 'this is a description',
    'opengraph' => [
      'title' => 'this is a custom title for og:title'
    ]
  ]
);
```

#### Populating SEO Attributes with Default Content

[](#populating-seo-attributes-with-default-content)

You will usually want to automatically populate your SEO information directly from your bound model information. You can do so by creating fallback methods in you model as shown below:

```
public function getPeramlinkSeoTitleAttribute()
{
  return $this->name;
}

public function getPermalinkSeoOpenGraphTitleAttribute()
{
  return $this->name . ' for OpenGraph';
}
```

This fallbacks will be used if they indeed exist and the value for that field has not been provided when creating the permalink. Note that these methods should be called as an Eloquent accessor. Use the *permalinkSeo* prefix and then the path to the default value in a *StudlyCase*, for example:

```
seo.title                   => getPermalinkSeoTitleAttribute()
seo.description             => getPermalinkSeoDescriptionAttribute()
seo.twitter.title           => getPermalinkSeoTwitterTitleAttribute()
seo.twitter.description     => getPermalinkSeoTwitterDescriptionAttribute()
seo.opengraph.title         => getPermalinkSeoTwitterOpenGraphAttribute()
seo.opengraph.description   => getPermalinkSeoOpenGraphDescriptionAttribute()

```

The package will look for any matching method, so you can create as many methods as your seo set-up may need, even if you are just creating custom meta tags so `getPermalinkMyCustomMetaDescriptionAttribute` would match if there's a `seo.my.custom.meta.description` object.

### SEO Builders

[](#seo-builders)

To provide even more flexibility, the method calls are piped through 3 classes (one for each helper) called [Builders](https://github.com/IsraelOrtuno/permalink/tree/master/src/Builders). These builders are responsible for calling the right method on the [ARCANDEV/SEO-Helper](https://github.com/ARCANEDEV/SEO-Helper) package.

If there is a method in this builders matching any of the JSON options, the package will execute that method instead of the default behaviour, which would be calling the method (if exists) from the *SEO-Helper* package.

Review the [MetaBuilder](https://github.com/IsraelOrtuno/permalink/blob/master/src/Builders/MetaBuilder.php) as example. This builder contains a `setCanonical` method which is basically used as an alias for `setUrl` (just to be more explicit).

#### Extending Builders

[](#extending-builders)

In order to modify the behaviour of any of these builders, you can create your own Builder which should extend the `Devio\Permalink\Contracts\SeoBuilder` interface or inherit the `Devio\Permalink\Builders\Builder` class.

Once you have created your own Builder, just replace the default one in the Container. Add the following to the `register` method of any Service Provider in your application:

```
// Singleton or not, whatever you require
$this->app->singleton("permalink.meta", function ($app) { // meta, opengraph, twitter or base
  return new MyCustomBuilder;

  // Or if you are inheriting the default builder class

  return (new MyCustomBuilder($app->make(SeoHelper::class)));
});
```

If you wish to use other package for generating the SEO meta tags, extending and modifying the builders will do the trick.

### Disabling SEO generation

[](#disabling-seo-generation)

If you wish to prevent the rendering of any of the three Builders (meta, OpenGraph or Twitter), just set its JSON option to false:

```
{
  "meta": { },
  "opengraph": false,
  "twitter": false
}
```

This will disable the execution of the OpenGraph and Twitter builders.

###  Health Score

38

—

LowBetter than 85% of packages

Maintenance20

Infrequent updates — may be unmaintained

Popularity32

Limited adoption so far

Community14

Small or concentrated contributor base

Maturity71

Established project with proven stability

 Bus Factor1

Top contributor holds 99.7% 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 ~66 days

Recently: every ~117 days

Total

15

Last Release

1975d ago

Major Versions

0.6.1 → 1.0.0-alpha.02019-09-07

### Community

Maintainers

![](https://www.gravatar.com/avatar/e40220fc9be76f3a9578c47d54172e37a492e48515dea55ab4197f6509d402a3?d=identicon)[IsraelOrtuno](/maintainers/IsraelOrtuno)

---

Top Contributors

[![IsraelOrtuno](https://avatars.githubusercontent.com/u/1769417?v=4)](https://github.com/IsraelOrtuno "IsraelOrtuno (333 commits)")[![crnkovic](https://avatars.githubusercontent.com/u/6536260?v=4)](https://github.com/crnkovic "crnkovic (1 commits)")

---

Tags

laravelwordpressroutingpermalinkdatabase routingdynamic routes

###  Code Quality

TestsPHPUnit

### Embed Badge

![Health badge](/badges/devio-permalink/health.svg)

```
[![Health](https://phpackages.com/badges/devio-permalink/health.svg)](https://phpackages.com/packages/devio-permalink)
```

###  Alternatives

[laravel/cashier

Laravel Cashier provides an expressive, fluent interface to Stripe's subscription billing services.

2.5k25.9M107](/packages/laravel-cashier)[laravel/pulse

Laravel Pulse is a real-time application performance monitoring tool and dashboard for your Laravel application.

1.7k12.1M99](/packages/laravel-pulse)[laravel/passport

Laravel Passport provides OAuth2 server support to Laravel.

3.4k85.0M532](/packages/laravel-passport)[laravel/scout

Laravel Scout provides a driver based solution to searching your Eloquent models.

1.7k49.4M479](/packages/laravel-scout)[laravel/boost

Laravel Boost accelerates AI-assisted development by providing the essential context and structure that AI needs to generate high-quality, Laravel-specific code.

3.4k10.6M274](/packages/laravel-boost)[roots/acorn

Framework for Roots WordPress projects built with Laravel components.

9682.1M97](/packages/roots-acorn)

PHPackages © 2026

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