Laravel 8 E-Commerce - Making Shop Page Products Dynamic

In this video, we will learn about making the products on the shop page dynamic.

Let's see how we can achieve this. First, we need to create a product and product category model and migration.

For that, go to the command prompt and run the following command:


php artisan make:model Category –m

php artisan make:model Product –m

Now, switch to the project and go to the database directory, then migrations. Open the create_category_table migration file and add the following code:


public function up()
{
Schema::create('categories', function (Blueprint $table) {
$table->id();
$table->string('name')->unique();
$table->string('slug')->unique();
$table->timestamps();
});
}

Next, open the app\Models\Category.php model file and add the following code:


class Category extends Model
{
use HasFactory;

protected $table = "categories";
}

Now, open the create_product_table migration file and add the following code:


public function up()
{
Schema::create('products', function (Blueprint $table) {
$table->id();
$table->string('name');
$table->string('slug')->unique();
$table->string('short_description')->nullable();
$table->text('description');
$table->decimal('regular_price');
$table->decimal('sale_price')->nullable();
$table->string('SKU');
$table->enum('stock_status',['instock','outofstock']);
$table->boolean('featured')->default(false);
$table->unsignedInteger('quantity')->default(10);
$table->string('image')->nullable();
$table->text('images')->nullable();
$table->bigInteger('category_id')->unsigned()->nullable();
$table->timestamps();
$table->foreign('category_id')->references('id')->on('categories')->onDelete('cascade');
});
}

Open the product model file and add the table name:


class Product extends Model
{
use HasFactory;

protected $table="products";

}

Alright, now save the files and let's migrate the migration. For that, switch to the command prompt and type the command for migration:


php artisan migrate

Migration migrated successfully!

Now, let's insert some dummy products and categories. For that, let's create a factory for products and categories. To create a factory, just type the command:


php artisan make:factory CategoryFactory –model=Category

php artisan make:factory ProductFactory –model=Product

Now, switch to the project and go to the database directory, then open the factories directory. Open the CategoryFactory file and add the following code:


<?php

namespace Database\Factories;

use App\Models\Category;
use Illuminate\Database\Eloquent\Factories\Factory;
use Illuminate\Support\Str;

class CategoryFactory extends Factory
{
/**
* The name of the factory's corresponding model.
*
* @var string
*/
protected $model = Category::class;

/**
* Define the model's default state.
*
* @return array
*/
public function definition()
{
$category_name = $this->faker->unique()->words($nb=2,$asText=true);
$slug = Str::slug($category_name);
return [
'name' => $category_name,
'slug' =>$slug
];
}
}

Open the ProductFactory file and add the following code:


<?php

namespace Database\Factories;

use App\Models\Product;
use Illuminate\Database\Eloquent\Factories\Factory;
use Illuminate\Support\Str;

class ProductFactory extends Factory
{
/**
* The name of the factory's corresponding model.
*
* @var string
*/
protected $model = Product::class;

/**
* Define the model's default state.
*
* @return array
*/
public function definition()
{
$product_name = $this->faker->unique()->words($nb=4,$asText=true);
$slug = Str::slug($product_name);
return [
'name' => $product_name,
'slug' => $slug,
'short_description'=> $this->faker->text(200),
'description' => $this->faker->text(500),
'regular_price' => $this->faker->numberBetween(10,500),
'SKU' => 'DIGI'.$this->faker->unique()->numberBetween(100,500),
'stock_status' => 'instock',
'quantity' => $this->faker->numberBetween(100,200),
'image' => 'digital_' . $this->faker->unique()->numberBetween(1,22).'.jpg',
'category_id' => $this->faker->numberBetween(1,5)
];
}
}

Now, go to the seeders directory and open the DatabaseSeeders.php file. Inside the DatabaseSeeder.php file, add the following code:


\App\Models\Category::factory(6)->create();
\App\Models\Product::factory(22)->create();

Now, let's run the seeder. In the command prompt, type the following command:


php artisan db:seed

