Welcome to a tutorial on how to create a simple PHP shopping cart. Without a database, that is. Need a simple “no database cart”? Well, it is possible, but it is still not a straightforward thing. So let us walk through an example, read on!
TABLE OF CONTENTS
DOWNLOAD & NOTES
Here is the download link to the example code, so you don’t have to copy-paste everything.
EXAMPLE CODE DOWNLOAD
I have released it under the MIT license, so feel free to build on top of it or use it in your own project.
SORRY FOR THE ADS...
But someone has to pay the bills, and sponsors are paying for it. I insist on not turning Code Boxx into a "paid scripts" business, and I don't "block people with Adblock". Every little bit of support helps.
Buy Me A Coffee Code Boxx eBooks
PHP SHOPPING CART
All right, let us now get into the steps of building a PHP shopping cart without a database.
PART 1) PRODUCTS LIST
$products = [
1 => ["name" => "Apple", "price" => 1.23, "image" => "apple.png"],
2 => ["name" => "Lemon", "price" => 2.34, "image" => "lemon.png"],
3 => ["name" => "Orange", "price" => 3.45, "image" => "orange.png"],
4 => ["name" => "Avocado", "price" => 4.32, "image" => "avocado.png"]
];
Since we don’t have a database, the only way is store products is to hardcode them in an array. This should be self-explanatory, the products are in the format of PRODUCT ID => [PRODUCT DETAILS]
.
PART 2) AJAX CART HANDLER
<?php
if (isset($_POST["req"])) {
// (A) INIT SHOPPING CART
session_start();
if (!isset($_SESSION["cartI"])) {
$_SESSION["cartI"] = []; // cart items
$_SESSION["cartC"] = 0; // total quantity
}
// (B) UPDATE CART COUNT
function ccount () {
$_SESSION["cartC"] = 0;
if (count($_SESSION["cartI"])!=0) {
foreach ($_SESSION["cartI"] as $id=>$qty) { $_SESSION["cartC"] += $qty; }
}
}
// (C) STANDARD SYSTEM RESPONSE
function respond ($status=1, $msg="OK") {
echo json_encode(["status"=>$status, "msg"=>$msg, "count" => $_SESSION["cartC"]]);
}
// (D) CART ACTIONS
switch ($_POST["req"]) {
// (D1) GET COUNT
case "count": respond(); break;
// (D2) ADD / CHANGE QUANTITY / REMOVE
// send id only to add item
// send id and qty to set quantity
// send id and 0 qty to remove item
case "set":
$max = 99; // max allowed quantity per item
$item = &$_SESSION["cartI"][$_POST["id"]];
if (isset($_POST["qty"])) { $item = $_POST["qty"]; }
else { if (isset($item)) { $item++; } else { $item = 1; } }
if ($item<=0) { unset($_SESSION["cartI"][$_POST["id"]]); } if ($item > $max) { $item = $max; }
ccount(); respond(); break;
// (D3) NUKE
case "nuke":
$_SESSION["cartI"] = [];
$_SESSION["cartC"] = 0;
respond(); break;
// (D4) GET ALL ITEMS IN CART
case "get":
// (D4-1) CART IS EMPTY
if ($_SESSION["cartC"]==0) { respond(1, null); break; }
// (D4-2) GET PRODUCTS + FILTER ILLEGAL
require "1-products.php";
$items = [];
foreach ($_SESSION["cartI"] as $id=>$qty) {
if (isset($products[$id])) {
$items[$id] = $products[$id];
$items[$id]["qty"] = $qty;
} else {
$_SESSION["cartC"] -= $_SESSION["cartI"][$id];
unset($_SESSION["cartI"][$id]);
}
}
if ($_SESSION["cartC"]==0) { respond(1, null); break; }
respond(1, $items); break;
// (D5) CHECKOUT
case "checkout":
// (D5-1) CART IS EMPTY
if ($_SESSION["cartC"]==0) { respond(0, "Cart Empty"); break; }
// (D5-2) EMAIL TO ADMIN
require "1-products.php";
$to = "admin@site.com";
$subject = "Order Received";
$body = "Name: " . $_POST["name"] . "\r\n";
$body .= "Email: " . $_POST["email"] . "\r\n";
foreach ($_SESSION["cartI"] as $id=>$qty) {
$body .= sprintf("%s X %s\r\n", $qty, $products[$id]["name"]);
}
if (mail($to, $subject, $body)) {
$_SESSION["cartI"] = [];
$_SESSION["cartC"] = 0;
respond();
} else { respond(0, "ERROR SENDING MAIL"); }
break;
}
}
Next, we build the shopping cart, the backbone of the system. It looks intimidating, but keep calm and look closely.
- (A) We keep the user’s shopping cart items in the PHP session.
$_SESSION["cartI"]
An array that contains the cart items in the format ofPRODUCT ID => QUANTITY
.$_SESSION["cartC"]
The total items quantity.
- (D) How the script work is very simple, just send the request
$_POST["req"]
and required parameters. For example,$_POST["req"]="set"
and$_POST["id"]=1
to add product ID 1 to the cart.
Request | Notes & Parameters |
count |
Get the total items quantity. |
set |
|
nuke |
Remove all items. |
get |
Get all items in cart. |
checkout |
|
PART 3) SHOPPING PAGE
3A) HTML SHOPPING PAGE
<!-- (A) PRODUCTS + SHOPPING CART -->
<div id="wrap">
<!-- (A1) HEADER -->
<div id="head">
<div id="iCart" onclick="cart.show()">
My Cart <span id="cCart">0</span>
</div>
</div>
<!-- (A2) PRODUCTS -->
<div id="products"><?php
require "1-products.php";
foreach ($products as $i=>$p) { ?>
<div class="pCell">
<img class="pImg" src="<?=$p["image"]?>">
<div class="pName"><?=$p["name"]?></div>
<div class="pPrice">$<?=$p["price"]?></div>
<input class="pAdd button" type="button" value="Add To Cart" onclick="cart.add(<?=$i?>)">
</div>
<?php } ?>
</div>
<!-- (A3) CART ITEMS -->
<div id="wCart">
<span id="wCartClose" class="button" onclick="cart.toggle(cart.hWCart, false)">⇦</span>
<h2>SHOPPING CART</h2>
<div id="cart"></div>
</div>
</div>
<!-- (B) CHECKOUT FORM -->
<div id="checkout"><form onsubmit="return cart.checkout()">
<div id="coClose" class="button" onclick="cart.toggle(cart.hCO, false)">X</div>
<label>Name</label>
<input type="text" id="coName" required value="Jon Doe">
<label>Email</label>
<input type="email" id="coEmail" required value="jon@doe.com">
<input class="button" type="submit" value="Checkout">
</form></div>
With the PHP foundations ready, we can now build the HTML page. This looks confusing once again, but the essential parts are:
- (A2)
<div id="products">
We load1-products.php
and draw the HTML products here. - (A3)
<div id="cart">
The current shopping cart. - (B)
<div id="checkout">
Checkout form.
3B) SHOPPING CART JAVASCRIPT
var cart = {
// (A) HELPER - AJAX FETCH
ajax : (data, after) => {
// (A1) FORM DATA
let form = new FormData();
for (let [k, v] of Object.entries(data)) { form.append(k, v); }
// (A2) FETCH
fetch("2-ajax-cart.php", { method:"POST", body:form })
.then(res => res.json())
.then(res => {
if (res.status==1) { after(res); }
else { alert(res.msg); }
})
.catch(err => console.error(err));
},
// (B) HELPER - TOGGLE HTML SECTIONS
toggle : (target, show) => {
if (show) { target.className = "show"; }
else { target.className = ""; }
},
// (C) INITIALIZE
hCart : null, // html cart
hWCart : null, // html cart wrapper
hCCart : null, // html cart count
hCO : null, // html checkout wrapper
init : () => {
// (C1) GET HTML ELEMENTS
cart.hCart = document.getElementById("cart");
cart.hWCart = document.getElementById("wCart");
cart.hCCart = document.getElementById("cCart");
cart.hCO = document.getElementById("checkout");
// (C2) UPDATE CART COUNT
cart.ajax({ req : "count" }, res => cart.count(res.count));
},
// (D) UPDATE CART COUNT
count : qty => {
cart.hCCart.innerHTML = qty;
if (cart.hWCart.classList.contains("show")) { cart.show(); }
},
// (E) SHOW CART ITEMS
show : () => {
// (E1) RESET
cart.toggle(cart.hWCart, true);
cart.hCart.innerHTML = "";
// (E2) LOAD & GENERATE HTML
cart.ajax({ req : "get" }, items => {
// (E2-1) ITEMS IN CART
items = items.msg;
// (E2-2) CART IS EMPTY
if (items==null) {
cart.hCart.innerHTML = `<div class="cCell empty">Cart is empty</div>`;
}
// (E2-3) DRAW CART ITEMS
else {
let row, subtotal, total = 0;
for (let [id, item] of Object.entries(items)) {
// CALCULATE SUBTOTAL
subtotal = item["price"] * item["qty"];
total += subtotal;
// ITEM ROW
row = document.createElement("div");
row.className = "cCell";
row.innerHTML = `<input class="cQty" type="number" value="${item["qty"]}"
min="0" max="99" onchange="cart.change(${id}, this.value)">
<div class="cInfo">
<div class="cName">${item["name"]}</div>
<div class="cPrice">$${subtotal.toFixed(2)}</div>
</div>
<input class="cDel button" type="button" value="X" onclick="cart.remove(${id})">`;
cart.hCart.appendChild(row);
}
// CART TOTALS
row = document.createElement("div");
row.className = "cCell";
row.innerHTML = `<input class="cDel button" type="button" value="X" onclick="cart.empty()">
<div class="cInfo">
<div class="cName">Total</div>
<div class="cPrice">$${total.toFixed(2)}</div>
</div>
<input class="cDel button" type="button" value=">" onclick="cart.toggle(cart.hCO, true)">`;
cart.hCart.appendChild(row);
}
});
},
// (F) ADD ITEM TO CART
add : id => cart.ajax(
{ req : "set", id : id },
res => cart.count(res.count)
),
// (G) CHANGE ITEM QTY
change : (id, qty) => cart.ajax(
{ req : "set", id : id, qty : qty },
res => cart.count(res.count)
),
// (H) REMOVE ITEM
remove : id => cart.ajax(
{ req : "set", id : id, qty : 0 },
res => cart.count(res.count)
),
// (I) NUKE
empty : () => { if (confirm("Reset cart?")) {
cart.ajax(
{ req : "nuke" },
res => cart.count(res.count)
);
}},
// (J) CHECKOUT
checkout : () => {
cart.ajax({
req : "checkout",
name : document.getElementById("coName").value,
email : document.getElementById("coEmail").value
}, res => location.href = "3c-thank-you.html");
return false;
}
};
window.onload = cart.init;
Not going to explain line by line, so here’s a quick summary.
- (A)
ajax()
A helper function to do an AJAX call to2-ajax-cart.php
. - (B)
toggle()
A helper function to toggle show/hide for the cart and checkout form. - (C)
init()
Runs on window load, pretty much just getting the HTML elements. - (D To J) All the cart actions.
count()
Update the total cart quantity.show()
Show the cart items.add()
Add an item to the shopping cart.change()
Change item quantity.remove()
Remove item from cart.empty()
Empty the entire cart.checkout()
Checkout.
3C) THANK YOU PAGE
<h1>Thank You</h1>
<p>Order received.</p>
Lastly, a dummy “thank you” on successful order.
EXTRAS
That’s all for the tutorial, and here is a small section on some extras and links that may be useful to you.
LINKS & REFERENCES
- PHP MYSQL Shopping Cart – Code Boxx
- HTML Javascript Shopping Cart – Code Boxx
A WAY BETTER SHOPPING CART
A shopping cart with product options, categories, discount coupons, user system, admin panel, API, and an installable web app - Click here to check out my eBook!
THE END
Thank you for reading, and we have come to the end. I hope that it has helped you to better understand, and if you want to share anything with this guide, please feel free to comment below. Good luck and happy coding!
First of all I really appreciate your work and its excellent to have the cart without database but the code above I found out that the function for Checkout not working. Could you please check and help.
https://code-boxx.com/faq#notwork
I check the console it stated that the syntax error in 3b-cart.js is not valid JSON mention the line fetch and catch. Im still learning as beginner I dont really have any ideas how to solve…
“Invalid JSON” can be anything. Divide and conquer, get more details on what went wrong first.