Making your store interactive
Up to this point, your store can display products beautifully, and customers can browse them. But browsing alone won’t pay the bills — your site needs a way for users to collect products they want to buy, just like a real-world shopping basket.
This is where the shopping cart system comes in. It’s the first real piece of “e-commerce logic” that connects browsing with purchasing. Without it, your store is just a catalog.
In this part, you’ll learn how to design and build a simple yet flexible shopping cart system using Laravel. We’ll cover both the conceptual side (how a cart works behind the scenes) and the technical side (building it with Laravel sessions).
🎯 What We’ll Build
Let’s clearly define our goals so you have a mental roadmap:
- Each product detail page has an “Add to Cart” button.
- Users can view a cart page showing all selected products, quantities, and totals.
- Users can update quantities or remove items.
- Cart data will be stored in sessions (for now — database cart comes later).
- We will write clean, reusable cart logic so you can expand it later during checkout.
This step will make your store feel alive and interactive.
🧠 How Shopping Carts Work (Behind the Scenes)
Before writing code, it helps to understand the mechanics:
- A cart is basically a collection (array) of products with quantities.
- It lives temporarily in session storage until the user checks out or leaves.
- When a user adds a product, we check if it’s already in the cart:
- If yes, increase the quantity
- If no, add a new item entry
- When showing the cart, we calculate the subtotal, tax, and total.
This concept is simple but powerful — and it will become the base for our checkout system later.
⚙️ Step 1 : Setting Up Routes
Let’s first plan the user flows:
/cart– Show the shopping cart./cart/add/{id}– Add a product to the cart./cart/remove/{id}– Remove a product from the cart./cart/update/{id}– Update quantity.
Open routes/web.php and add:
use App\Http\Controllers\CartController;
Route::get('/cart', [CartController::class, 'index'])->name('cart.index');
Route::post('/cart/add/{id}', [CartController::class, 'add'])->name('cart.add');
Route::post('/cart/update/{id}', [CartController::class, 'update'])->name('cart.update');
Route::delete('/cart/remove/{id}', [CartController::class, 'remove'])->name('cart.remove');
This gives you all the endpoints you need to interact with the cart.
⚙️ Step 2: Create the CartController
Now build the logic behind those routes.
php artisan make:controller CartController
Open app/Http/Controllers/CartController.php and add:
namespace App\Http\Controllers;
use App\Models\Product;
use Illuminate\Http\Request;
class CartController extends Controller
{
public function index()
{
$cart = session()->get('cart', []);
$total = collect($cart)->sum(fn($item) => $item['price'] * $item['quantity']);
return view('cart.index', compact('cart','total'));
}
public function add($id)
{
$product = Product::findOrFail($id);
$cart = session()->get('cart', []);
if(isset($cart[$id])) {
$cart[$id]['quantity']++;
} else {
$cart[$id] = [
'name' => $product->name,
'price' => $product->price,
'quantity' => 1,
'image' => $product->image
];
}
session()->put('cart', $cart);
return redirect()->back()->with('success','Product added to cart!');
}
public function update(Request $request, $id)
{
$cart = session()->get('cart', []);
if(isset($cart[$id])) {
$cart[$id]['quantity'] = $request->quantity;
session()->put('cart', $cart);
}
return redirect()->route('cart.index');
}
public function remove($id)
{
$cart = session()->get('cart', []);
if(isset($cart[$id])) {
unset($cart[$id]);
session()->put('cart', $cart);
}
return redirect()->route('cart.index');
}
}
What this does:
- We use Laravel’s
session()to store the cart array. add()checks if the product exists in the cart before adding.update()changes the quantity.remove()deletes an item completely.index()sends cart data to the view with a computed total.
This is a clean, self-contained system — no database needed yet.
⚙️ Step 3: Adding the “Add to Cart” Button
Let’s make the button on your product detail page actually do something.
In resources/views/shop/show.blade.php replace the Add to Cart button:
<form action="{{ route('cart.add', $product->id) }}" method="POST">
@csrf
<button type="submit" class="btn btn-success btn-lg mt-3">
Add to Cart
</button>
</form>
Now when someone clicks it, the product goes into their cart session.
⚙️ Step 4: Building the Cart Page View
Create a new file resources/views/cart/index.blade.php:
@extends('layouts.app')
@section('content')
<div class="container">
<h1 class="mb-4">Your Shopping Cart</h1>
@if(session('success'))
<div class="alert alert-success">{{ session('success') }}</div>
@endif
@if(empty($cart))
<p>Your cart is empty. <a href="{{ route('shop.index') }}">Continue shopping</a></p>
@else
<table class="table table-bordered">
<thead>
<tr>
<th>Product</th>
<th>Price</th>
<th>Quantity</th>
<th>Subtotal</th>
<th></th>
</tr>
</thead>
<tbody>
@foreach($cart as $id => $item)
<tr>
<td>
<img src="{{ asset('storage/'.$item['image']) }}" width="50" class="me-2">
{{ $item['name'] }}
</td>
<td>${{ $item['price'] }}</td>
<td>
<form action="{{ route('cart.update',$id) }}" method="POST" class="d-flex">
@csrf
<input type="number" name="quantity" value="{{ $item['quantity'] }}" min="1" class="form-control form-control-sm w-50 me-2">
<button class="btn btn-sm btn-primary">Update</button>
</form>
</td>
<td>${{ $item['price'] * $item['quantity'] }}</td>
<td>
<form action="{{ route('cart.remove',$id) }}" method="POST">
@csrf @method('DELETE')
<button class="btn btn-sm btn-danger">Remove</button>
</form>
</td>
</tr>
@endforeach
</tbody>
</table>
<div class="text-end">
<h4>Total: ${{ $total }}</h4>
<a href="#" class="btn btn-success btn-lg mt-3">Proceed to Checkout</a>
</div>
@endif
</div>
@endsection
What’s happening here:
- Displays all cart items with images and quantities.
- Lets users update or remove items directly.
- Shows running total at the bottom.
- Handles empty cart gracefully.
⚙️ Step 5 : Session Tips and Common Gotchas
A few lessons learned from real projects:
- Session data disappears on browser close — This is okay for now, but later we’ll store carts in the database for logged-in users.
- Always validate quantity input — Make sure users can’t set quantity to zero or negative.
- Use flash messages (
with('success','...')) for user feedback. It makes the site feel more interactive. - Clear session on checkout — Don’t forget this later when building the order system.
💡 Personal Notes & UX Suggestions
Here are a few insights from building carts on real Laravel projects:
- Users expect a mini cart icon in the navbar showing the number of items. You can do this by counting session items in your layout.
- Add a “Continue Shopping” button on the cart page to bring users back.
- Keep cart actions fast and simple. Avoid page reloads if possible — you can later upgrade this to use AJAX or Alpine.js for instant updates.
- For mobile users, make sure the table scrolls horizontally using Bootstrap’s
.table-responsivewrapper.
Even small UX touches make your cart feel professional.
✅ Summary
At this point, your Laravel e-commerce application has:
- A fully functional session-based shopping cart
- Add, update, and remove item features
- A clean and responsive cart page
- A smooth user experience to keep shoppers engaged
This is a huge milestone. Your store has gone from static product listings to a dynamic interactive shop where customers can collect products for checkout.
🚀 Coming Next
In Step 7, we’ll move from the cart to the checkout system — where customers enter their details, confirm their order, and where you’ll store the order data in the database.
This is where your e-commerce app becomes a real store.