Advertisement

Build An AJAX Powered Shopping Cart

by

This Cyber Monday Tuts+ courses will be reduced to just $3 (usually $15). Don't miss out.

The NETTUTS community asked for it. So here you are! One of the innovations of the web is online shopping. It allows us to buy things without ever leaving the comfort of our homes. However, the most basic element of online shopping, the shopping cart, has not evolved much. In this tutorial, we're going to make an AJAX powered shopping cart using PHP, jQuery, and a few nifty plugins.

Preface

The goal of this tutorial is to show you how to build an AJAX powered shopping cart. However, it will not be production ready. The back end requirements vary from site to site far too much to write an effective tutorial. Instead, we are going to focus on the AJAX parts. The back end code in this tutorial acts as scaffolding for us to build the AJAX functionality, however, it can be built off of to meet your own site's requirements. In the last section, we'll discuss some possible next steps to implementing this in your own websites.

The other thing to note is that this tutorial will not explain all the details. A firm grasp of HTML, CSS, and some basic PHP is expected. By basic I mean variables, arrays, control structures, and basic OOP. Some knowledge of Javascript is a plus. We'll walk through and break down the trickier bits of PHP and Javascript, but will gloss over the basic stuff like CSS styling. Links to documentation and other relevant resources will be sprinkled throughout wherever relevant.

The final thing to note is that the order codes (or product codes) used in this tutorial are completely arbitrary.

The Demo

The demo page shows a few different ways our AJAX shopping cart can function. It should be noted that this is not a production ready shopping cart. Due to variability of the requirements from site to site, this tutorial will only cover building the skeleton while you will have to code in the details for retrieving product names, prices, and other data that might come from a database.

Step 1 - Downloading the scripts

We're going to be using jQuery, the jQuery
color animations plugin
, and Thickbox. The color plugin extends jQuery to allow us to use jQuery to animate colors and Thickbox lets us create quick and easy modal windows.

Create a directory on your web server for the cart to live in. For this tutorial we'll be using cart/. Substitute cart/ with the directory you are using on your server. Inside the cart/ directory create js/, css/, and images/ folders for storing your Javascript, CSS, and images.

Download the jQuery, color plugin, and Thickbox files and save them into the appropriate folders we just created in the cart/ directory. Make sure you download the uncompressed thickbox.js.

Your folder structure should look something like this. I have renamed some of the files but it should be pretty obvious what each one is.

cart/js/jquery-1.2.6.pack.js
cart/js/jquery.color.js
cart/js/thickbox.js
cart/css/thickbox.css
cart/images/loadingAnimation.gif
cart/images/macFFBgHack.png

Step 2 - Setup Thickbox

Since our folder structure is a little different from the default Thickbox one, we're going to need to fix some of the paths referencing loadingAnimation.gif and macFFBgHack.png.

Open thickbox.js and you'll see the following line of code after the comments (line 8):

var tb_pathToImage = "images/loadingAnimation.gif";

Change that to the following so it references the loadingAnimation.gif file correctly:

var tb_pathToImage = "../images/loadingAnimation.gif";

Next open up thickbox.css and find the line that says (line 37):

.TB_overlayMacFFBGHack {background: url(macFFBgHack.png) repeat;}

And change it to:

.TB_overlayMacFFBGHack {background: url(../images/macFFBgHack.png) repeat;}

Step 3 - The Shopping_Cart class

We will create a class to handle all the different actions such as adding items to the cart and saving the cart. The following is the code for the Shopping_Cart class we'll be using for this tutorial. Again, this is very barebones intentionally because the backend requirements will be different from site to site. Since there isn't much code, I will not explain each and every method and instead let the comments do the explaining. Save this as shopping_cart.class.php. We'll take a look at how to use this class in the next step when we create a sample load script.

<?php

class Shopping_Cart {
	var $cart_name;       // The name of the cart/session variable
	var $items = array(); // The array for storing items in the cart
	
	/**
	 * __construct() - Constructor. This assigns the name of the cart
	 *                 to an instance variable and loads the cart from
	 *                 session.
	 *
	 * @param string $name The name of the cart.
	 */
	function __construct($name) {
		$this->cart_name = $name;
		$this->items = $_SESSION[$this->cart_name];
	}
	
	/**
	 * setItemQuantity() - Set the quantity of an item.
	 *
	 * @param string $order_code The order code of the item.
	 * @param int $quantity The quantity.
	 */
	function setItemQuantity($order_code, $quantity) {
		$this->items[$order_code] = $quantity;
	}
	
