Laravel E-Commerce Application Development – Categories Navigation

Laravel E-Commerce Application Development – Categories Navigation

Laravel E-Commerce Application Development ( 25 Lessons )

In this course, you’ll learn how to create an E-Commerce Website from scratch in Laravel. The process has never been easier I’ll take you from the very beginning stages of setting up Laravel till the last steps of adding products to the cart. If you’ve good understanding & experience in PHP & MySQL then this course is for you.

see full series
  1. Laravel E-Commerce Application Development – Introduction
  2. Laravel E-Commerce Application Development – Initial Project Setup
  3. Laravel E-Commerce Application Development – Assets Setup Using Laravel Mix
  4. Laravel E-Commerce Application Development – Admin Model and Migration
  5. Laravel E-Commerce Application Development – Backend Admin Authentication
  6. Laravel E-Commerce Application Development – Base Controller and Repository
  7. Laravel E-Commerce Application Development – Settings Section Part 1
  8. Laravel E-Commerce Application Development – Settings Section Part 2
  9. Laravel E-Commerce Application Development – Categories Section Part 1
  10. Laravel E-Commerce Application Development – Categories Section Part 2
  11. Laravel E-Commerce Application Development – Attributes Section Part 1
  12. Laravel E-Commerce Application Development – Attributes Section Part 2
  13. Laravel E-Commerce Application Development – Attributes Section Part 3
  14. Laravel E-Commerce Application Development – Brands Section
  15. Laravel E-Commerce Application Development – Products Section Part 1
  16. Laravel E-Commerce Application Development – Products Section Part 2
  17. Laravel E-Commerce Application Development – Products Section Part 3
  18. Laravel E-Commerce Application Development – Products Section Part 4
  19. Laravel E-Commerce Application Development – Frontend Login & Registration
  20. Laravel E-Commerce Application Development – Categories Navigation
  21. Laravel E-Commerce Application Development – Catalog Listing
  22. Laravel E-Commerce Application Development – Product Details Page
  23. Laravel E-Commerce Application Development – Shopping Cart
  24. Laravel E-Commerce Application Development – Checkout
  25. Laravel E-Commerce Application Development – Payment Processing

This is part 19 of the Laravel E-Commerce Application Development series. In this part, we will work on Categories Navigation which means we will populate our site navigation with the categories.

I assume you should have the e-commerce application project on your machine or you can grab it from Laravel E-Commerce Application repository, we will start from where we left it in the last part.

Installing Nested Collection Package

As you already know, we have used the parent_id in our categories table, to nest the categories. We can write our own logic to render the nested categories using a recursive PHP function but I opt for using a package called NestedCollection.

So firstly, we will install this package in our application using the Composer. Open the command line terminal and run the below command to install this package.

composer require typicms/nestablecollection

When the installation finishes, you don’t have to do anything as this package will be auto-discovered in your Laravel installation.

Now we need to use this package, so open the app/Models/Category.php class file and add the NestableTrait in our model file.

use TypiCMS\NestableTrait;

Next, instruct your model to use this trait by adding it like.

use TypiCMS\NestableTrait;
use Illuminate\Support\Str;
use Illuminate\Database\Eloquent\Model;

class Category extends Model
{
    use NestableTrait;

    // Remaining content of our model file.
}

Now we are ready to use the nested collection based on our parent_id column.

Updating Parent Category List in Admin Area

Before jumping into the frontend navigation, let’s utilize this package to show nested levels of categories in our admin’s categories section.

Firstly, open the CategoryContract(app/Contracts/CategoryContract.php) file and add the below method signature in it.

/**
 * @return mixed
 */
public function treeList();

Next, we will implement this treeList() method in our CategoryRepository class. Open the CategoryRepository(app/Repositories/CategoryRepository.php) file and add the below method.

/**
 * @return mixed
 */
public function treeList()
{
    return Category::orderByRaw('-name ASC')
        ->get()
        ->nest()
        ->listsFlattened('name');
}

The nest() and listFlattened() methods are provided by the NestedCollection package we installed earlier.

Next, we will use the treeList() method in our Admin\CategoryController instead of listCategories().

Open the category controller (app/Http/Controllers/Admin/CategoryController) and within the create() and edit() method, replace the below line:

$categories = $this->categoryRepository->listCategories('id', 'asc');

