Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

HB_BHF's avatar

How to create URL slugs in Laravel

Right now I have a routes with an ID as a wildcard.

Route::get('detailPage/{id}', 'DetailPageController@index');

How can I create URLs with slugs (i.e. like on stackoverflow)? I have a table of campaigns with ID and product name. How can I use this product name? So, instead of

myapp.com/detailPage/12345

I have this -

myapp.com/detailPage/Microsoft-Xbox-360

Of course, 12345 is an ID of Microsoft Xbox 360...

0 likes
20 replies
topvillas's avatar

If you're using form model binding then change the key name in your model ..

public function getRouteKeyName()
{
    return 'slug';
}
5 likes
HB_BHF's avatar

But how can I create slugs? Should I create another column in my table? I know there is a helper function str_slug($title, $separator);, but I don't know how to use it in this case...

Spec's avatar

Yes, I would add a column with the stored slug name. Something like this (not tested):

Route::get('detailPage/{slug}', function($slug){
    $result =   DB::table('campains')->where('slug', $slug)->get(); 
    // .... call controller etc...
});
1 like
topvillas's avatar

Yeah, you'd need a (preferably indexed) slug column. You can use the str_slug function when saving your model.

HB_BHF's avatar

So, I should loop through my table and create slug for each item? How can I set this action to be done automatically. So when I insert new record, its slug is created as well...

martinbean's avatar

@HB_BHF Generate the slug when saving your model:

class Item extends Model
{
    public static function boot()
    {
        parent::boot();

        static::saving(function ($model) {
            $model->slug = str_slug($model->name);
        });
    }
}

If you want to use route–model binding, then you’ll need to tell Eloquent the column to use should be your slug column instead:

public function getRouteKeyName()
{
    return 'slug';
}

Now, when you request a URL like items/xbox-360, it’ll instead look for a model with a slug of xbox-360 instead of a primary key.

5 likes
guc43's avatar

Important note: the str_slug function will not check if the slug is already taken. To make your slug unique you could add the id at the end of the slug-string

nanpaul68's avatar

This work for me and you can try it out:

// Store Method
public function store(Request $request) {
    $game->title = $request->title;
    $str = strtolower($request->title);
    $game->slug = preg_replace('/\s+/', '-', $str);
    $game->save();
}
// Show Method
public function show($slug){
    $game = Game::where('slug', $slug)->first();
    return view('game.show')->with('game', $game);
}
// Route
Route::get('/detailPage/{slug}', 'GameController@show')->name('show_game');
4 likes
HB_BHF's avatar

Actually, I'm having a problem because in Campaigns table I have a product_id as a foreign key from Products table.

Campaigns: |id| |product_id| |slug| -> I need to create here this column?

Products: |id| |product_name|

How can I create this |slug| column out of Products?

nanpaul68's avatar

Check my solution above. The slug is generated from my title field coming from the request. Why not have the slug column on the products table.

HB_BHF's avatar

@nanpaul68 because I search items through campaigns table. Also it is one-to-many relationship..

guc43's avatar

@HB_BHF can you show us the the code which saves the Campaigns? Because you have the product_id you should have access to the Product itself. Than you can take the product_name and create a slug.

Please be aware that a product has many Campaigns, and so many campaigns will get the same slug. Maybe you should think about the structure of you project.

HB_BHF's avatar

@guc43 I don't have the code which saves the Campaigns. I got two tables as final product.

guc43's avatar

@HB_BHF I don't get it. How do you save your Campaigns in your table? I think you have to show us some more, if you want some help.

Snapey's avatar

if campaign has many products then you will need a slug column in the campaign as well as on the product? Think FIRST how you want users to access campaigns and products. you will then know what slugs you need

flashadvocate's avatar

I solved this fairly easily.

Update your route to include an optional parameter (so it works regardless):

Route::get('{member}-{slug?}', 'MemberController@show')->name('member');

On your model, add a method that handles the composition of the url parameters:

...
    public function getUrlParams()
    {
        return [
            $this->clan_id, // member
            $this->rank->abbreviation . '-' . $this->name // slug
        ];
    }
...

Now when you reference your route, use the model method to provide the parameters:

route('member', $member->getUrlParams());

Note that I opted for the "id-slug" format to avoid route collisions with other routes.

m33bo's avatar

I am not sure if this is relevant but the way I handled slugs was first to have a slug in my DB table. Then in the route:

Route::get('{slug}', 'PageController@getSlug')->where('slug', '[A-Za-z0-9_\-]+');

and in the controller:

public function getSlug($slug)
    {
        $page = Page::where('slug', $slug)->firstOrFail();
        return $page;
    }

Hope this helps.

2 likes

Please or to participate in this conversation.