	/**
	 * getItemPrice() - Get the price of an item.
	 *
	 * @param string $order_code The order code of the item.
	 * @return int The price.
	 */
	function getItemPrice($order_code) {
		// This is where the code taht retrieves prices
		// goes. We'll just say everything costs $19.99 for this tutorial.
		return 9.99;
	}
	
	/**
	 * getItemName() - Get the name of an item.
	 *
	 * @param string $order_code The order code of the item.
	 */
	function getItemName($order_code) {
		// This is where the code that retrieves product names
		// goes. We'll just return something generic for this tutorial.
		return 'My Product (' . $order_code . ')';
	}
	
	/**
	 * getItems() - Get all items.
	 *
	 * @return array The items.
	 */
	function getItems() {
		return $this->items;
	}
	
	/**
	 * hasItems() - Checks to see if there are items in the cart.
	 *
	 * @return bool True if there are items.
	 */
	function hasItems() {
		return (bool) $this->items;
	}
	
	/**
	 * getItemQuantity() - Get the quantity of an item in the cart.
	 *
	 * @param string $order_code The order code.
	 * @return int The quantity.
	 */
	function getItemQuantity($order_code) {
		return (int) $this->items[$order_code];
	}
	
	/**
	 * clean() - Cleanup the cart contents. If any items have a
	 *           quantity less than one, remove them.
	 */
	function clean() {
		foreach ( $this->items as $order_code=>$quantity ) {
			if ( $quantity < 1 )
				unset($this->items[$order_code]);
		}
	}
	
	/**
	 * save() - Saves the cart to a session variable.
	 */
	function save() {
		$this->clean();
		$_SESSION[$this->cart_name] = $this->items;
	}
}

?>

Step 4 - load.php

Before we do anything else, we're going to create a simple script that loads some sample items into the cart. This will make building the actual cart page easier. Let's name this file load.php and save it in the cart/ directory.

<?php
	include('shopping_cart.class.php');
	session_start();
	$Cart = new Shopping_Cart('shopping_cart');
	
	$Cart->setItemQuantity('HSD-KSE', 2);
	$Cart->setItemQuantity('KLS-IEN', 1);
	$Cart->setItemQuantity('ELS-OWK', 4);
	
	$Cart->save();
	
	header('Location: cart.php');
?>

The first three lines include the shopping cart class we created in the previous step, start the session so we can save the cart, and create a new Shopping_Cart instance. These three lines will be at the top of any file that needs to access the shopping cart. Notice how on line 3 I pass a single parameter, 'shopping_cart', when I create the Shopping_Cart instance. 'shopping_cart' gets passed to the constructor of the class, which sets the instance variable $cart_name. This is the name of the session variable that we will be storing all the cart data. The reason we do this is to avoid conflicts with other carts.

The rest of the code simply adds three items to the cart, saves them, and redirects the user to the cart itself which we'll be building in the next step. Methods (which are basically functions) in a class are accessed using a special arrow syntax.

Step 5 - Building the cart

We're going to build the cart, but without the AJAX functionality first, so that in the event that the user has Javascript disabled, she will still be able to use the cart. This is important, because we want her to buy something and she won't be able to do that if it doesn't degrade well when Javascript is disabled!

<?php
	include('shopping_cart.class.php');
	session_start();
	$Cart = new Shopping_Cart('shopping_cart');