To this:

$categories = $this->categoryRepository->treeList();

Next, we will update our views for admin section, because treeList() method return an array instead of a collection.

Open the create.blade.php file from resources/views/admin/categories folder and replace parent category block with the below one.

<div class="form-group">
    <label for="parent">Parent Category <span class="m-l-5 text-danger"> *</span></label>
    <select id=parent class="form-control custom-select mt-15 @error('parent_id') is-invalid @enderror" name="parent_id">
        <option value="0">Select a parent category</option>
        @foreach($categories as $key => $category)
            <option value="{{ $key }}"> {{ $category }} </option>
        @endforeach
    </select>
    @error('parent_id') {{ $message }} @enderror
</div>

Next, open the edit.blade.php file from the same folder and replace the parent category block with the below one.

<div class="form-group">
    <label for="parent">Parent Category <span class="m-l-5 text-danger"> *</span></label>
    <select id=parent class="form-control custom-select mt-15 @error('parent_id') is-invalid @enderror" name="parent_id">
        <option value="0">Select a parent category</option>
        @foreach($categories as $key => $category)
            @if ($targetCategory->parent_id == $key)
                <option value="{{ $key }}" selected> {{ $category }} </option>
            @else
                <option value="{{ $key }}"> {{ $category }} </option>
            @endif
        @endforeach
    </select>
    @error('parent_id') {{ $message }} @enderror
</div>

Now, if you open the categories section in your admin area, you will have the parent category dropdown something like below.

Nested Categories
Nested Categories

Adding Category View Route for Frontend

Let’s start working on the site navigation on the frontend. When we will click on any category it will lead us to a category page, for that we have to create a route. Open the routes/web.php file and add the below route in it.

Route::get('/category/{slug}', 'Site\[email protected]')->name('category.show');

Creating Category Controller for Frontend

Open the command line terminal and run the below command to create a CategoryController for frontend, as category.show route pointing to this controller.

php artisan make:controller Site\CategoryController

Now, open the newly generated controller and replace the whole class with below one.

namespace App\Http\Controllers\Site;

use Illuminate\Http\Request;
use App\Http\Controllers\Controller;
use App\Contracts\CategoryContract;

class CategoryController extends Controller
{
    protected $categoryRepository;

    public function __construct(CategoryContract $categoryRepository)
    {
        $this->categoryRepository = $categoryRepository;
    }

    public function show($slug)
    {
        $category = $this->categoryRepository->findBySlug($slug);

        return view('site.pages.category', compact('category'));
    }
}

In this controller file, we have injected the CategoryContract which will provide us the access to all Category repository functions.

Now, open the CategoryContract and add the below signature in it.

**
 * @param $slug
 * @return mixed
 */
public function findBySlug($slug);

Add the implementation of this method in the CategoryRepository like below.

public function findBySlug($slug)
{
    return Category::with('products')
        ->where('slug', $slug)
        ->where('menu', 1)
        ->first();
}

Next, in our Site\CategoryController we will add the show() method, which will load the the category by slug.

public function show($slug)
{
    $category = $this->categoryRepository->findBySlug($slug);

    dd($category);
    // return view('site.pages.category', compact('category')); we will add this in the next post
}

Now, we have a route which points to a controller and that controller will load the requested category.

Creating View Composer Service Provider

The most efficient way to pass categories to our nav.blade.php partial view is by using the View Composers.

Open the command line terminal and run the below command to generate a service provider.

php artisan make:provider ViewComposerServiceProvider

Now, open this generate provider from app/Providers folder and replace the content with the below one.

namespace App\Providers;

use App\Models\Category;
use Illuminate\Support\Facades\View;
use Illuminate\Support\ServiceProvider;

class ViewComposerServiceProvider extends ServiceProvider
{
    /**
     * Bootstrap services.
     *
     * @return void
     */
    public function boot()
    {
        View::composer('site.partials.nav', function ($view) {
            $view->with('categories', Category::orderByRaw('-name ASC')->get()->nest());
        });
    }
}

As you can see that using the View:: facade, we are binding the site.partials.nav blade file to a callback function which send the $categories variable to nav view.

Adding View Composer Service Provider to Providers Array

Now, quickly open the config/app.php file and register the ViewComposerServiceProvider by adding it to the $providers array.

