> ## Documentation Index
> Fetch the complete documentation index at: https://docs.lunarphp.com/llms.txt
> Use this file to discover all available pages before exploring further.

# URLs

> Create SEO-friendly slugs for products, collections, brands, and custom models.

URLs provide SEO-friendly slugs for models such as products, collections, and brands.

## Overview

URLs provide SEO-friendly slugs for models such as products, collections, and brands. Instead of exposing database IDs in storefront routes:

```
/products/1
```

A URL slug allows routes like:

```
/products/apple-iphone
```

URLs are polymorphic, so any Eloquent model can support them. Each URL belongs to a language, and each model can have one default URL per language.

<Info>
  URLs are not to be confused with Laravel routes. They provide a slug-based lookup mechanism for storefront routing, not route definitions.
</Info>

## Model

```php theme={null}
Lunar\Models\Url
```

### Fields

| Field | Type | Description |
| :- | :- | :- |
| `id` | `bigIncrements` | Primary key |
| `language_id` | `foreignId` | The language this URL belongs to |
| `element_type` | `string` | Morph type of the parent model |
| `element_id` | `unsignedBigInteger` | Morph ID of the parent model |
| `slug` | `string` | The URL slug |
| `default` | `boolean` | Whether this is the default URL for this element and language combination |
| `created_at` | `timestamp` | |
| `updated_at` | `timestamp` | |

### Relationships

| Relationship | Type | Related Model | Description |
| :- | :- | :- | :- |
| `element` | MorphTo | Polymorphic | The parent model (e.g. Product, Collection, Brand) |
| `language` | BelongsTo | `Lunar\Models\Language` | The language this URL is for |

### Scopes

| Scope | Description |
| :- | :- |
| `default()` | Filter to URLs where `default` is `true` |

## Creating a URL

URLs can be created directly or through a model's `urls()` relationship.

```php theme={null}
use Lunar\Models\Url;

Url::create([
    'slug' => 'apple-iphone',
    'language_id' => $language->id,
    'element_type' => $product->getMorphClass(),
    'element_id' => $product->id,
    'default' => true,
]);

// Or through the relationship
$product->urls()->create([
    'slug' => 'apple-iphone',
    'language_id' => $language->id,
    'default' => true,
]);
```

### Default URL behavior

Only one URL can be the default per element and language combination. When a new URL is created or updated with `default` set to `true`, any existing default URL for that same element and language is automatically set to `false`.

```php theme={null}
$urlA = $product->urls()->create([
    'slug' => 'apple-iphone',
    'language_id' => 1,
    'default' => true,
]);

$urlA->default; // true

$urlB = $product->urls()->create([
    'slug' => 'apple-iphone-16',
    'language_id' => 1,
    'default' => true,
]);

$urlA->refresh()->default; // false
$urlB->default; // true
```

This behavior is scoped to each language independently. Setting a default for one language does not affect defaults in another language.

```php theme={null}
// This URL is for a different language, so $urlB remains the default for language 1
$urlC = $product->urls()->create([
    'slug' => 'apple-iphone-fr',
    'language_id' => 2,
    'default' => true,
]);

$urlB->refresh()->default; // true (still default for language 1)
$urlC->default; // true (default for language 2)
```

## Deleting a URL

When a default URL is deleted, Lunar automatically promotes another URL for the same element and language to become the new default.

```php theme={null}
$urlA = $product->urls()->create([
    'slug' => 'apple-iphone',
    'language_id' => 1,
    'default' => true,
]);

$urlB = $product->urls()->create([
    'slug' => 'apple-iphone-16',
    'language_id' => 1,
    'default' => false,
]);

$urlA->delete();

$urlB->refresh()->default; // true
```

## Adding URL support to models

Lunar ships with URL support on the following models:

* `Lunar\Models\Product`
* `Lunar\Models\Collection`
* `Lunar\Models\Brand`

To add URL support to a custom model, use the `HasUrls` trait:

```php theme={null}
<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Model;
use Lunar\Base\Traits\HasUrls;

class MyModel extends Model
{
    use HasUrls;
}
```

### Available relationships

The `HasUrls` trait provides the following relationships:

```php theme={null}
// All URLs for the model
$model->urls;

// The default URL (where default is true)
$model->defaultUrl;

// The URL for the application's current locale
$model->localeUrl;

// The URL for a specific locale (matches against the language code)
$model->localeUrl('fr')->first();
```

<Info>
  When a model using the `HasUrls` trait is deleted (hard delete only), all associated URLs are automatically removed.
</Info>

## Automatic URL generation

Lunar can automatically generate a URL when a model with the `HasUrls` trait is created. This is controlled by the `generator` option in `config/lunar/urls.php`.

```php theme={null}
<?php

use Lunar\Generators\UrlGenerator;

return [
    'required' => true,
    'generator' => UrlGenerator::class,
];
```

| Option | Type | Default | Description |
| :- | :- | :- | :- |
| `required` | `bool` | `true` | Whether URLs are required when creating or editing models in the admin panel. Has no effect if a generator is configured. |
| `generator` | `string\|null` | `UrlGenerator::class` | The class responsible for generating URLs on model creation. Set to `null` to disable automatic generation. |

### Default generator behavior

The built-in `Lunar\Generators\UrlGenerator` performs the following steps when a model is created:

1. Checks whether the model already has any URLs (skips generation if it does).
2. Reads the model's `name` column, falling back to the `name` attribute (via `attr('name')`).
3. Converts the name to a slug using `Str::slug()`.
4. Ensures uniqueness by appending a numeric suffix if the slug already exists (e.g. `test-product`, `test-product-2`, `test-product-3`).
5. Creates the URL as the default for the system's default language.

### Custom generator

To customize URL generation, create a class with a `handle` method that accepts an Eloquent model:

```php theme={null}
<?php

namespace App\Generators;

use Illuminate\Database\Eloquent\Model;

class CustomUrlGenerator
{
    public function handle(Model $model)
    {
        // Custom URL generation logic
    }
}
```

Then reference it in the config:

```php theme={null}
// config/lunar/urls.php
return [
    'required' => true,
    'generator' => \App\Generators\CustomUrlGenerator::class,
];
```

To disable automatic generation entirely, set the generator to `null`:

```php theme={null}
return [
    'required' => true,
    'generator' => null,
];
```


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.