This tutorial is to create a shopping cart in Laravel. It shows how to add a product to a shopping cart. This is as simple as it gets. It will be a starter program who wants to get into writing a fullfledged shopping cart in PHP Laravel.
This example manages the cart items in a session. It shows a product gallery with the add-to-cart button on the welcome page.
This code gives a simple shopping cart interface that allows add-to-cart from multiple places.
This example keeps the product data in a config file. In a real-time application, it will be from the database. In a previous tutorial, we have already seen how to load products into a Laravel shopping cart from the database.
config/products.php
<?php
return [
'H123' => [
'name' => 'On-Ear Headphone BT v8.1',
'code' => 'H123',
'price' => 19.99,
'image_path' => 'storage/products/headphone.jpg',
],
'C456' => [
'name' => 'Mirrorless Digital Camera',
'code' => 'C456',
'price' => 29.99,
'image_path' => 'storage/products/camera.jpg',
],
'W789' => [
'name' => 'Quartz Analog Black Dial Watch',
'code' => 'W789',
'price' => 39.99,
'image_path' => 'storage/products/watch.jpg',
],
];
?>
In this Laravel add-to-cart example, the following web URL rules are created to perform the shopping cart operations. The supported cart operations are add-to-cart, delete item or clear cart, bulk-add-to-cart and filtering product.
routes/web.php
<?php
use Illuminate\Support\Facades\Route;
use App\Http\Controllers\ProductController;
use App\Http\Controllers\CartController;
Route::get('/', [ProductController::class, 'index'])->name('products.index');
Route::get('/products/{product_code}', [ProductController::class, 'viewProduct'])->name('products.view');
Route::post('/add-to-cart', [ProductController::class, 'addToCart']);
Route::post('/bulk-add-to-cart', [ProductController::class, 'bulkAddToCart']);
Route::get('/cart', [CartController::class, 'cart'])->name('cart');
Route::get('clear-cart', [CartController::class, 'clearCart']);
Route::post('/remove-from-cart', [CartController::class, 'deleteProduct'])->name('delete.cart.product');
Route::get('/search', [ProductController::class, 'productSearch'])->name('products.search');
?>
There are three templates created for the Laravel add-to-cart project.
These three templates have the products with an add-to-cart option. The search result list allows one to select multiple products to push bulk data to the Laravel shopping cart.
resources/views/products.blade.php
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Add to Cart in Laravel</title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css" integrity="sha384-T3c6CoIi6uLrA9TneNEoa7RxnatzjcDSCmG1MXxSR1GAsXEV/Dwwykc2MPK8M2HN" crossorigin="anonymous">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.1.2/css/bootstrap.min.css">
<style>
body{
padding: 2rem 0rem;
}
.image-parent {
max-width: 60px;
border: #F0F0F0 1px solid;
}
</style>
</head>
<body>
<div class="container">
@include('header')
<div class="row mt-5">
@foreach ($products as $index => $product)
<div class="col-md-4 mb-4">
<div class="card" style="width:23rem">
<a href="{{ route('products.view', ['product_code' => $product['code']]) }}"><img src="{{ asset($product['image_path']) }}" class="card-img-top" alt="{{ $product['name'] }}"></a>
<div class="card-body">
<h5 class="card-title">{{ $product['name'] }}</h5>
<p class="card-text">Code# {{ $product['code'] }}</p>
<p class="card-text">${{ $product['price'] }}</p>
<span class="">
<span class="btn btn-primary add-text add-to-cart" data-product-code="{{ $product['code'] }}">Add to cart</span> <span class="btn btn-primary d-none adding-text">Adding</span>
<span class="btn btn-primary d-none added-text">Added. <a href="/cart" class="text-white text-decoration-none">Go to cart</a></span></span>
</div>
</div>
</div>
@endforeach
</div>
</div>
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
</body>
</html>
resources/views/view.blade.php
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Product view</title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css" integrity="sha384-T3c6CoIi6uLrA9TneNEoa7RxnatzjcDSCmG1MXxSR1GAsXEV/Dwwykc2MPK8M2HN" crossorigin="anonymous">
<style>
img {
max-width: 100%;
height: auto;
}
</style>
</head>
<body>
<div class="container">
@include('header')
@if($productDetails)
<div class="mt-5 d-flex w-100">
<div class="w-50"><img src="{{ asset($productDetails['image_path']) }}"></div>
<div class="ms-5 w-75">
<h2>{{ $productDetails['name'] }}</h2>
<h4>${{ $productDetails['price'] }}</h4>
<div>Code# {{ $productDetails['code'] }}</div>
<span class="btn btn-primary mt-3">
<span class="add-text add-to-cart" data-product-code="{{ $productDetails['code'] }}">Add to cart</span> <span class="d-none adding-text">Adding</span>
<span class="d-none added-text">Added. <a href="/cart" class="text-white text-decoration-none">Go to cart</a></span></span>
</div>
</div>
@endif
</div>
</body>
</html>
The Laravel shopping cart application header consists of a product filter. The below code is to include a header into the Laravel page templates.
On entering text into this filter, it will show a product list in a suggestion box.
resources/views/header.blade.php
<nav class="navbar navbar-light bg-light">
<div class="container-fluid">
<h3><a href="/" class="text-decoration-none text-dark">Laravel Cart</a></h3>
<div class="d-flex w-50">
<div class="position-relative" style="width:80%">
<div>
<input class="form-control me-2" id="product-search" type="text" autocomplete="off" placeholder="Enter product code, e.g. H123,C456">
</div>
<div id="product-details-container" class="position-absolute top-100 start-0 bg-light z-2 w-100"></div>
</div>
<button class="btn btn-outline-success bulk-upload mx-2" type="button">Add to cart</button>
</div>
<a href="/cart" class="text-decoration-none"><img class="mx-2" src="{{ asset('images/shopping-cart.svg') }}">View Cart</a>
</div>
</nav>
The below HTML is to display the list of products on changing the filter input. When selecting an item from the suggested result, it will add the code to the input.
If multiple products are selected, it adds a comma-separated product code to the filter. It helps to perform a bulk add-to-cart action.
resources/views/search_results.blade.php
@if (!empty($searchResults))
<ul class="list-group">
@foreach ($searchResults as $product)
<a class="list-group-item list-group-item-action d-flex justify-content-between align-items-center product" data-code="{{ $product['code'] }}" style="cursor: pointer;">
<div class="flex-column">
{{ $product['name'] }}
<p><small>${{ $product['price'] }}</small></p>
</div>
<div class="image-parent">
<img src="{{ asset($product['image_path']) }}" class="img-fluid">
</div>
</a>
@endforeach
</ul>
@else
<p class="mx-3 mt-3">No products found.</p>
@endif
There are many JavaScript event handlers registered for this Laravel add-to-cart application. Those are for the following purposes.
The below code is part of the product gallery and product-view templates to perform add-to-cart and product searches. The product search and the bulk add-to-cart is enabled on the common header template.
$('.add-to-cart').click(function() {
var addButton = $(this);
var productCode = addButton.data('product-code');
addButton.closest('div').find('.add-text').hide();
addButton.closest('div').find('.adding-text').removeClass('d-none');
$.ajax({
type: 'POST',
url: '/add-to-cart',
data: {
product_code: productCode,
_token: '{{ csrf_token() }}'
},
success: function(response) {
addButton.closest('div').find('.adding-text').addClass('d-none');
addButton.closest('div').find('.added-text').removeClass('d-none');
}
});
});
$('.bulk-add-to-cart').click(function() {
var productCodes = $('#product-search').val();
$.ajax({
type: 'POST',
url: '/bulk-add-to-cart',
data: {
product_code: productCodes,
_token: '{{ csrf_token() }}'
},
success: function(response) {
window.location.href = '/cart';
},
error: function(xhr, status, error) {
alert('Error: ' + xhr.responseText);
}
});
});
$('#product-search').keyup(function() {
var productCode = $(this).val();
if (productCode.includes(',')) {
var productCodes = productCode.split(',');
}
$.ajax({
type: 'GET',
url: '/search',
data: {
product_code: productCode
},
success: function(response) {
$('#product-details-container').html(response);
$('#product-details-container').show();
}
});
});
When clicking a product list item from the filtered result, the below event handler will be called.
It pushes the selected product code to the search input. The search box contains a button which pushes the selected product data into a cart session in one click.
$(document).ready(function() {
var productCodes = [];
// On clicking the search result item, append the code to the filter input
$('.product').click(function() {
var productCode = $(this).data('code');
if (!productCodes.includes(productCode)) {
productCodes.push(productCode);
}
$('#product-search').val(productCodes.join(','));
});
});
The cart deletes and clear actions are the common functionalities of an eCommerce application.
Each cart item has a “remove” button. The below code shows how to register the delete button’s click event to call the cart item delete action.
On clicking the “clear cart” button, it wipes out the entire cart by using a single line of code.
The delete action prompts user confirmation via JavaScript before request deleting.
$(".delete-item").click(function() {
var removeButton = $(this);
var productCode = removeButton.data('product-code');
if (confirm("Are you sure you want to remove product from the cart?")) {
removeButton.closest('div').find('.remove-text').hide();
removeButton.closest('div').find('.removing-text').removeClass('d-none');
$.ajax({
type: 'POST',
url: '{{ url("remove-from-cart") }}',
data: {
_token: '{{ csrf_token() }}',
product_code: productCode
},
success: function(response) {
removeButton.closest('div').find('.removing-text').addClass('d-none');
removeButton.closest('div').find('.removed-text').removeClass('d-none');
window.location.reload();
}
});
}
});
$('#clear-cart-btn').click(function(e) {
e.preventDefault();
if (confirm('Are you sure you want to clear your cart?')) {
window.location.href = $(this).attr('href');
} else {
return false;
}
});
This section shows a cart controller class. It shows how the cart list, add, delete and clear action handles are coded.
The cart delete handler receives the particular product code via the AJAX POST request.
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Redirect;
class CartController extends Controller
{
public function cart()
{
return view('cart');
}
public function clearCart()
{
session()->forget('cart');
return redirect()->back();
}
public function deleteProduct(Request $request)
{
if ($request->product_code) {
$cart = session()->get('cart');
if (isset($cart[$request->product_code])) {
unset($cart[$request->product_code]);
session()->put('cart', $cart);
}
}
}
}
?>
The below template contains an HTML table that displays rows of cart items from the session.
The cart table displays minimal data on the products in the cart. It shows the product name, price, and quantity with the image thumbnails.
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Laravel</title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css" integrity="sha384-T3c6CoIi6uLrA9TneNEoa7RxnatzjcDSCmG1MXxSR1GAsXEV/Dwwykc2MPK8M2HN" crossorigin="anonymous">
</head>
<body>
<div class="container">
@include('header')
@if(session('success'))
<div class="alert alert-success">
{{ session('success') }}
</div>
@endif
<a href="{{ url('clear-cart') }}" id="clear-cart-btn"><button class="btn btn-danger mb-2 float-end">Clear Cart</button></a>
<table id="cart" class="table table-bordered">
<thead>
<tr>
<th>Product</th>
<th class="text-center">Quantity</th>
<th class="text-end">Price</th>
<th class="text-end">Total</th>
<th class="text-center">Action</th>
</tr>
</thead>
<tbody>
@if(session('cart'))
@foreach(session('cart') as $id => $details)
<tr rowId="{{ $id }}">
<td data-th="Product">
<div class="row">
<div class="col-sm-3 hidden-xs"><a href="{{ route('products.view', ['product_code' => $details['code']]) }}"><img src="{{ asset($details['image']) }}" width="100" height="80" class="img-responsive" /></a>
</div>
<div class="col-sm-9">
<h5 class="my-auto">{{ $details['name'] }}</h5>
</div>
</div>
</td>
<td class="text-center">{{ $details['quantity'] }}</td>
<td class="text-end">${{ $details['price'] }}</td>
<td class="text-end">${{ $details['quantity'] * $details['price'] }}</td>
<td class="text-center">
<span>
<span class="btn btn-outline-danger remove-text delete-item" data-product-code="{{ $details['code'] }}">Remove Item</span>
<span class="btn btn-outline-danger d-none removing-text">Removing</span>
<span class="btn btn-outline-danger d-none removed-text">Removed.</span></span>
</td>
</tr>
@endforeach
@endif
</tbody>
</table>
</div>
</body>
</html>
Thus we have created an add-to-cart option from multiple points in Laravel. If you are new to Laravel, setting up the development environment is required.
view demo Download