In this section, we will create shopping cart functionality with Laravel 9 using the Shopping Cart package. For this tutorial, we will use Laravel Breeze for authentication and Tailwind CSS. We will cover add-to-cart functionality including adding products to the cart, editing product quantities, and removing products from the cart.
Step 1: Create Laravel Project
To install a fresh new Laravel 9 application, navigate to your terminal, type the command, and create a new Laravel app.
composer create-project laravel/laravel project-name
Step 2: Setup Databases
Now, you need to connect the Laravel app to the database. Open the .env configuration file and add the database credentials as suggested below.
DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=database_name
DB_USERNAME=database_user_name
DB_PASSWORD=database_password
Step 3: Install Laravel Breeze
Next, you need install laravel breeze via composer.
composer require laravel/breeze --dev
Authentication to run below command.
php artisan breeze:install
npm install
npm run dev
php artisan migrate
Step 4: Setup laravelshoppingcart package
composer require "darryldecode/cart"
Open config/app.php and add this line to your Service Providers Array.
Darryldecode\Cart\CartServiceProvider::class
Open config/app.php and add this line to your Aliases.
'Cart' => Darryldecode\Cart\Facades\CartFacade::class
Optional configuration file (useful if you plan to have full control).
php artisan vendor:publish --provider="Darryldecode\Cart\CartServiceProvider" --tag="config"
Step 5: Create Product Model with Migration
php artisan make:model Product -m
product migration file.
create_products_table.php
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('products', function (Blueprint $table) {
$table->id();
$table->string('name');
$table->double('price');
$table->text('description');
$table->string('image');
$table->timestamps();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('products');
}
};
App/Modals/Product.php
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class Product extends Model
{
use HasFactory;
protected $fillable = [
'name',
'price',
'image',
'description',
];
}
Step 6: Create Product Seeder
php artisan make:seeder ProductSeeder
Now add dummy data in seeder.
database/seeders/ProductSeeder.php
<?php
namespace Database\Seeders;
use App\Models\Product;
use Illuminate\Database\Console\Seeds\WithoutModelEvents;
use Illuminate\Database\Seeder;
class ProductSeeder extends Seeder
{
/**
* Run the database seeds.
*
* @return void
*/
public function run()
{
$products = [
[
'name' => 'Fesh milk 250ml',
'price' => 250,
'description' => 'lorem ipsum',
'image' => 'https://cdn.pixabay.com/photo/2016/12/06/18/27/milk-1887234__340.jpg'
],
[
'name' => '12 Egs',
'price' => 6,
'description' => 'lorem ipsum',
'image' => 'https://cdn.pixabay.com/photo/2016/07/23/15/24/egg-1536990__340.jpg'
],
[
'name' => 'Wine 500ml',
'price' => 50,
'description' => 'lorem ipsum',
'image' => 'https://cdn.pixabay.com/photo/2015/11/07/12/00/alcohol-1031713__340.png'
],
[
'name' => 'Homey 100ml',
'price' => 12,
'description' => 'lorem ipsum',
'image' => 'https://cdn.pixabay.com/photo/2017/01/06/17/49/honey-1958464__340.jpg'
]
];
Product::insert($products);
}
}
database/seeders/DatabaseSeeder.php
<?php
namespace Database\Seeders;
// use Illuminate\Database\Console\Seeds\WithoutModelEvents;
use Illuminate\Database\Seeder;
class DatabaseSeeder extends Seeder
{
/**
* Seed the application's database.
*
* @return void
*/
public function run()
{
$this->call(ProductSeeder::class);
// \App\Models\User::factory(10)->create();
// \App\Models\User::factory()->create([
// 'name' => 'Test User',
// 'email' => '[email protected]',
// ]);
}
}
Step 7: Add Shopping Cart Logic In Controller
app/Http/Controllers/ProductController.php
<?php
namespace App\Http\Controllers;
use App\Models\Product;
use Illuminate\Http\Request;
class ProductController extends Controller
{
public function productList()
{
$products = Product::all();
return view('products', compact('products'));
}
}
app/Http/Controllers/CartController.php
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
class CartController extends Controller
{
public function cartList()
{
$cartItems = \Cart::getContent();
// dd($cartItems);
return view('cart', compact('cartItems'));
}
public function addToCart(Request $request)
{
\Cart::add([
'id' => $request->id,
'name' => $request->name,
'price' => $request->price,
'quantity' => $request->quantity,
'attributes' => array(
'image' => $request->image,
)
]);
session()->flash('success', 'Product is Added to Cart Successfully !');
return redirect()->route('cart.list');
}
public function updateCart(Request $request)
{
\Cart::update(
$request->id,
[
'quantity' => [
'relative' => false,
'value' => $request->quantity
],
]
);
session()->flash('success', 'Item Cart is Updated Successfully !');
return redirect()->route('cart.list');
}
public function removeCart(Request $request)
{
\Cart::remove($request->id);
session()->flash('success', 'Item Cart Remove Successfully !');
return redirect()->route('cart.list');
}
public function clearAllCart()
{
\Cart::clear();
session()->flash('success', 'All Item Cart Clear Successfully !');
return redirect()->route('cart.list');
}
}
Step 8: Create products and Cart Routes
<?php
use App\Http\Controllers\CartController;
use App\Http\Controllers\ProductController;
use Illuminate\Support\Facades\Route;
/*
|--------------------------------------------------------------------------
| Web Routes
|--------------------------------------------------------------------------
|
| Here is where you can register web routes for your application. These
| routes are loaded by the RouteServiceProvider within a group which
| contains the "web" middleware group. Now create something great!
|
*/
Route::get('/', function () {
return view('welcome');
});
Route::get('products', [ProductController::class, 'productList'])->name('products.list');
Route::get('cart', [CartController::class, 'cartList'])->name('cart.list');
Route::post('cart', [CartController::class, 'addToCart'])->name('cart.store');
Route::post('update-cart', [CartController::class, 'updateCart'])->name('cart.update');
Route::post('remove', [CartController::class, 'removeCart'])->name('cart.remove');
Route::post('clear', [CartController::class, 'clearAllCart'])->name('cart.clear');
Route::get('/dashboard', function () {
return view('dashboard');
})->middleware(['auth'])->name('dashboard');
require __DIR__.'/auth.php';
Step 9: Add Shopping Cart in Laravel Blade View Files
Add products routes and carts routes.
resources/views/layouts/navigation.blade.php
<nav x-data="{ open: false }" class="bg-white border-b border-gray-100">
<!-- Primary Navigation Menu -->
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
<div class="flex justify-between h-16">
<div class="flex">
<!-- Logo -->
<div class="shrink-0 flex items-center">
<a href="{{ route('dashboard') }}">
<x-application-logo class="block h-10 w-auto fill-current text-gray-600" />
</a>
</div>
<!-- Navigation Links -->
<div class="hidden space-x-8 sm:-my-px sm:ml-10 sm:flex">
<x-nav-link :href="route('dashboard')" :active="request()->routeIs('dashboard')">
{{ __('Dashboard') }}
</x-nav-link>
<x-nav-link :href="route('products.list')" :active="request()->routeIs('products.list')">
{{ __('Products') }}
</x-nav-link>
<a href="{{ route('cart.list') }}" class="flex items-center">
<svg class="w-5 h-5 text-purple-600" fill="none" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" viewBox="0 0 24 24" stroke="currentColor">
<path d="M3 3h2l.4 2M7 13h10l4-8H5.4M7 13L5.4 5M7 13l-2.293 2.293c-.63.63-.184 1.707.707 1.707H17m0 0a2 2 0 100 4 2 2 0 000-4zm-8 2a2 2 0 11-4 0 2 2 0 014 0z"></path>
</svg>
<span class="text-red-700">{{ Cart::getTotalQuantity()}}</span>
</a>
</div>
</div>
<!-- Settings Dropdown -->
<div class="hidden sm:flex sm:items-center sm:ml-6">
<x-dropdown align="right" width="48">
<x-slot name="trigger">
<button class="flex items-center text-sm font-medium text-gray-500 hover:text-gray-700 hover:border-gray-300 focus:outline-none focus:text-gray-700 focus:border-gray-300 transition duration-150 ease-in-out">
<div>{{ Auth::user()->name }}</div>
<div class="ml-1">
<svg class="fill-current h-4 w-4" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20">
<path fill-rule="evenodd" d="M5.293 7.293a1 1 0 011.414 0L10 10.586l3.293-3.293a1 1 0 111.414 1.414l-4 4a1 1 0 01-1.414 0l-4-4a1 1 0 010-1.414z" clip-rule="evenodd" />
</svg>
</div>
</button>
</x-slot>
<x-slot name="content">
<!-- Authentication -->
<form method="POST" action="{{ route('logout') }}">
@csrf
<x-dropdown-link :href="route('logout')"
onclick="event.preventDefault();
this.closest('form').submit();">
{{ __('Log Out') }}
</x-dropdown-link>
</form>
</x-slot>
</x-dropdown>
</div>
<!-- Hamburger -->
<div class="-mr-2 flex items-center sm:hidden">
<button @click="open = ! open" class="inline-flex items-center justify-center p-2 rounded-md text-gray-400 hover:text-gray-500 hover:bg-gray-100 focus:outline-none focus:bg-gray-100 focus:text-gray-500 transition duration-150 ease-in-out">
<svg class="h-6 w-6" stroke="currentColor" fill="none" viewBox="0 0 24 24">
<path :class="{'hidden': open, 'inline-flex': ! open }" class="inline-flex" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 6h16M4 12h16M4 18h16" />
<path :class="{'hidden': ! open, 'inline-flex': open }" class="hidden" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12" />
</svg>
</button>
</div>
</div>
</div>
<!-- Responsive Navigation Menu -->
<div :class="{'block': open, 'hidden': ! open}" class="hidden sm:hidden">
<div class="pt-2 pb-3 space-y-1">
<x-responsive-nav-link :href="route('dashboard')" :active="request()->routeIs('dashboard')">
{{ __('Dashboard') }}
</x-responsive-nav-link>
</div>
<!-- Responsive Settings Options -->
<div class="pt-4 pb-1 border-t border-gray-200">
<div class="px-4">
<div class="font-medium text-base text-gray-800">{{ Auth::user()->name }}</div>
<div class="font-medium text-sm text-gray-500">{{ Auth::user()->email }}</div>
</div>
<div class="mt-3 space-y-1">
<!-- Authentication -->
<form method="POST" action="{{ route('logout') }}">
@csrf
<x-responsive-nav-link :href="route('logout')"
onclick="event.preventDefault();
this.closest('form').submit();">
{{ __('Log Out') }}
</x-responsive-nav-link>
</form>
</div>
</div>
</div>
</nav>
resources/views/products.blade.php
<x-app-layout>
<x-slot name="header">
<h2 class="font-semibold text-xl text-gray-800 leading-tight">
{{ __('Product List') }}
</h2>
</x-slot>
<div class="container px-12 py-8 mx-auto">
<h3 class="text-2xl font-bold text-purple-700">Our Product</h3>
<div class="h-1 bg-red-500 w-36"></div>
<div class="grid grid-cols-1 gap-6 mt-6 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4">
@foreach ($products as $product)
<div class="w-full max-w-sm mx-auto overflow-hidden bg-white rounded-md shadow-md">
<img src="{{ url($product->image) }}" alt="" class="w-full max-h-60">
<div class="flex items-end justify-end w-full bg-cover">
</div>
<div class="px-5 py-3">
<h3 class="text-gray-700 uppercase">{{ $product->name }}</h3>
<span class="mt-2 text-gray-500">${{ $product->price }}</span>
<form action="{{ route('cart.store') }}" method="POST" enctype="multipart/form-data">
@csrf
<input type="hidden" value="{{ $product->id }}" name="id">
<input type="hidden" value="{{ $product->name }}" name="name">
<input type="hidden" value="{{ $product->price }}" name="price">
<input type="hidden" value="{{ $product->image }}" name="image">
<input type="hidden" value="1" name="quantity">
<button class="px-4 py-1.5 text-white text-sm bg-blue-800 rounded">Add To Cart</button>
</form>
</div>
</div>
@endforeach
</div>
</div>
</x-app-layout>
resources/views/cart.blade.php
<x-app-layout>
<x-slot name="header">
<h2 class="font-semibold text-xl text-gray-800">
{{ __('Cart') }}
</h2>
</x-slot>
<main class="my-8">
<div class="container px-6 mx-auto">
<div class="flex justify-center my-6">
<div class="flex flex-col w-full p-8 text-gray-800 bg-white shadow-lg pin-r pin-y md:w-4/5 lg:w-4/5">
@if ($message = Session::get('success'))
<div class="p-4 mb-3 bg-green-400 rounded">
<p class="text-green-800">{{ $message }}</p>
</div>
@endif
<h3 class="text-3xl font-bold">Carts</h3>
<div class="flex-1">
<table class="w-full text-sm lg:text-base" cellspacing="0">
<thead>
<tr class="h-12 uppercase">
<th class="hidden md:table-cell"></th>
<th class="text-left">Name</th>
<th class="pl-5 text-left lg:text-right lg:pl-0">
<span class="lg:hidden" title="Quantity">Qtd</span>
<span class="hidden lg:inline">Quantity</span>
</th>
<th class="hidden text-right md:table-cell"> price</th>
<th class="hidden text-right md:table-cell"> Remove </th>
</tr>
</thead>
<tbody>
@foreach ($cartItems as $item)
<tr>
<td class="hidden pb-4 md:table-cell">
<a href="#">
<img src="{{ $item->attributes->image }}" class="w-20 rounded" alt="Thumbnail">
</a>
</td>
<td>
<a href="#">
<p class="mb-2 md:ml-4 text-purple-600 font-bold">{{ $item->name }}</p>
</a>
</td>
<td class="justify-center mt-6 md:justify-end md:flex">
<div class="h-10 w-28">
<div class="relative flex flex-row w-full h-8">
<form action="{{ route('cart.update') }}" method="POST">
@csrf
<input type="hidden" name="id" value="{{ $item->id}}" >
<input type="text" name="quantity" value="{{ $item->quantity }}"
class="w-16 text-center h-6 text-gray-800 outline-none rounded border border-blue-600" />
<button class="px-4 mt-1 py-1.5 text-sm rounded rounded shadow text-violet-100 bg-violet-500">Update</button>
</form>
</div>
</div>
</td>
<td class="hidden text-right md:table-cell">
<span class="text-sm font-medium lg:text-base">
${{ $item->price }}
</span>
</td>
<td class="hidden text-right md:table-cell">
<form action="{{ route('cart.remove') }}" method="POST">
@csrf
<input type="hidden" value="{{ $item->id }}" name="id">
<button class="px-4 py-2 text-white bg-red-600 shadow rounded-full">x</button>
</form>
</td>
</tr>
@endforeach
</tbody>
</table>
<div>
Total: ${{ Cart::getTotal() }}
</div>
<div>
<form action="{{ route('cart.clear') }}" method="POST">
@csrf
<button class="px-6 py-2 text-sm rounded shadow text-red-100 bg-red-500">Clear Carts</button>
</form>
</div>
</div>
</div>
</div>
</div>
</main>
</x-app-layout>
Step 10: Run Laravel and vite server
php artisan serve
# and
npm run dev
Note: If you want additional functionality such as tax charges, authenticated user shopping carts, and subtotal calculations, you can check the documentation for more details. Shopping Cart