Laravel : create hierarchical route for category
Asked Answered
C

3

6

I'm implementing category structure , some products would have one level category but other may have two or more level :

/posts/cat2/post-sulg

/posts/cat-1/sub-1/post-slug

/posts/cat-3/sub../../../post-slug

as i dont know how depth it would be and using category slugs is only for seo (i find post only by its slug) what is the best way to create a route to handle this structure?

Cookhouse answered 21/11, 2016 at 9:39 Comment(0)
H
13

You can solve this with:

Route::get('posts/{categories}', 'PostController@categories')
    ->where('categories','^[a-zA-Z0-9-_\/]+$');

And then in controller

class PostController
{
    public function categories($categories)
    {
        $categories = explode('/', $categories);
        $postSlug = array_pop($categories)

        // here you can manage the categories in $categories array and slug of the post in $postSlug
        (...)
    }

}
Hollister answered 21/11, 2016 at 9:54 Comment(2)
thanks but you should add ->where('categories','^[a-zA-Z0-9-_\/]+$'); to route to make it to workCookhouse
According to ^[a-zA-Z0-9-_\/]+$, --_/////----/-__// is a valid route (proof).Rudyrudyard
D
1

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:

  1. Database column (slug) must be unique
  2. 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!

Debbradebby answered 12/1, 2023 at 0:43 Comment(0)
A
0

I did something similar, this in PostController.php using

public function slug($slug) { return $this->show(Post::where('slug', @end(explode('/', $slug)))->firstOrFail()); }

In routes/web.php

Route::get ('posts/{slug}', 'PostController@slug')->name('post.slug')->where(['slug' => '^(?!((.*/edit$)|(create$))).*\D+.*$']);
Route::resource('posts', 'PostController');

If you want to use the full category list as the slug, just change the slug function:

public function slug($slug) { return $this->show(Post::where('slug', $slug)->firstOrFail()); }
Airbrush answered 20/2, 2020 at 8:18 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.