?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
	<head>
		<title>Shopping Cart</title>

		<script src="js/jquery-1.2.6.pack.js" type="text/javascript"></script>
		<script src="js/jquery.color.js" type="text/javascript"></script>
		<script src="js/cart.js" type="text/javascript"></script>
		<link href="css/cart.css" rel="stylesheet" type="text/css" media="screen" />
	</head>

	<body>
		<div id="container">
			<h1>Shopping Cart</h1>
			<?php if ( $Cart->hasItems() ) : ?>
			<form action="cart_action.php" method="get">

				<table id="cart">
					<tr>
						<th>Quantity</th>
						<th>Item</th>
						<th>Order Code</th>

						<th>Unit Price</th>
						<th>Total</th>
						<th>Remove</th>
					</tr>

					<?php
						$total_price = $i = 0;
						foreach ( $Cart->getItems() as $order_code=>$quantity ) :
							$total_price += $quantity*$Cart->getItemPrice($order_code);
					?>
						<?php echo $i++%2==0 ? "<tr>" : "<tr class='odd'>"; ?>
							<td class="quantity center"><input type="text" name="quantity[<?php echo $order_code; ?>]" size="3" value="<?php echo $quantity; ?>" tabindex="<?php echo $i; ?>" /></td>

							<td class="item_name"><?php echo $Cart->getItemName($order_code); ?></td>
							<td class="order_code"><?php echo $order_code; ?></td>
							<td class="unit_price">$<?php echo $Cart->getItemPrice($order_code); ?></td>

							<td class="extended_price">$<?php echo ($Cart->getItemPrice($order_code)*$quantity); ?></td>
							<td class="remove center"><input type="checkbox" name="remove[]" value="<?php echo $order_code; ?>" /></td>
						</tr>

					<?php endforeach; ?>
					<tr><td colspan="4"></td><td id="total_price">$<?php echo $total_price; ?></td></tr>
				</table>
				<input type="submit" name="update" value="Update cart" />

			</form>

			<?php else: ?>
				<p class="center">You have no items in your cart.</p>
			<?php endif; ?>
			<p><a href="load.php">Load Sample Cart</a></p>

		</div>
	</body>
</html>

Here we just show the items in the cart in a nicely formatted table with some form controls for removing items and changing the quantities. On line 18 we check to see if there are items in the cart. If there are, we go ahead and create the table. If not, we show a simple message letting the user know she doesn't have any items in her cart. I'm using the alternative syntax for if...else statements.

This chunk of code might look intimidating but it's pretty simple if we break it down:

<?php
	$total_price = $i = 0;
	foreach ( $Cart->getItems() as $order_code=>$quantity ) :
		$total_price += $quantity*$Cart->getItemPrice($order_code);
?>

	<?php echo $i++%2==0 ? "<tr>" : "<tr class='odd'>"; ?>
		<td class="quantity center"><input type="text" name="quantity[<?php echo $order_code; ?>]" size="3" value="<?php echo $quantity; ?>" tabindex="<?php echo $i; ?>" /></td>

		<td class="item_name"><?php echo $Cart->getItemName($order_code); ?></td>
		<td class="order_code"><?php echo $order_code; ?></td>
		<td class="unit_price">$<?php echo $Cart->getItemPrice($order_code); ?></td>

		<td class="extended_price">$<?php echo ($Cart->getItemPrice($order_code)*$quantity); ?></td>
		<td class="remove center"><input type="checkbox" name="remove[]" value="<?php echo $order_code; ?>" /></td>
	</tr>

<?php endforeach; ?>

