I spend many hours for researching, googing, testing to achive this and this is the most simpy way and clean way!
You will achive this:
www.example/ <-- Home
www.example/category/post
www.example/category/sub-category/post
www.example/category/sub-category/sub-cat/sub-sub-sub-cat/post
Before start:
- Database column (slug) must be unique
- You must write full path in database to avoid cinficts
Example:
You write post about BMW tyres:
www.example.com/bmw/tyres/10-is-the-best-tyre-for-bmw-320d
So in DB slug column you save value like this:
bmw/tyres/10-is-the-best-tyre-for-bmw-320d
Steps how i slove this
First make route
Route::get('/{categories?}', [WebSiteController::class, 'index'])->where('categories', '^[a-zA-Z0-9-_\/]+$')->name('slug');
Here take care to provide ? on param. If you miss this you can't route homepage. Category will be required!
Second
Create controller method
public function index($categories = null)
{
// get categories in array
$cats = explode('/', $categories);
// make array to string used for slug
$cat_slug = implode('/', $cats);
// remove last url param. Used when you route only category without post
$post = array_pop($cats);
// Its simple alias (name convention)
$post_slug = $cat_slug;
// No url params provided? Show home page
if(!$categories) {
return view('website.homepage');
}
// Category param exist
else if($categories) {
// Get category based on url slug
$category = PostCategory::where('slug', $cat_slug)->with('childrens')->first();
// Here we must determine if category or post. If category not found we load post.
// Category does not exist! Load post
if(!$category) {
$post = Post::where('slug', $post_slug)->first();
return view('testing.post', compact('post'));
}
// Category founded load it and their childs
else {
$posts = Post::where('post_category_id', $category->id)->get();
return view('testing.category', compact('category', 'posts'));
}
}
// Nothing founded! Show 404
else {
abort('404');
}
}
Category Blade
@extends('layouts.web')
@section('title', $category->name)
@section('content')
<h1>{{ $category->name }}</h1>
<ul class="list-inline">
@foreach($category->childrens as $child)
<li><a href="{{ url($child->slug)}}">{{$child->name}}</a></li>
@endforeach
</ul>
@if($posts->count() > 0)
<hr>
<ul>
@foreach($posts as $post)
<li><a href="{{ url($post->slug)}}">{{$post->title}}</a></li>
@endforeach
</ul>
@endif
@endsection
Post Blade
@extends('layouts.web')
@section('title', $post->title)
@section('content')
<h1>{{ $post->title }}</h1>
@endsection
Whit this you cant make mistake. Dont waste hours like me! I just provide simple example you can now have new idea!
->where('categories','^[a-zA-Z0-9-_\/]+$');
to route to make it to work – Cookhouse