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

vlados's avatar

SEO Friendly URLs

I want to build SEO friendly URLs for ecommerce website and until now I was using https://github.com/spatie/laravel-sluggable but I want to take it even further.

I want to have this structure:

  • site.com/category1 -> CategoryController::show()
  • site.com/category1/subcategory1 -> CategoryController::show()
  • site.com/category1/product1 -> ProductController::show()
  • site.com/category1/subcategory1/product2 -> ProductController::show()

One way it will be to have something like:

/**
 * First we check if it is category
 */
Route::get('{categories}', function ($categories) {
    $categories = explode('/', $categories);
    $current_category_slug = array_pop($categories);
    if($current_category = Category::where("slug",$current_category_slug)->first()) {
        return 'category view';
    }
})->where('categories', '^[a-zA-Z0-9-_\/]+$');
/**
 * Else if it is a product
 */
Route::get('{categories}', function ($categories) {
    $categories = explode('/', $categories);
    $current_product_slug = array_pop($categories);
    if($current_category = Pruduct::where("slug",$current_product_slug)->first()) {
        return 'product view';
    }
})->where('categories', '^[a-zA-Z0-9-_\/]+$');

Better way

I think a better way will be to store all the possible urls in the database and cache them with redis. Also in the database I will store the controller and action I found one old package - https://github.com/dmcdenissen/urlalias

Does anyone have better suggestion or maintained package?

0 likes
10 replies
vlados's avatar

@jlrdw SEO urls means urls made for better SEO optimization

Snapey's avatar

consider the routing problems

You can have

Route:::get('{category}'.... and route this to the show method of the category controller

and then

Route::get('{category}/{subcategory}',.... You can tell in the controller if one or both fields are populated

but then

Route::get({category}/{product}', cannot work because there is no way to differentiate between product and subcategory. So for this form, you need to introduce a parameter to differentiate the route,

Route::get('{category}/product/{product},... then this can be directed to the product controller. It would need to be above the category routes so that 'product' is not mistaken for a category name

You can also add

Route::get('{category}/{subcategory}/product/{product}',.... for products in sub category

I can't see any reason to create all the routes ahead of time.

1 like
vlados's avatar

@Snapey So I want to achieve the same result ... The question was how to make it. I understand that there is other ways ... Also the example is working - I can have multiple handlers of the same url

Luxorus's avatar

I usually generate slugs using Laravel’s Str::slug helper and save them along with the title in the database. Then I fetch records by slug in my routes and controllers.

Snapey's avatar

I use IDs and slugs in the URL. Only the ID is used for routing and the slug is used for SEO

eg https://speakernet.co.uk/talk/4662/an-introduction-to-dalton-moor-farm

The slug has been indexed by google and comes up on page 1

No special handling is needed and routing to the talk controller is clean.

SEO is not impacted if the owner changes the title since the URL is not dependent on the slug.

Please or to participate in this conversation.