First we set the total price ($total_price) and a row counting variable ($i) to 0. Then we dive into a foreach loop that creates a row in the table for each item. Here's a run down of what happens inside the loop:

  1. Add the extended price (quantity * unit price) to the total price.

    $total_price += $quantity*$Cart->getItemPrice($order_code);
  2. Echo out the opening <tr> tag. If the row count is odd, include a class called "odd". This is for the zebra striping that will make browsing the cart easier. Here we use the ternary operator (?:) as a shortcut to a full if...else statement.

    echo $i++%2==0 ? "<tr>" : "<tr class='odd'>";
  3. Echo out the input quantity field. The name of the input field is formatted (quantity[ORDER-CODE]) so PHP will automatically convert it into an array. We reuse the row count ($i) to add a tab index.

    <td class="quantity center"><input type="text" name="quantity[<?php echo $order_code; ?>]" size="3" value="<?php echo $quantity; ?>" tabindex="<?php echo $i; ?>" /></td>
  4. Echo out the item name, order code, unit price, and extended price.

    <td class="item_name"><?php echo $Cart->getItemName($order_code); ?></td>
    <td class="order_code"><?php echo $order_code; ?></td>
    <td class="unit_price">$<?php echo $Cart->getItemPrice($order_code); ?></td>
    
    <td class="extended_price">$<?php echo ($Cart->getItemPrice($order_code)*$quantity); ?></td>
  5. Echo out the remove item checkbox. Notice again, the specially formatted name of the checkbox input element.

    <td class="remove center"><input type="checkbox" name="remove[]" value="<?php echo $order_code; ?>" /></td></td>
    
    </ol>
    <p>Afer the foreach loop we echo out another row that shows the total price of all the items in the cart. I've also added a link to the load.php we created in the previous step so we can load in sample data for testing easily.</p>
    
    <h3>Step 6 - Styling the cart</h3>
    <p>The cart looks a little plain at the moment so lets give it some styling. Save the CSS code as cart.css in cart/css/ folder. This will give the cart some color and formatting so that it's easier on the eyes.</p>
    <pre name="code" class="css">body {
    	color: #222;
    	font: 0.8em Arial, Helvetica, sans-serif;
    }
    
    h1 {
    	font: 2em normal Arial, Helvetica, sans-serif;
    	margin-bottom: 0.5em;
    }
    
    #container {
    	margin: 0 auto;
    	width: 80%;
    }
    
    table#cart {
    	border-collapse: collapse;
    	margin-bottom: 1em;
    	width: 100%;
    }
    	
    	table#cart th {
    		background: #006b68;
    		color: #fff;
    		text-align: left;
    		white-space: nowrap;
    	}
    	
    	table#cart th,
    	table#cart td {
    		padding: 5px 10px;
    	}
    	
    	table#cart .item_name {
    		width: 100%;
    	}
    	
    	table#cart .quantity input {
    		text-align: center;
    	}
    	
    	table#cart tr td {
    		background: #fff;
    	}
    	
    	table#cart tr.odd td {
    		background: #eee;
    	}
    	
    	.center {
    		text-align: center;
    	}

    Step 7 - Processing the cart

    Now we need to write the script that handles adding, removing, and setting quantities for items. Save this one as cart_action.php in the cart/ folder.

    <?php
    
    include('shopping_cart.class.php');
    session_start();
    $Cart = new Shopping_Cart('shopping_cart');
    
    if ( !empty($_GET['order_code']) && !empty($_GET['quantity']) ) {
    	$quantity = $Cart->getItemQuantity($_GET['order_code'])+$_GET['quantity'];
    	$Cart->setItemQuantity($_GET['order_code'], $quantity);
    }
    
    if ( !empty($_GET['quantity']) ) {
    	foreach ( $_GET['quantity'] as $order_code=>$quantity ) {
    		$Cart->setItemQuantity($order_code, $quantity);
    	}
    }
    
    if ( !empty($_GET['remove']) ) {
    	foreach ( $_GET['remove'] as $order_code ) {
    		$Cart->setItemQuantity($order_code, 0);
    	}
    }
    
    $Cart->save();
    
    header('Location: cart.php');
    
    ?>

    This is another fairly simple script. There are three if statements to check for adding items, setting quantities, and removing items. Here's where the special formatting on the input field names comes in play. PHP will automatically convert input field names with brackets into arrays. So if we do a var_dump() of $_GET on the update cart form submission, you might get something that looks like this:

    array(3) {
      ["quantity"]=>
      array(3) {
        ["HSD-KSE"]=>
        string(1) "2"
        ["KLS-IEN"]=>
        string(1) "1"
        ["KWL-JFE"]=>
        string(1) "9"
      }
      ["remove"]=>
      array(2) {
        [0]=>
        string(7) "KLS-IEN"
        [1]=>
        string(7) "KWL-JFE"
      }
      ["update"]=>
      string(11) "Update cart"
    }

    Since all the new quantities and items to be removed are in arrays, we can simply loop over them using a foreach loop and call the appropriate functions. The first if statement adds new items to the cart, the second changes item quantities, and the third removes items.

    At this point, we have a functioning shopping cart without the AJAX. Pretty boring so far, but we'll be adding in the AJAX in the next step.

    Step 8 - Adding AJAX

    The first thing we need to do is link jQuery, the color animation plugin, and our own javascript, which we will be creating in a little bit, to the cart. Open up cart.php again and add the following lines inside the <head></head> tags.

    <script src="js/jquery-1.2.6.pack.js" type="text/javascript"></script>
    <script src="js/jquery.color.js" type="text/javascript"></script>
    <script src="js/cart.js" type="text/javascript"></script>

    Now create a file called cart.js inside the cart/js/ folder. This is where we will be putting our own Javascript code that enables all the AJAX functionality. Inside it, add the following code.

    $(function() {
    	$("#cart tr .remove input").click(function() {
    		var orderCode = $(this).val();
    		$.ajax({
    			type: "GET",
    			url: "cart_action.php",
    			data: "remove[]=" + orderCode,
    			success: function() {
    				$("#cart tr .remove input[value=" + orderCode + "]").parent().parent().fadeOut(500, function() {
    					$(this).remove();
    					calcPrice();
    				});
    			},
    			error: function() {
    				window.location("cart_action.php?remove[]="+orderCode);
    			}
    		});
    	});
    	
    	$("#cart tr .quantity input").change(function() {
    		var orderCode = $(this).attr("name").slice(9, -1);
    		var quantity = $(this).val();
    		$.ajax({
    			type: "GET",
    			url: "cart_action.php",
    			data: "quantity[" + orderCode + "]=" + quantity,
    			success: function() {
    				var startColor = $("#cart tr .quantity input[name*=" + orderCode + "]").parent().parent().hasClass("odd") ? "#eee" : "#fff";
    				$("#cart tr .quantity input[name*=" + orderCode + "]").parent().parent().find("td").animate({ backgroundColor: "#ff8" }, 100).animate({ backgroundColor: startColor }, 800);
    				calcPrice();
    			},
    			error: function() {
    				window.location("cart_action.php?quantity[" + orderCode + "]=" + quantity);
    			}
    		});
    	});
    });
    
    function calcPrice() {
    	var totalPrice = 0;
    	$("#cart tr .quantity").parent().each(function() {
    		var quantity = $(".quantity input", this).val();
    		var unitPrice = $(".unit_price", this).text().slice(1);
    		var extendedPrice = quantity*unitPrice;
    		totalPrice += extendedPrice;
    		
    		$(".extended_price", this).html("$" + extendedPrice);
    		$("#total_price").html("$"+totalPrice);
    	});
    	if ( totalPrice == 0 ) {
    		$("#cart").parent().replaceWith("<p class='center'>You have no items in your cart.</p>");
    	}
    }

    This jumble of code looks rather intimidating too, but it can be divided into three distinct blocks: the block that handles the remove checkboxes, the block that handles the quantity fields, and the last block that recalculates all the prices when a an item is removed or a quantity is changed. The first two blocks are contained in a function that looks like this:

    $(function() {
    	// Code goes here...
    });

    Code that goes inside this function is executed once the DOM has been loaded. It's a shortcut to the $(document).ready(callback) function.

    The first block of code that goes inside that aforementioned function handles the remove checkboxes:

    $("#cart tr .remove input").click(function() {
    	var orderCode = $(this).val();
    	$.ajax({
    		type: "GET",
    		url: "cart_action.php",
    		data: "remove[]=" + orderCode,
    		success: function() {
    			$("#cart tr .remove input[value=" + orderCode + "]").parent().parent().fadeOut(500, function() {
    				$(this).remove();
    				calcPrice();
    			});
    		},
    		error: function() {
    			window.location("cart_action.php?remove[]="+orderCode);
    		}
    	});
    });

    This binds a function to the click event of all the checkboxes. When a checkbox is clicked, a couple things happen:

    1. Grab the order code and store it in a variable.

      var orderCode = $(this).val();
    2. Make an AJAX call to the server, telling it to remove the item. If you read Eric's tutorial on submitting forms without refreshing a page, this will look familiar. The data that is submitted is exactly the same as if we did a form submission. The data parameter is identical to the GET string we would see if we removed the redirect in cart_action.php and did an update cart form submission. If the AJAX call is successful, we fade out the row with the item we want to remove and then remove it completely from the DOM. Then we call the calcPrice() function (the third block of code) to recalculate all the prices. If the call was unsuccessful, we fallback to a page refresh.

    The second block of code is very similar except it sets the quantities:

    $("#cart tr .quantity input").change(function() {
    	var orderCode = $(this).attr("name").slice(9, -1);
    	var quantity = $(this).val();
    	$.ajax({
    		type: "GET",
    		url: "cart_action.php",
    		data: "quantity[" + orderCode + "]=" + quantity,
    		success: function() {
    			var startColor = $("#cart tr .quantity input[name*=" + orderCode + "]").parent().parent().hasClass("odd") ? "#eee" : "#fff";
    			$("#cart tr .quantity input[name*=" + orderCode + "]").parent().parent().find("td").animate({ backgroundColor: "#ff8" }, 100).animate({ backgroundColor: startColor }, 800);
    			calcPrice();
    		},
    		error: function() {
    			window.location("cart_action.php?quantity[" + orderCode + "]=" + quantity);
    		}
    	});
    });

    Here we bind a function to the change event of all the quantity input fields that will execute an AJAX call whenever the quantities are changed. Let's break it down:

    1. Retrieve and store the order code and the new quantity.

      var orderCode = $(this).attr("name").slice(9, -1);
      var quantity = $(this).val();
    2. Make an AJAX call to the server telling it to update the specified quantity. If the call is successful, we make the background color of the row "blink" yellow for a second to let the user know the quantity has been changed, then call the calcPrice() function to recalculate all the prices. If the call is unsuccessful, fall back to a page refresh.

    And finally the third block of code, which we've seen been called twice already: the calcPrice() function.

    function calcPrice() {
    	var totalPrice = 0;
    	$("#cart tr .quantity").parent().each(function() {
    		var quantity = $(".quantity input", this).val();
    		var unitPrice = $(".unit_price", this).text().slice(1);
    		var extendedPrice = quantity*unitPrice;
    		totalPrice += extendedPrice;
    		
    		$(".extended_price", this).html("$" + extendedPrice);
    		$("#total_price").html("$"+totalPrice);
    	});
    	if ( totalPrice == 0 ) {
    		$("#cart").parent().replaceWith("<p class='center'>You have no items in your cart.</p>");
    	}
    }

    This is simple as well. We loop through each row and recalculate the extended price and total price. Let's break it down what happens inside each loop:

    1. First retrieve the quantity and unit price of the item and multiply them to get the extended price. Then add it to the running total price which starts at zero.

      var quantity = $(".quantity input", this).val();
      var unitPrice = $(".unit_price", this).text().slice(1);
      var extendedPrice = quantity*unitPrice;
      totalPrice += extendedPrice;
    2. Update the extended price for the current row and the total price with the running total.

      $(".extended_price", this).html("$" + extendedPrice);
      $("#total_price").html("$"+totalPrice);
    3. If after we finish looping through the columns we find that all the items have been removed, replace the cart view with a message saying the cart is empty.

      if ( totalPrice == 0 ) {
      	$("#cart").parent().replaceWith("<p class='center'>You have no items in your cart.</p>");
      }

    One thing to note is the selector I use to retrieve the rows in the table. I select all the table cells with the class of "quantity" and then call the parent() function to get the rows. This is because the table headers are also stored in a row. If we simply used "#cart tr", we would get the table headers as well.

    Step 9 - "Add to cart"

    No cart is complete without a way to add new items to the cart, so we're going to create an index page that shows off two different ways you can do just that. While we're at it, we're going to enable Thickbox so that the cart opens up in a modal window rather than going to a new page.

    Let's create the page and then break it down. Save the following as index.html in the cart/ folder.

    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
    <html xmlns="http://www.w3.org/1999/xhtml">
    	<head>
    		<title>Shopping Cart</title>
    
    		<script src="js/jquery-1.2.6.pack.js" type="text/javascript"></script>
    		<script src="js/jquery.color.js" type="text/javascript"></script>
    		<script src="js/thickbox.js" type="text/javascript"></script>
    		<script src="js/cart.js" type="text/javascript"></script>
    		<link href="css/style.css" rel="stylesheet" type="text/css" media="screen" />
    
    		<link href="css/thickbox.css" rel="stylesheet" type="text/css" media="screen" />
    		
    		<script type="text/javascript">
    			$(function() {
    				$("form.cart_form").submit(function() {
    					var title = "Your Shopping Cart";
    					var orderCode = $("input[name=order_code]", this).val();
    					var quantity = $("input[name=quantity]", this).val();
    					var url = "cart_action.php?order_code=" + orderCode + "&quantity=" + quantity + "&TB_iframe=true&height=400&width=780";
    					tb_show(title, url, false);
    					
    					return false;
    				});
    			});
    		</script>
    	</head>
    
    	<body>
    		<div id="container">
    			<h1>Shopping Cart Demo</h1>
    			<a href="cart.php?KeepThis=true&TB_iframe=true&height=400&width=780" title="Your Shopping Cart" class="thickbox">Open Cart</a>
    
    			<hr />
    			<a href="cart_action.php?order_code=KWL-JFE&quantity=3&TB_iframe=true&height=400&width=780" title="Your Shopping Cart" class="thickbox">Add three KWL-JFE to cart</a>
    			<hr />
    			<form class="cart_form" action="cart_action.php" method="get">
    
    				<input type="hidden" name="order_code" value="KWL-JFE" />
    				<label>KWL-JFE: <input class="center" type="text" name="quantity" value="1" size="3" ?></label>
    				<input type="submit" name="submit" value="Add to cart" />
    			</form>
    		</div>
    
    	</body>
    </html>

    If you take a look at the code between the <head></head> tags you'll notice I've included two more files, thickbox.js and thickbox.css, and added some more Javascript. Let's talk about the Thickbox bits first.

    Thickbox converts links with a class of "thickbox" into a link that opens up in a modal window. The different options for the modal window are defined in the GET string of the URL. The different options are detailed in the examples section of the Thickbox site. For our shopping cart, we are interested in opening iFramed content in a modal window.

    To open iFrame content we use the following parameters in the URL:

    ?KeepThis=true&TB_iframe=true&height=400&width=600

    The first two parameters, KeepThis and TB_iframe, are constant but the other two define the height and width of the modal window. We'll make ours 780px wide and 400px tall. Our open cart link will look like this (don't forget to set the class to "thickbox" or it won't work!):

    <a href="cart.php?KeepThis=true&TB_iframe=true&height=400&width=780" title="Your Shopping Cart" class="thickbox">Open Cart</a>

    Another thing to note is that the title attribute of the link will be displayed as the title of the modal window.

    The next link will add an item to the cart in addition to opening it. To do this we have to pass two more parameters in the GET query string: order_code and quantity. However, these two parameters need to come before the KeepThis parameter in the query--Thickbox automatically removes all parameters after the KeepThis parameter. The URL should look something like this:

    cart_action.php?order_code=KWL-JFE&quantity=1&TB_iframe=true&height=400&width=780

    This URL will add a single item with the order code of KWL-JFE. The cart_action.php script we wrote previously will look for the order code and quantity parameters and add them to the cart accordingly.

    The second way we can add items to the cart is by form that lets the user specify the quantity. However, since we want the cart to open up in a Thickbox, we have to use a bit of Javascript. Between the <head></head> tags you'll notice we have some Javascript that executes once the DOM has been loaded:

    <script type="text/javascript">
    	$(function() {
    		$("form.cart_form").submit(function() {
    			var title = "Your Shopping Cart";
    			var orderCode = $("input[name=order_code]", this).val();
    			var quantity = $("input[name=quantity]", this).val();
    			var url = "cart_action.php?order_code=" + orderCode + "&quantity=" + quantity + "&TB_iframe=true&height=400&width=780";
    			tb_show(title, url, false);
    			
    			return false;
    		});
    	});
    
    </script>

    This code looks for forms with a class of "cart_form" and binds a function to the submit event. The handler can be broken down as follows:

    1. Set the title of the window and get the order code and quantity from the form fields.
    2. Build a URL with order_code, quantity, and the Thickbox parameters.
    3. Open a Thickbox modal window.
    4. Return false to stop the form submission.

    Finally, we'll add a little bit of CSS to give it some style. Save the following code as style.css in the cart/css/ folder.

    body {
    	color: #222;
    	font: 0.8em Arial, Helvetica, sans-serif;
    }
    
    h1 {
    	font: 2em normal Arial, Helvetica, sans-serif;
    	margin-bottom: 0.5em;
    }
    
    #container {
    	margin: 0 auto;
    	width: 80%;
    }
    
    table#cart {
    	border-collapse: collapse;
    	margin-bottom: 1em;
    	width: 100%;
    }
    	
    	table#cart th {
    		background: #006b68;
    		color: #fff;
    		text-align: left;
    		white-space: nowrap;
    	}
    	
    	table#cart th,
    	table#cart td {
    		padding: 5px 10px;
    	}
    	
    	table#cart .item_name {
    		width: 100%;
    	}
    	
    	table#cart .quantity input {
    		text-align: center;
    	}
    	
    	table#cart tr td {
    		background: #fff;
    	}
    	
    	table#cart tr.odd td {
    		background: #eee;
    	}
    	
    	.center {
    		text-align: center;
    	}

    The final product

    You're done! Well, you're done with this tutorial. There is still some coding that needs to be done to adapt this to the requirements of your site.

    Next steps

    As I've mentioned several times before, there are still some key parts of the cart we just created that are missing. These parts depend on the requirements of your site. For instance: most online shopping sites will have a database storing all the product information, but the structure of this database varies widely. Methods in the Shopping_Cart class that retrieve item names, prices, and other information will need database code.

    Another important thing to add is input validation. Since much of the data is passed along via GET, it would not be hard for someone to start putting in random order codes and non-numeric quantities. These two things should definitely be validated before adding an item to the cart.

Advertisement