Database seeding complete!

Now, let's open the app\Http\Livewire\ShopComponent.php class file and add the following code:


<?php

namespace App\Http\Livewire;

use App\Models\Product;
use Livewire\Component;
use Livewire\WithPagination;

class ShopComponent extends Component
{
use WithPagination;
public function render()
{
$products = Product::paginate(12);
return view('livewire.shop-component',['products'=> $products])->layout("layouts.base");
}
}

Open the resources\views\livewire\shop-component.blade.php view file and add the following code:


<main id="main" class="main-site left-sidebar">
<div class="container">
<div class="wrap-breadcrumb">
<ul>
<li class="item-link"><a href="#" class="link">home</a></li>
<li class="item-link"><span>Shop</span></li>
</ul>
</div>
<div class="row">
<div class="col-lg-9 col-md-8 col-sm-8 col-xs-12 main-content-area">
<div class="banner-shop">
<a href="#" class="banner-link">
<figure><img src="{{ asset('assets/images/shop-banner.jpg') }}" alt=""></figure>
</a>
</div>
<div class="wrap-shop-control">
<h1 class="shop-title">Shop</h1>
<div class="wrap-right">
<div class="sort-item orderby ">
<select name="orderby" class="use-chosen">
<option value="default" selected="selected">Default sorting</option>
<option value="date">Sort by newness</option>
<option value="price">Sort by price: low to high</option>
<option value="price-desc">Sort by price: high to low</option>
</select>
</div>

<div class="sort-item product-per-page">
<select name="post-per-page" class="use-chosen">
<option value="12" selected="selected">12 per page</option>
<option value="16">16 per page</option>
<option value="18">18 per page</option>
<option value="21">21 per page</option>
<option value="24">24 per page</option>
<option value="30">30 per page</option>
<option value="32">32 per page</option>
</select>
</div>

<div class="change-display-mode">
<a href="#" class="grid-mode display-mode active"><i class="fa fa-th"></i>Grid</a>
<a href="list.html" class="list-mode display-mode"><i class="fa fa-th-list"></i>List</a>
</div>
</div>

</div><!--end wrap shop control-->

<style>
.product-wish{
position: absolute;
top:10%;
left:0;
z-index:99;
right:30px;
text-align:right;
padding-top: 0;
}
.product-wish .fa{
color:#cbcbcb;
font-size:32px;
}
.product-wish .fa:hover{
color:#ff7007;
}
.fill-heart{
color:#ff7007 !important;
}
</style>

<div class="row">

