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

danielcarr's avatar

How to handle SEO friendly urls

How would you handle a url like {category}/{subject}/{page title}. Would it be compared with three seperate tables or one table or would the parameters be compared in the controller or model with the relationships? How do people handle SEO friendly url's in Laravel?

0 likes
7 replies
adrian_d's avatar

Framework has really nothing to say here. This works everywhere the same way. At first, all your models need to have slugs that will be used inside URLs - there is an awesome package that provides this outside the box - https://github.com/spatie/laravel-sluggable. Secondly, you need to create URLs that take all these slugs as parameters.

For example:

action('PageController@show', [$category->slug, $subject->slug, $page->slug])
danielcarr's avatar

Thank you for your response, but I have slug columns and pass them through as parameters, but how would you then compare these separate tables so the The chain is validated so you would come to the right page at the end of the url?

kahriman's avatar

It would work.


//Route
Route::pattern('categorySlug', '[a-z\-]+');
Route::pattern('subjectSlug', '[a-z\-]+');
Route::pattern('pageSlug', '[a-z\-]+');

Route::get('/{categorySlug}/{subjectSlug}/{pageSlug}', 'PageController@show');

//Controller public function show($categorySlug,$subjectSlug,$pageSlug) { $page = Page::whereSlug($pageSlug) ->whereHas('category', function ($query) use ($categorySlug) { $query->whereSlug($categorySlug); }) ->whereHas('category.subject', function ($query) use ($subjectSlug) { $query->whereSlug($subjectSlug); })->first()

return view('pages.show',compact('page'));

}

//Models

class Page extends Model {

public function category()
{
    return $this->belongsTo('App\Category');
}

}

class Category extends Model {

public function subject()
{
    return $this->belongsTo('App\Subject');
}

}

//View @extends('layout')

@section('title') {{ $page->category->title }} | {{ $page->category->subject->title }} | {{ $page->title }} @endsection

@section('content') {{ $page->title }} @endsection

1 like
bashy's avatar

I would think about using "depth". That way you can check the depth and slug for the levels.

wheeler's avatar

I have approached this by having a helper for more complex routes and then doing a comparison in the controller.

// routes.php
Route::get('designs/{design}-{design_slug}', ['as' => 'design.show', 'uses' => 'DesignController@show']);

// helpers.php
function design_route(App\Design $design)
{
    return route('design.show', [
        'id' => $design->id,
        'design_slug' => $design->slug,
    ]);
}

// DesignController.php
public function show(Request $request, Design $design)
        if ($request->url() != design_route($design)) {
            // test url slug is correct for design
            return redirect(design_route($design), 301);
        }
         
        // proceed...
}
bashy's avatar

Like, with your structure of your DB. Use a depth field to show the depth/level of the item. Just a thought and one that I've used before.

Please or to participate in this conversation.