PHPackages                             mriembau/laravel-urlable - 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. [Utility &amp; Helpers](/categories/utility)
4. /
5. mriembau/laravel-urlable

ActiveLibrary[Utility &amp; Helpers](/categories/utility)

mriembau/laravel-urlable
========================

A package to add friendly urls to any Eloquent model.

1.0.0(8mo ago)01MITPHPPHP ^8.2

Since Aug 25Pushed 8mo agoCompare

[ Source](https://github.com/mriembau/laravel-urlable)[ Packagist](https://packagist.org/packages/mriembau/laravel-urlable)[ RSS](/packages/mriembau-laravel-urlable/feed)WikiDiscussions main Synced 1mo ago

READMEChangelogDependencies (9)Versions (2)Used By (0)

Laravel Urlable
===============

[](#laravel-urlable)

A Laravel package to add **SEO-friendly**, **multilingual** URLs to any Eloquent model.

✅ Features
----------

[](#-features)

- Automatic **friendly slugs** for any Eloquent model
- **Multi-language support**
- Optional integration with **[Spatie Laravel Translatable](https://github.com/spatie/laravel-translatable)**
- Automatic **redirects for old slugs**
- **Event system** for custom handling
- **Middleware** to handle redirects
- Full **test coverage** (PHPUnit)

---

📦 Installation
--------------

[](#-installation)

Install the package via Composer:

```
composer require mriembau/laravel-urlable
```

⚙️ Configuration
----------------

[](#️-configuration)

Publish the config and migration files:

```
php artisan vendor:publish --provider="Mriembau\Urlable\Providers\UrlableServiceProvider"
```

This will create:

- config/urlable.php
- A migration for the urls table

Run the migration:

```
php artisan migrate
```

### `config/urlable.php`

[](#configurlablephp)

```
return [
    // List of supported locales for URL generation
    'locales' => ['ca', 'en'],

    // Enable or disable the middleware that handles old slug redirects
    'enable_middleware' => true,

    // If true, the package will automatically register a fallback route
    // to resolve URLs for your models
    'resolve_urls' => true,

    // If true, the default listener will net be registering, and you will
    // be able to add your own listener
    'custom_listener' => false
];
```

🚀 Usage
-------

[](#-usage)

### 1. Add the `HasUrl` trait to your model

[](#1-add-the-hasurl-trait-to-your-model)

```
namespace App\Models;

use Illuminate\Database\Eloquent\Model;
use Mriembau\Urlable\Traits\HasUrl;

class Post extends Model
{
    use HasUrl;

    protected $fillable = ['title'];

    // Optionally, customize URL generation fields
    protected array $urlFields = ['title'];

    // Optional: define supported locales for this model
    public array $urlLocales = ['en', 'ca'];
}
```

When you create or update the model, URLs will be automatically generated for each locale.

### 2. Get the URL for a given locale

[](#2-get-the-url-for-a-given-locale)

```
$post = Post::create(['title' => 'My first article']);

// Get the URL object for the current locale
$url = $post->url();

// Get full URL string (e.g., https://yourapp.com/en/my-first-article)
echo $url->full_url;
```

### 3. Use with Spatie Translatable

[](#3-use-with-spatie-translatable)

If your model uses Spatie's HasTranslations, you can add HasUrlSpatie trait:

```
namespace App\Models;

use Illuminate\Database\Eloquent\Model;
use Spatie\Translatable\HasTranslations;
use Mriembau\Urlable\Traits\HasUrl;
use Mriembau\Urlable\Traits\HasUrlSpatie;

class Post extends Model
{
    use HasTranslations, HasUrl, HasUrlSpatie;

    protected $fillable = ['title'];

    public array $translatable = ['title'];
}

```

This way, the package will automatically use the Spatie Translatable methods for each locale.

### 4. Automatic Redirects for Old Slugs

[](#4-automatic-redirects-for-old-slugs)

If a slug changes, the old one will be **soft deleted** and Laravel's `RedirectIfOldSlug` middleware will handle redirects automatically.

By default, the middleware is registered and ready to use. You can apply it to your routes like this:

```
Route::middleware(['web', 'redirect'])->group(function () {
    // Your routes...
});
```

This ensures that:

- If a user visits an old URL, they are redirected (301) to the current URL.
- If the URL is current, the request continues normally.
- If no URL is found, a 404 is returned.

🔍 Route Fallback for URLs
-------------------------

[](#-route-fallback-for-urls)

🔍 Route Fallback for URLs
-------------------------

[](#-route-fallback-for-urls-1)

The package automatically registers a **fallback route** to resolve URLs dynamically to the correct model.

### How it works:

[](#how-it-works)

1. When a request does **not match any other route**, it hits the fallback route.
2. The `UrlController`:
    - Extracts the locale from the first segment (if it matches a configured locale).
    - Extracts the remaining path as the slug.
    - Looks up the `urls` table for a matching slug and locale.
3. If the URL is found:
    - If the slug is **soft-deleted**, it redirects to the current slug (301 redirect).
    - Otherwise, it fires the **`UrlResolved`** event to handle the response.
4. If no URL is found, it returns a **404 Not Found**.

> Note: No manual route registration is needed. The fallback route is only active if `'resolve_urls' => true` in the package config.

📂 Views
-------

[](#-views)

The package includes a default view for resolved URLs. You can publish it to customize:

```
php artisan vendor:publish --tag=urlable-views
```

After publishing, the view will be located at:

```
resources/views/vendor/urlable/default.blade.php

```

You can edit this view to display your model's content or design a custom layout.

Example default content:

```
{{-- resources/views/vendor/urlable/default.blade.php --}}
{{ $model->title ?? 'Untitled' }}
{{ $model->content ?? '' }}

```

🔔 Events
--------

[](#-events)

The package fires a **`UrlResolved`** event whenever a URL is successfully resolved.

### Default Listener

[](#default-listener)

By default, the package includes a listener `HandleUrlResolved` that will:

- Render the default view (`urlable.default`) if no custom handler is provided.
- Call a model's `urlHandler` property if it exists.

This means out-of-the-box, you don't need to create any listener to get basic functionality.

### 🛠 Custom URL Handler by Model

[](#-custom-url-handler-by-model)

By default, the package uses the `HandleUrlResolved` listener, which renders a generic view.

You can override this behavior for every specific model by adding a $urlHandler property that points to a class with an \_\_invoke method:

**Example:**

```