<ul class="product-list grid-products equal-container">
@php
$witems = Cart::instance('wishlist')->content()->pluck('id') ;
@endphp
@foreach ($products as $product)
<li class="col-lg-4 col-md-6 col-sm-6 col-xs-6 ">
<div class="product product-style-3 equal-elem ">
<div class="product-thumnail">
<a href="{{route('product.details',['slug'=>$product->slug])}}" title="{{$product->name}}">
<figure><img src="{{ asset('assets/images/products') }}/{{$product->image}}" alt="{{$product->name}}"></figure>
</a>
</div>
<div class="product-info">
<a href="{{route('product.details',['slug'=>$product->slug])}}" class="product-name"><span>{{$product->name}}</span></a>
<div class="wrap-price"><span class="product-price">${{$product->regular_price}}</span></div>
<a href="#" class="btn add-to-cart" wire:click.prevent="store({{$product->id}},'{{$product->name}}',{{$product->regular_price}})">Add To Cart</a>
<div class="product-wish">
@if($witems->contains($product->id))
<a href="#" wire:click.prevent="removeFromWishlist({{$product->id}})"><i class="fa fa-heart fill-heart"></i></a>
@else
<a href="#" wire:click.prevent="addToWishlist({{$product->id}},'{{$product->name}}',{{$product->regular_price}})"><i class="fa fa-heart"></i></a>
@endif
</div>
</div>
</div>
</li>
@endforeach
</ul>
</div>
<div class="wrap-pagination-info">
{{$products->links()}}
</div>
</div>
<div class="col-lg-3 col-md-4 col-sm-4 col-xs-12 sitebar">
<div class="widget mercado-widget categories-widget">
<h2 class="widget-title">All Categories</h2>
<div class="widget-content">
<ul class="list-category">
<li class="category-item has-child-cate">
<a href="#" class="cate-link">Fashion & Accessories</a>
<span class="toggle-control">+</span>
<ul class="sub-cate">
<li class="category-item"><a href="#" class="cate-link">Batteries (22)</a></li>
<li class="category-item"><a href="#" class="cate-link">Headsets (16)</a></li>
<li class="category-item"><a href="#" class="cate-link">Screen (28)</a></li>
</ul>
</li>
<li class="category-item has-child-cate">
<a href="#" class="cate-link">Furnitures & Home Decors</a>
<span class="toggle-control">+</span>
<ul class="sub-cate">
<li class="category-item"><a href="#" class="cate-link">Batteries (22)</a></li>
<li class="category-item"><a href="#" class="cate-link">Headsets (16)</a></li>
<li class="category-item"><a href="#" class="cate-link">Screen (28)</a></li>
</ul>
</li>
<li class="category-item has-child-cate">
<a href="#" class="cate-link">Digital & Electronics</a>
<span class="toggle-control">+</span>
<ul class="sub-cate">
<li class="category-item"><a href="#" class="cate-link">Batteries (22)</a></li>
<li class="category-item"><a href="#" class="cate-link">Headsets (16)</a></li>
<li class="category-item"><a href="#" class="cate-link">Screen (28)</a></li>
</ul>
</li>
<li class="category-item">
<a href="#" class="cate-link">Tools & Equipments</a>
</li>
<li class="category-item">
<a href="#" class="cate-link">Kid's Toys</a>
</li>
<li class="category-item">
<a href="#" class="cate-link">Organics & Spa</a>
</li>
</ul>
</div>
</div><!-- Categories widget-->

<div class="widget mercado-widget filter-widget brand-widget">
<h2 class="widget-title">Brand</h2>
<div class="widget-content">
<ul class="list-style vertical-list list-limited" data-show="6">
<li class="list-item"><a class="filter-link active" href="#">Fashion Clothings</a></li>
<li class="list-item"><a class="filter-link " href="#">Laptop Batteries</a></li>
<li class="list-item"><a class="filter-link " href="#">Printer & Ink</a></li>
<li class="list-item"><a class="filter-link " href="#">CPUs & Prosecsors</a></li>
<li class="list-item"><a class="filter-link " href="#">Sound & Speaker</a></li>
<li class="list-item"><a class="filter-link " href="#">Shop Smartphone & Tablets</a></li>
<li class="list-item default-hiden"><a class="filter-link " href="#">Printer & Ink</a></li>
<li class="list-item default-hiden"><a class="filter-link " href="#">CPUs & Prosecsors</a></li>
<li class="list-item default-hiden"><a class="filter-link " href="#">Sound & Speaker</a></li>
<li class="list-item default-hiden"><a class="filter-link " href="#">Shop Smartphone & Tablets</a></li>
<li class="list-item"><a data-label='Show less<i class="fa fa-angle-up" aria-hidden="true"></i>' class="btn-control control-show-more" href="#">Show more<i class="fa fa-angle-down" aria-hidden="true"></i></a></li>
</ul>
</div>
</div><!-- brand widget-->

<div class="widget mercado-widget filter-widget price-filter">
<h2 class="widget-title">Price</h2>
<div class="widget-content">
<div id="slider-range"></div>
<p>
<label for="amount">Price:</label>
<input type="text" id="amount" readonly>
<button class="filter-submit">Filter</button>
</p>
</div>
</div><!-- Price-->