// ...
App\Providers\ViewComposerServiceProvider::class,

Updating nav.blade.php File for Categories Navigation

In this last, section we will render our categories in our nav.blade.php partials file which we created in the last post. Open the resources/views/site/partials/nav.blade.php file and replace the whole file content with the below one.

<nav class="navbar navbar-expand-lg navbar-dark bg-dark">
    <div class="container">
        <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#main_nav"
                aria-controls="main_nav" aria-expanded="false" aria-label="Toggle navigation">
            <span class="navbar-toggler-icon"></span>
        </button>
        <div class="collapse navbar-collapse" id="main_nav">
            <ul class="navbar-nav">
                @foreach($categories as $cat)
                    @foreach($cat->items as $category)
                        @if ($category->items->count() > 0)
                            <li class="nav-item dropdown">
                                <a class="nav-link dropdown-toggle" href="{{ route('category.show', $category->slug) }}" id="{{ $category->slug }}"
                                   data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">{{ $category->name }}</a>
                                <div class="dropdown-menu" aria-labelledby="{{ $category->slug }}">
                                    @foreach($category->items as $item)
                                        <a class="dropdown-item" href="{{ route('category.show', $item->slug) }}">{{ $item->name }}</a>
                                    @endforeach
                                </div>
                            </li>
                        @else
                            <li class="nav-item">
                                <a class="nav-link" href="{{ route('category.show', $category->slug) }}">{{ $category->name }}</a>
                            </li>
                        @endif
                    @endforeach
                @endforeach
            </ul>
        </div>
    </div>
</nav>

In this view file, we are running a loop on the $categories variable which we are getting using the view composer created in the previous section. If any category has the nested items, we are showing a dropdown if not then simply a link.

Now, if you load your site again, you will get the categories in the navigation bar like below.

Website Navigation with Categories
Website Navigation with Categories

What’s Next

In the next post, we will start working on the category page to show all products under a category.

Code Repository

You can find the code base of this series on Laravel eCommerce Application repository.

If you have any question about this post, please leave a comment in the comment box below.

11 comments on “Laravel E-Commerce Application Development – Categories Navigation

  1. hello sir,

    i have face database migration error when i run migrate command then got bellow error.

    General error: 1005 Can’t create table `Laravel_woo`.`#sql-c18_33c` (errno: 150 “Foreign key constraint is incorrectly formed”) (SQL: alter table `attribute_values` add constraint `attribute_values_attribute_id_foreign` foreign key (`attribute_id`) references `attributes` (`id`))
    Or
    i have got all the project in git but i have got same issue
    please resolve it.
    https://drive.google.com/file/d/112_Vzca6-qEw5KaSl3wkx0g5IkBDruh2/view?usp=sharing

    1. Hallo Mahestana

      I am bit stacked on this chapter .Nothing is displayed on front end page also if i use this code on categorycontroller to create a new category doesn’t work $categories = $this->categoryRepository->treeList(); //using a package showing 500 error code.Are you willing to assist?

  2. aim getting this error please help

    Undefined variable: categories (View: /Users/dasyamchandu/ecommerce/resources/views/site/partials/nav.blade.php)

  3. Hey @LaraShout,
    Can you explain or add an example how would you do chaining/nesting on routing level?

    For example, lets imagine we are building a whiskey & wine liquor store and we want to achieve next:

    example.com/whiskies/irish-whiskey/[/single-malt, /single-pot-still, /grain, /blended…]
    example.com/whiskies/scotch-whiskey/[/single-grain, /blended-malt…]

    and something similar for wine:
    example.com/wines/red-wine/[/pinot-noir, /cabernet, /sauvignon]
    example.com/wines/white-wine/[/chardonnay, /pinot-grigio]

    There are few solutions but I am not sure what is best option For example:
    1. We can break nesting and make for example: Group, Category, Subcategory models etc.
    2. We can merge slugs from categories table, pass it to the router and then parse it in controller to get slugs back.
    3. We can do some chaining/nesting for few levels of nesting.

    What would be best option by your opinion?

Leave a Reply

Your email address will not be published. Required fields are marked *

*When sharing a code snippet please wrap you code with pre tag and add a class code-block to it like below.
<pre class="code-block">you code here</pre>

*
*

This site uses Akismet to reduce spam. Learn how your comment data is processed.