Customizing the AJAX-enabled Cart
From Shopp Documentation
Shopp has built-in support for AJAX, but has it disabled by default for the widest possible compatibility out-of-the-box. Shopp makes it easy to turn the AJAX-enabled cart on by customizing theme template files.
Contents |
How It Works
AJAX (asynchronous JavaScript and XML) is a term used to describe website development techniques for requesting and processing information in the background without requiring a page redirect (or refresh).
Shopp's shopping cart has support for returning information asyncronously back to the client (the web browser) using specially formatted cart requests via JavaScript. When activating the appropriate element (usually the Add to Cart button), the AJAX request is made to Shopp in the background and Shopp returns results back for the JavaScript to handle.
Enabling Basic AJAX
Shopp already has default AJAX request and handling routines built-in to send requests to the cart and handle responses from the cart. You'll need to make sure the sidebar cart is enabled by turning on the widget or adding the <?php shopp('cart','sidecart'); ?> tag to your WordPress theme's sidebar.php file directly. This is the cart display that will show the updates when an AJAX request is sent. To enable the AJAX add to cart behavior, simply find the shopp('product','addtocart') tags typically found in the category.php template file and product.php template file and add the ajax option like so:
<?php shopp('product','addtocart','ajax=on'); ?>
Now when visiting your store, clicking the Add to Cart buttons that have the ajax=on option will show the AJAX request in action. The product will be added to the cart in the background. At this point you'll see the default behavior for handling AJAX responses from Shopp. The item thumbnail will appear with the item name (variation name) and the unit price in the sidecart.
Customizing AJAX Behaviors
Shopp has two JavaScript functions for making and handling cart requests. Both functions are dependant on specific markup to work.
Each function can be overridden by your own JavaScript code. In your own JavaScript files called by your theme, you simply need to re-initalize the functions with your own code.
As of WordPress 2.8, Shopp's scripts are loaded in the footer instead of the header to improve the perceived performance of the site. As a result, in order to override the AJAX cart functions, you will need to ensure your JavaScript file containing your custom functions are loaded in the footer after Shopp's scripts. You can do this by using the WordPress wp_enqueue_script function like so:
wp_enqueue_script('handle','path/to/your/script.js',array('shopp'),'version',true);
- handle is a simple name for your script and can be anything you want to call it such as: theme-behaviors.
- path/to/your/script.js refers to the URI to your JavaScript file.
- shopp is referenced as a dependency, ensuring your script is loaded after Shopp's behaviors.
- version should be a version number for your script such as: 1.0
- true as the last argument will cause your script to be loaded in the footer instead of in the header.
ShoppCartAjaxRequest()
This is a wrapper function for making a request to the cart using AJAX. It calls another Shopp JavaScript function called cartajax() that does the actual AJAX request. When the ajax=on option is added to the shopp('product','addtocart') tag, this function is called and the appropriate default parameters are sent. The default function looks like this:
var ShoppCartAjaxRequest = function (url,data,response) { cartajax(url,data,response); }
As shown in the figure above, the function takes 3 parameters:
- url — the URL of the shopping cart to submit the request to
- data — the form data to pass along in the request in query string format (name=value&name=value)
- response — the type of response that Shopp should send back. By default this is set to json. Youcan also choose to get html back instead. When Shopp sends html updated back, it reprocesses the entire sidecart.php template and sends back the markup, updated with any changes to the cart back to the browser to replace the current sidecart element on the page (in the DOM).
By design, this function is meant to be overridable. You can replace it's functionality by writing your own version of the function in any of your theme's JavaScript files. For example, to override the function so that it forces Shopp to return html markup instead of json you would include something like the following in your JavaScript files:
ShoppCartAjaxRequest = function (url,data,response) { cartajax(url,data,'html'); }
This still retains the default passthru behavior of the original function, but now tells Shopp to return the data as re-interpreted (or updated) sidecart.php HTML markup.
ShoppCartAjaxHandler()
Unlike the ShoppCartAjaxRequest() function, this is not a wrapper function. It is directly responsible for taking a response from Shopp and updating the page (or more specifically, the DOM) with the new information. The default form of this function handles processing the default JSON response from Shopp then updates the sidecart to show the recently added product and updates the cart's totals. It relies heavily on the jQuery JavaScript Framework to make light of updating the DOM. For reference, here is what the built-in handler looks like:
var ShoppCartAjaxHandler = function (cart) { (function($) { var display = $('#shopp-cart-ajax'); display.empty().hide(); // clear any previous additions var item = $('<ul></ul>').appendTo(display); if (cart.Item.thumbnail) $('<li><img src="'+cart.Item.thumbnail.uri+'" alt="" width="'+cart.Item.thumbnail.width+'" height="'+cart.Item.thumbnail.height+'" /></li>').appendTo(item); $('<li></li>').html('<strong>'+cart.Item.name+'</strong>').appendTo(item); if (cart.Item.optionlabel.length > 0) $('<li></li>').html(cart.Item.optionlabel).appendTo(item); $('<li></li>').html(asMoney(cart.Item.unitprice)).appendTo(item); if ($('#shopp-cart-items').length > 0) { $('#shopp-cart-items').html(cart.Totals.quantity); $('#shopp-cart-total').html(asMoney(cart.Totals.total)); } else { $('.widget_shoppcartwidget p.status').html('<a href="'+cart.url+'"><span id="shopp-cart-items">'+cart.Totals.quantity+'</span> <strong>Items</strong> — <strong>Total</strong> <span id="shopp-cart-total">'+asMoney(cart.Totals.total)+'</span></a>'); } display.slideDown(); })(jQuery) }
Let's walk through how it works.
- First it finds the container element for the recently added product information to go, clears any existing content out and hides it to prepare it's display state for a slideout animation.
- Next it builds an <ul> list element to layout the product information display and adds each element to the DOM. The information getting added to the product display comes from the cart object that was sent back from Shopp. It contains a large amount of updated information about the state of the shopper's cart. The format of that object is explained in more detail later in this guide.
- Then it updates the total item quantity of the cart and subtotal of item costs repectively.
- The if statement is a simple state check. If the sidecart already has items, it simply updates the HTML of the approriate elements. Otherwise the cart will usually have a simple message telling the shopper "Your cart is empty" and none of the updatable elements will exist, so they need to be created from scratch and added to the DOM
AJAX Cart Response Object
Below is an outline of the structural properties of the response object returned when making an AJAX Cart request:
{ Contents: [Item, Item, Item...], // Array of items in the cart Item: { // Object of the recently added/update cart item category: 1, // ID of the category the item came from (if applicable) data: [], // Array of custom product data provided by any custom product inputs in the add-to-cart form description: "", // String containing the product description donation: {...}, // Donation settings object download: 1, // Download asset id freeshipping: "", // Whether the item has free shipping inventory: false, // Is inventory tracked on this product menus: {...}, // Product variation option menus name: "Product", // Name of the product option: {...}, // Selected variation option object optionlabel: "", // Name of the variation permutation price: 1, // ID of the product price record in the DB product: 1, // ID of the product record in the DB quantity: 1, // Number of quantity of the item in the cart sale: false, // Is the product on sale saved: 0, // Dollars (or other currency amount) saved if a promo price is available savings: 0, // Percentage savings if a promo price is available shipfee: 0, // Shipping handling fee mark-up (per unit) shipping: false, // Is a shipped item sku: "", // Stock Keeping Unit ID slug: "product", // Product permalink slug tax: 0, // Calculated tax for the item taxable: true, // Is taxable thumbnail: {...} // Product thumbnail image object total: 1.00000000, // Total price of the cart item (unit price x quantity) type: "Download", // Type of product/product variation unitprice: 1.0000, // Unit price of the product weight: 0 // Weight of a unit of the product }, Totals: { discount: 0, // Discount applied to the order quantity: 1, // Total quantity of products shipping: 1.00000, // Total (estimated) cost of shipping subtotal: 1.00000, // Total cost of all cart item totals tax: 0, // Calculated tax taxed: 0, // Is cart taxed taxrate: 0.15, // Tax rate percentage total: 1.000000 // Total cost of order (subtotal+(-discount)+shipping+tax) } url: "http://wordpress/shop/cart" // URL of the cart }
Handling HTML Responses
The default behavior handles JSON responses, but if you opt to just reprocess the entire sidecart.php template and return the HTML, you'll need to handle the response differently. In this case, override the default handler:
var ShoppCartAjaxHandler = function (cart) { jQuery('#shopp-cart-ajax').html(cart); }
This would need to be added to your active WordPresss theme in one of the theme's JavaScript files.
You'll also want to modify the sidecart.php template file. The default sidecart.php file includes the following line at the very top of the file:
<div id="shopp-cart-ajax"></div>Instead of it being on one line, wrap the entire sidecart.php file in that element:
<div id="shopp-cart-ajax"> <!-- ...existing contents of sidecart.php... --> </div>
This gives the custom HTML response handler a container it can easily hook on to and replace.