<div class="widget mercado-widget filter-widget">
<h2 class="widget-title">Color</h2>
<div class="widget-content">
<ul class="list-style vertical-list has-count-index">
<li class="list-item"><a class="filter-link " href="#">Red <span>(217)</span></a></li>
<li class="list-item"><a class="filter-link " href="#">Yellow <span>(179)</span></a></li>
<li class="list-item"><a class="filter-link " href="#">Black <span>(79)</span></a></li>
<li class="list-item"><a class="filter-link " href="#">Blue <span>(283)</span></a></li>
<li class="list-item"><a class="filter-link " href="#">Grey <span>(116)</span></a></li>
<li class="list-item"><a class="filter-link " href="#">Pink <span>(29)</span></a></li>
</ul>
</div>
</div><!-- Color -->

<div class="widget mercado-widget filter-widget">
<h2 class="widget-title">Size</h2>
<div class="widget-content">
<ul class="list-style inline-round ">
<li class="list-item"><a class="filter-link active" href="#">s</a></li>
<li class="list-item"><a class="filter-link " href="#">M</a></li>
<li class="list-item"><a class="filter-link " href="#">l</a></li>
<li class="list-item"><a class="filter-link " href="#">xl</a></li>
</ul>
<div class="widget-banner">
<figure><img src="{{ asset('assets/images/size-banner-widget.jpg') }}" width="270" height="331" alt=""></figure>
</div>
</div>
</div><!-- Size -->

<div class="widget mercado-widget widget-product">
<h2 class="widget-title">Popular Products</h2>
<div class="widget-content">
<ul class="products">
<li class="product-item">
<div class="product product-widget-style">
<div class="thumbnnail">
<a href="detail.html" title="Radiant-360 R6 Wireless Omnidirectional Speaker [White]">
<figure><img src="{{ asset('assets/images/products/digital_01.jpg') }}" alt=""></figure>
</a>
</div>
<div class="product-info">
<a href="#" class="product-name"><span>Radiant-360 R6 Wireless Omnidirectional Speaker...</span></a>
<div class="wrap-price"><span class="product-price">$168.00</span></div>
</div>
</div>
</li>

<li class="product-item">
<div class="product product-widget-style">
<div class="thumbnnail">
<a href="detail.html" title="Radiant-360 R6 Wireless Omnidirectional Speaker [White]">
<figure><img src="{{ asset('assets/images/products/digital_17.jpg') }}" alt=""></figure>
</a>
</div>
<div class="product-info">
<a href="#" class="product-name"><span>Radiant-360 R6 Wireless Omnidirectional Speaker...</span></a>
<div class="wrap-price"><span class="product-price">$168.00</span></div>
</div>
</div>
</li>

<li class="product-item">
<div class="product product-widget-style">
<div class="thumbnnail">
<a href="detail.html" title="Radiant-360 R6 Wireless Omnidirectional Speaker [White]">
<figure><img src="{{ asset('assets/images/products/digital_18.jpg') }}" alt=""></figure>
</a>
</div>
<div class="product-info">
<a href="#" class="product-name"><span>Radiant-360 R6 Wireless Omnidirectional Speaker...</span></a>
<div class="wrap-price"><span class="product-price">$168.00</span></div>
</div>
</div>
</li>

<li class="product-item">
<div class="product product-widget-style">
<div class="thumbnnail">
<a href="detail.html" title="Radiant-360 R6 Wireless Omnidirectional Speaker [White]">
<figure><img src="{{ asset('assets/images/products/digital_20.jpg') }}" alt=""></figure>
</a>
</div>
<div class="product-info">
<a href="#" class="product-name"><span>Radiant-360 R6 Wireless Omnidirectional Speaker...</span></a>
<div class="wrap-price"><span class="product-price">$168.00</span></div>
</div>
</div>
</li>

</ul>
</div>
</div><!-- brand widget-->

</div><!--end sitebar-->

</div><!--end row-->

</div><!--end container-->
</main>

Now, let's check this. Switch to the browser and go to the shop page. You can see here that the products are coming from the database.

So, in this way, you can make products dynamic on the shop page.