Skip to content
Home » Laravel » Laravel – Create SEO friendly URLs with slugs easily!

Laravel – Create SEO friendly URLs with slugs easily!

Recently, I discovered Laravel, a framework that should be considered of public utility because of its flexibility, ease of learning, ease of use and an undeniable asset, its very large community.

I took advantage of the redesign of my library management tool to get started and I can tell you that I was not disappointed. So I decided to share with you a few points, which I find interesting and useful during the development of my project.

So I needed to create SEO Friendly URLs thanks to slugs, like the ones you can find by default on WordPress. By default, the URLs of your Laravels templates are only made of your template IDs (except the endpoints used by default: edit, create, etc.).

For the show function of my Book controller, I wanted to have a URL consisting of the ID of my book and a slug automatically generated from the title. Here is what you want to get :

For this article, I will start from my example, that is to say a Book class composed of an id and a title attribute. To make it simple, the slug will be a “slugified” version of the title of my book.

Creating the slug

As a first step, we will create the slug attribute for our book as follows:

[pastacode lang=”php” manual=”%3C%3Fphp%0A%0Ause%20Illuminate%5CDatabase%5CEloquent%5CModel%3B%0A%0Aclass%20Book%20extends%20Model%0A%7B%0A%20%20%20%20public%20function%20getSlugAttribute()%3A%20string%0A%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20return%20str_slug(%24this-%3Etitle)%3B%0A%20%20%20%20%7D%0A%7D” message=”” highlight=”” provider=”manual”/]

Routing management

In your route file, web.php, the URL format we want looks like this:

[pastacode lang=”php” manual=”Route%3A%3Aget(‘%2Fbook%2F%7Bid%7D%2F%7Bslug%3F%7D’%2C%20’BookController%40show’)-%3Ename(‘’)%3B” message=”” highlight=”” provider=”manual”/]

To simplify our lives, I make the slug parameter not mandatory in my route. At first, I won’t use it in my controller.

Controller Management

In the BookController, nothing really changes. We only take the ID into account, as before the slug was set up.

[pastacode lang=”php” manual=”%3C%3Fphp%0A%0Ause%20App%5CModels%5CBook%3B%0A%0Aclass%20BookController%0A%7B%0A%20%20%20%20public%20function%20show(%24id)%0A%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20return%20view(‘’)%0A%20%20%20%20%20%20%20%20%20%20%20%20-%3EwithBook(Book%3A%3AfindOrFail(%24id))%3B%0A%20%20%20%20%7D%0A%7D%0A” message=”” highlight=”” provider=”manual”/]

Using your SEO Friendly URL

Now, in your Blade templates, you can generate a SEO Friendly URL to access the view of your Book object.

[pastacode lang=”php” manual=”%7B%7B%20route(‘’%2C%5B%24book-%3Eid%2C%20%24book-%3Eslug%5D)%7D%7D” message=”” highlight=”” provider=”manual”/]

To go beyond

If you don’t want to leave it at that, I offer you some additional code snippets 😉

Generate a URL attribute for your Object

It can be useful to have, directly in your object, a url attribute containing the complete and already generated URL leading to the object view.

[pastacode lang=”php” manual=”%3C%3Fphp%0A%0Aclass%20Book%20extends%20Model%0A%7B%0A%20%20%20%20%2F%2F%20…%0A%0A%20%20%20%20public%20function%20getUrlAttribute()%3A%20string%0A%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20return%20action(‘BookController%40show’%2C%20%5B%24this-%3Eid%2C%20%24this-%3Eslug%5D)%3B%0A%20%20%20%20%7D%0A%09%0A%09%2F%2F%20…%0A%7D” message=”” highlight=”” provider=”manual”/]

You can now use the $book->url attribute in your Blade views or directly in your project’s PHP.

Avoid duplicate content

With the creation of slugs for your object, you may have several URLs for the same entity. Either because you still have links without slugs running on your site, or a poorly formed slug. To solve this problem, I propose two solutions, either automatically redirecting to the right page if the slug is not the right one, or by setting up a canonical tag.

Automatic redirection

To automatically redirect a bad URL, I suggest you check if the slug given in the URL corresponds to the slug generated by our attribute added above. If the slug does not match, we automatically redirect to the right URL.

To automatically redirect a bad URL, I suggest you check if the slug given in the URL corresponds to the slug generated by our attribute added above. If the slug does not match, we automatically redirect to the right URL.

Generating a canonical meta

Some don’t like redirections and would prefer a gentler solution, via the installation of a canonical beacon.

As a reminder, this is what a canonical meta is

A Canonical Tag is used to indicate to search engines such as Google or Bing the fact that a web page is duplicated and includes the content of another document. This tag then contains the address of the original page, called canonical.

Let’s go to the code. First, you need to add a canonical tag (only if it exists) in your layout file, by default : app.blade.php

[pastacode lang=”markup” manual=”…%0A%20%20%3Chead%3E%0A%20%20%20%20%40if(isset(%24canonical))%0A%20%20%20%20%3Clink%20rel%3D%22canonical%22%20href%3D%22%7B%7B%20%24canonical%20%7D%7D%22%20%2F%3E%0A%20%20%20%20%40endif%0A%20%20%3C%2Fhead%3E%0A…%0A” message=”” highlight=”” provider=”manual”/]

In your controller, it is now necessary to add the passage of the canonical beacon to the view, like this

[pastacode lang=”php” manual=”%3C%3Fphp%0A%0Ause%20App%5CModels%5CBook%3B%0A%0Aclass%20BookController%0A%7B%0A%20%20%20%20%2F%2F%20…%0A%20%20%20%20public%20function%20show(%24id%2C%20%24slug%20%3D%20”)%0A%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20%24book%20%3D%20Book%3A%3AfindOrFail(%24id)%3B%0A%0A%20%20%20%20%20%20%20%20return%20view(‘’)%0A%20%20%20%20%20%20%20%20%20%20%20%20-%3EwithBook(%24book)%0A%20%20%20%20%20%20%20%20%20%20%20%20-%3EwithCanonical(%24book-%3Eurl)%3B%0A%20%20%20%20%7D%0A%20%20%20%20%2F%2F%20…” message=”” highlight=”” provider=”manual”/]

That’s it, you now have a page accessible from a clearly more readable URL and more SEO Friendly for your Laravel models. Don’t hesitate if you have any suggestions or corrections, I’m interested 😉

Featured image : lmonk72 / Pixabay