If you work with project or blog where records require so-called slug (posts, pages etc.), it’s convenient to generate slug immediately after title has been typed in. This article will show you how to do it in Laravel, with AJAX and with a help of one Laravel package.
First, what we’re doing here. This is the example:

We have a form to add a page, and our goal is to have Slug field auto-generated, as we finish typing in the Title.
Not only that, slug should be unique for every post, even if title is the same.
Step 1. Blade Create Form
I will show you, how resources/views/admin/pages/create.blade.php looks like. To be exact, the part responsible for those two fields – title and slug:
<div class="form-group">
<label for="title">Title*</label>
<input type="text" id="title" name="title" class="form-control">
</div>
<div class="form-group">
<label for="slug">Slug*</label>
<input type="text" id="slug" name="slug" class="form-control">
</div>
Notice: this form code has been generated by our QuickAdminPanel, you should check it out.
So, the code is simple, nothing to comment here. Now, let’s add some JavaScript, that is fired when title value is changed.
Step 2. AJAX Call On Title Change
In the “main” Blade layout file, I have a special @yield(‘scripts’) code that allows to add any JavaScript to any other Blade template. So, that’s exactly what we will do – add this code to the bottom of our pages/create.blade.php:
@section('scripts')
<script>
$('#title').change(function(e) {
$.get('{{ route('pages.check_slug') }}',
{ 'title': $(this).val() },
function( data ) {
$('#slug').val(data.slug);
}
);
});
</script>
@endsection
Now, we need to create the logic behind pages.check_slug route.
Step 3. Route/Controller to Return Slug
First, in routes/web.php we add this line:
Route::get('pages/check_slug', 'PagesController@check_slug')
->name('pages.check_slug');
Next, we create app/Http/Controllers/PagesController method check_slug(). We’ll start from a simple version using Laravel’s str_slug() helper.
public function check_slug(Request $request)
{
$slug = str_slug($request->title);
return response()->json(['slug' => $slug]);
}
Simple, right? We make a slug and return it. That could be the end of our tutorial, but we forgot one important rule – slugs should be unique. How to check it?
Step 4. Making Slug Unique
Not only that, we need to not only check uniqueness, but also automatically add -1, -2, -3 and other numbers to the end of the slug, to generate a new unique one.
For that, I’ve decided to not reinvent the wheel and to use an existing package cviebrock/eloquent-sluggable. It’s not the only slug-related package on the market, but it has a very useful (in our case) feature of generating slug without saving it to the database.
We install the package with this command:
composer require cviebrock/eloquent-sluggable
Next, we need to prepare our Model app/Page.php to make it “sluggable”:
use Cviebrock\EloquentSluggable\Sluggable;
class Page extends Model
{
use Sluggable;
/**
* Return the sluggable configuration array for this model.
*
* @return array
*/
public function sluggable()
{
return [
'slug' => [
'source' => 'title'
]
];
}
}
We’ve created a method that defines to generate slug field from title field of pages database table.
And now, final step, we can replace old “simple” method of generating slug in PagesController:
use Cviebrock\EloquentSluggable\Services\SlugService;
public function check_slug(Request $request)
{
// Old version: without uniqueness
$slug = str_slug($request->title);
// New version: to generate unique slugs
$slug = SlugService::createSlug(Page::class, 'slug', $request->title);
return response()->json(['slug' => $slug]);
}
And, that’s it!
P.S. Oh, and don’t forget to still check uniqueness on back-end validation when doing store() for the page, add rule ‘slug’ => unique:pages in validation. You never know if someone else is using the system and creates the same page at the same time from another computer 🙂
Awesome blog post, just what I needed for my Blog CMS that I’m building. Seems quite simple to get a slug field added to the application.
I personally use Laravel-sluggable by #Spatie https://github.com/spatie/laravel-sluggable it’s very easy and no need do it manually,,,,,,,,,,check it
Yes, but Spatie package (at least in the docs) doesn’t have the feature to “check” the slug and show it, without saving it it to the database. That’s why I’ve chosen that other package.
Sometimes it does make a huge sense to have manual slug field, for SEO purposes. So, in this article, it’s a mix of auto-generating slug and possibility to change it manually.
One other thing to consider when setting up slugs is the question of redirects:
* When slugs are changed, how will you ensure that users who visit the old URL are redirected to the correct URL? Presumably you don’t want to be manually setting up 301 redirects.
There are two general options:
// ***** Keep a DB Table of Redirects ***** //
Keep a database table of slugs:
* Fields something like id, post_id, slug, redirect_to_slug_id
* If redirect_to_slug_id is not null, follow IDs until you find the live URL
Wordpress uses a system like this.
// ***** Put an ID Into the URL; Slug is Purely Cosmetic ***** //
For this approach, include an ID in the URL, then have that be what is passed to the route the find the post. Then, generate the slugs *after* finding the post.
This is similar to what StackExchange does. For example, both of these go to the same place. The route uses the post ID part of the URL and the slug is generated on the fly:
https://meta.stackexchange.com/questions/155878/
https://meta.stackexchange.com/questions/155878/some-fake-url
https://meta.stackexchange.com/questions/155878/stackoverflow-url-format
Good catch “August R. Garcia”!
For those looking for how WordPress handle it, here are some key references:
Search for `wp_old_slug_redirect`, `wp_check_for_changed_slugs` functions, in the Codex.
They are used into core, here: https://github.com/WordPress/WordPress/blob/master/wp-includes/default-filters.php#L390.
Some additional info: https://wordpress.stackexchange.com/questions/33361/does-wordpress-keep-track-of-a-posts-url-history-and-provide-automatic-redirect
GET http://localhost:8000/admin/catagory/check_slug?title=fd 500 (Internal Server Error)
I am getting this error what can i do?
Check storage/logs/laravel.log for the actual error
Awesome blog post, Great job, thanks you man
What are we putting in the check_slug page? Can’t see that anywhere and is why my app is throwing an error
whats in the check_slug post. i tried it but i am getting no response
please i need help….