Show All Posts Associated With a Category in Laravel

Ep#25@Laracasts: Show All Posts Associated With a Category

This post is a part of the Week X of 100DaysOfCode Laravel Challenge series.

In the previous episode we established our first Eloquent relationship between our Post and Category models. We showed the associated category name under each post title on our blog listing page. Now it is time to click that category name and the load all the posts associated with that category i.e. filter posts by that category.

So, we add a new route to our web.php route file

Route::get('/categories/{category}', function (Category $category) {
    return view('posts', [
        'posts' => $category->posts
    ]);
});

From our Route-Model binding episode, we remember that the wildcard name and the callback variable name (category in this example) must match up. From the callback function we return the posts for that particular category $category->posts. So, let's add the relation to the Category model as we did for the Post model in the previous episode.

public function posts() {
    return $this->hasMany(Post::class);
}

This time we used the hasMany() relation as a category may have many posts.

Now that we added the posts() relation to our category model, let's play with it in the tinker. Boot up tinker php artisan tinker

use App\Models\Category;

$c = Category::first();
$c->posts;

The last command will return the posts associated to the first category.

>>> $c->posts;
=> Illuminate\Database\Eloquent\Collection {#4444
     all: [
       App\Models\Post {#4496
         id: 1,
         category_id: 1,
         title: "Just a personal post",
         slug: "just-a-personal-post",
         excerpt: "Lorem ipsum is...",
         body: "Lorem ipsum is simply a dummy...",
         published_at: null,
         created_at: "2021-12-15 16:51:59",
         updated_at: "2021-12-15 16:51:59",
       },
     ],
   }
>>>
>>>

Now let's update our views so that clicking a category name loads a page listing all the posts of that category only. In the Blade templates, update the category hyperlink to /categories/{{ $post->category->id }}, we later update it to slug.

<p><a href="/categories/{{ $post->category->id}}">{{ $post->category->title }}</a></p>

Now from the blog listing page click on a category link. It will load a page like this

In the URL you can see the id of the category. That is because Laravel by default will look for the id attribute of the model bound to the route. Let's change it to the slug attribute by mentioning slug in the wildcard as {category:slug}.

Route::get('/categories/{category:slug}', function (Category $category) {
    return view('posts', [
        'posts' => $category->posts
    ]);
});

And update the views to have the slug instead of id in the hyperlink.

<p><a href="/categories/{{ $post->category->slug}}">{{ $post->category->title }}</a></p>

To see the full changelog of this episode added to the Blog Project, see the GitHub commit Ep#25 Show All Posts Associated With a Category
.

39