dmytroshved's avatar

Create a slug based on a unique name without using packages

Hi everyone, at one point during development, I needed to add a slug to a model in an existing project, but I found several potential solutions to this problem on the internet.

  1. Install the package https://github.com/cviebrock/eloquent-sluggable

  2. Do it manually

My question

My model Recipe has name field with ->unique() attribute, so can I generate slug based on that unique name field? For example using Observer for generating and updating slug? Do you see potential issues in that solution?

Would be grateful for your advice

Best regards

0 likes
11 replies
Glukinho's avatar
Level 31

so can I generate slug based on that unique name field? For example using Observer

Yes you can, just put into your model:

protected static function booted(): void
{
    static::creating(function (Recipe $model) {
        $model->slug = Str::slug($model->name);
    });
}

https://laravel.com/docs/12.x/eloquent#events-using-closures

I see only one issue with such slug creating: names can change over time, what should happen with the slug generated from this name? Should it change automatically? Then old URLs with this slug stop working. Should it remain? Then the slug doesn't correspond to new name, which is wrong too.

My suggestion is to keep generated slugs forever. Put slugs into separate table with MorphToMany relation with all models have slugs. These models have trait HasManySlugs which handles all the logic.

When creating model, you put new slug to slugs table. When updating a model which has slugs, if name changed, you don't update old slug but create new one, maybe marking it "default".

Controllers should handle slugs accordingly, retrieving them from slugs table for corresponding models.

With this approach you never lose your old URLs.

1 like
Snapey's avatar

Your recipe names might be unique, but you will have to check that the slug is unique also.

For instance "Fruit Scones" might be different from fruit-scones as far as the database is concerned, but the slug would be the same.

On one of my sites I use the Str slug helper, but I also include the record ID in the url. In fact the slug is only there for SEO purposes and is not used for route model binding.

For example https://speakernet.co.uk/talk/7689/the-amazing-mr-cotton

The slug is decorative, so if the author changes the name of the talk, both the old link and the new link still work. There is no need for the slug to be unique since it is not used in routing, and Im never telling my users, sorry that title is not available.

2 likes
Glukinho's avatar

@Snapey very nice, thank you! In fact, you actually don't have to store your slugs at all, just generate when it needs to be shown.

1 like
PeteBatin's avatar

@Glukinho "nothing to be invalid" is a bad idea. You'll end up with multiple URLs for the same article/page, it will be flagged as duplicate content in search engines and face potential SEO/ranking penalties.

PeteBatin's avatar

@Glukinho personally, I'd take the Wordpress route. Have the slug built upon the page title, show it real time and check the database for uniqueness via ajax. If you're performing any SEO work on the site then you'll want the facility to be able to amend the URL in the future.

Go down the ID/page-title route if you like, but you'll still need to check both, ID calls the record and then if found, check the slug to see if it also is valid.

If the slug isn't valid, 301 redirect to the correct/current slug based on the ID.

By keeping the ID you don't need to keep a history of previous URLs to redirect to the current URL

1 like
Glukinho's avatar

@PeteBatin thanks! Very smart ideas. I like very much the idea of NOT storing slugs history and still being able to redirect to the correct slug. It simplifies a lot of logic.

1 like
Snapey's avatar

@PeteBatin You never have multiple slugs. You have one slug, then at some point it changes to a new one. This is no different to most systems that allow the author to change the title. In actual fact, the author very rarely changes the title and if they do, nothing breaks.

@ghabe the route has the slug as optional, and although it is passed to the controller, it is ignored. Route model binding works on the id as usual.

PeteBatin's avatar

@Snapey I'm not suggesting you do have multiple slugs? And by that I guess you mean records of historical slugs? Either way, I didn't suggest that. You sure you meant to reply to me? Reply seems a little OT for what I contributed/suggested.

JakeMiller's avatar

Yes, you can generate the slug using an observer from the unique name field. Just make sure to check slug uniqueness too, as two different names might result in the same slug. If name changes are expected, it’s better to store slugs in a separate table or include the ID in the URL to avoid broken links. This keeps SEO and routing consistent.

1 like

Please or to participate in this conversation.