Documentation You are here: start » v » 0.7.0 » advanced » json

JSON and JSONP with FoxyCart

What is JSON?

JSON stands for JavaScript Object Notation 1), and can be thought of as a very flexible method to store data. Conceptually it is similar to XML, but since it's actually a javascript object it's trivially easy to work with in javascript (whereas XML requires much more work to process by javascript).

FoxyCart's JSON looks like this:

{
	"products":[
		{
			"id": "3045365",
			"name": "Test Product",
			"code": "foo123",
			"image": "",
			"url": "",
			"length": "0",
			"width": "0",
			"height": "0",
			"options": {"color":"red"},
			"quantity": 1,
			"price_each": 10,
			"price": 10,
			"weight_each": 1,
			"weight": 1,
			"shipto": "",
			"category": "DEFAULT",
			"sub_frequency": "",
			"sub_startdate": "0000-00-00",
			"sub_nextdate": "0000-00-00",
			"sub_enddate": "0000-00-00"
		},
		{
			"id": "3045366",
			"name": "Second Product",
			"code": "bar456",
			"image": "",
			"url": "",
			"length": "0",
			"width": "0",
			"height": "0",
			"options": {},
			"quantity": 1,
			"price_each": 100,
			"price": 100,
			"weight_each": 1,
			"weight": 1,
			"shipto": "",
			"category": "DEFAULT",
			"sub_frequency": "",
			"sub_startdate": "0000-00-00",
			"sub_nextdate": "0000-00-00",
			"sub_enddate": "0000-00-00"
		},
		{
			"id": "3045367",
			"name": "Example Subscription",
			"code": "xyz456",
			"image": "",
			"url": "",
			"length": "0",
			"width": "0",
			"height": "0",
			"options": {"color":"red"},
			"quantity": 1,
			"price_each": 6,
			"price": 6,
			"weight_each": 4,
			"weight": 4,
			"shipto": "",
			"category": "DEFAULT",
			"sub_frequency": "1m",
			"sub_startdate": "2010-10-15",
			"sub_nextdate": "2010-11-15",
			"sub_enddate": "2013-01-01"
		}
	],
	"product_count": 3,
	"total_item_price": 116,
	"total_discount": -5,
	"total_price": 111,
	"total_weight": 6,
	"session_id": "9bpdjvm2ju0bulm6d7kkcf6d31",
	"coupons":{
		"test2":{
			"id":"201",
			"name":"test for line item coupon discount",
			"discount":-5}
	},
	"custom_fields":{
		"my_hidden_value":"I'm hidden!",
		"example_hidden":"value_1"
	},
	"messages":{
		"errors":[],
		"warnings":[],
		"info":[]
	}
}

What is JSONP?

JSONP is a magical tool that allows for relatively easy cross-domain javascript calls, which is impossible in most other ways (barring HTML5 functionality). We recommend getting a thororugh understanding, but the basic idea is this: You make a call to an endpoint (your FoxyCart cart) and you get back JSON wrapped inside of a function call. The reason for the function is so that your javascript can actually do something with the JSON you retrieve.

jQuery makes this easy, so let's try a quick example of retrieving the total number of products and the total cart price, less any discounts.

jQuery.getJSON('https://'+storedomain+'/cart?'+fcc.session_get()+'&output=json&callback=?', function(cart) {
	console.info(cart.product_count);
	console.info(cart.total_price);
	console.info(cart.total_discount);
	var total_price = cart.total_price - cart.total_discount;
	console.log('You have '+cart.product_count+' products in your cart, totalling $'+total_price+' (which is after a $'+cart.total_discount+' discount).');
});

To try this out:

  1. Use Firefox to open up your website to a page where you have FoxyCart-powered add-to-cart links or forms.
  2. Add a product to your cart.
  3. Open Firebug's “console” tab and paste the above code into the command line, then run it.
  4. Look at your “Net” tab in Firebug to examine the request and response. Notice how the request substituted the ? in the callback=? with something like jsonp1287171163698. Then notice that the JSON response is wrapped inside a jsonp1287171163698() function call. That's the magic of JSONP.

What it's actually doing is using jQuery's getJSON method to request your cart URL. The fcc.session_get() is inserting the FoxyCart session, so the right cart is actually retrieved, the output=json tells FoxyCart to return JSON and not the normal HTML cart, and the callback=? tells both FoxyCart and jQuery that it's a JSONP request. More about the output and callback parameters are on the cheat sheet#transaction_non-product_specific_options.

The function(cart) bit is the “callback”, and is run once the JSON is ready to be processed (after a momentary delay to actually make the request from the FoxyCart servers). It is passed in cart, so you access the JSON as cart in the callback function. (This could just as easily be data or foo or ilovepuppies. The important thing is that it's consistent, but data is a good choice. We've used cart in the example to make it clear that you're basically playing with the cart data itself.)

Modifying or Removing Items with JSONP

If you want to update the quantity of a specific item, send this:

&cart=update&quantity=<new quantity>&id=<product id from json>

If you want to modify multiple quantities at once you can prefix the separate products with a number prefix, similar to adding multiple products to the cart at the same time. Note that if you take this approach you must start at 1 and count up from there.

&cart=update&1:quantity=0&1:id=<product id from json>&2:quantity=0&2:id=<product id from json>

Note that the cart=update is required for these operations to function.

Unfortunately, modifying products in the cart beyond the quantity is not currently possible.

Adding a Coupon or Session Value Automatically Using JSONP

If you want to add a coupon code, affiliate tracking value, member group, user ID, or any other value to your visitor's FoxyCart session automatically and in the background you could use something like this:

<script type="text/javascript" charset="utf-8">
jQuery(document).ready(function(){
	setTimeout(function() {
		if (typeof(FC.json.coupons) == "undefined") {
			jQuery.getJSON('https://'+storedomain+'/cart?'+fcc.session_get()+'&coupon=YOUR_COUOPON_CODE&output=json&callback=?', function(data) {
				// console.info(FC.json.coupons.length);
			});
		}
	}, 1500);
});
</script>

That uses a setTimeout to wait 1.5 seconds2), then check to see if a value already exists in the JSON (in this case we're checking to see if any coupons have been added to the session). If no that node in the FC.json object is undefined, we will use a JSONP call to add the coupon to the session. This is just an example, but hopefully it's useful in crafting your own scripts.

Important Notes for JSON(P) Implementations

The most critical thing about making successful JSON(P) calls to FoxyCart is remembering to include the fcsid (FoxyCart Session ID) in the request. The foxycart.js file includes a few helper functions, most notably the session_get() method (which you can see in action above), which will output a string like &fcsid=abc123su2eoba8r9oknf7qa4b3. Please review the session_get() method below:

''session_get'' Appending the FCSID to Requests

What It Is

The fcsid (FoxyCart Session ID) cookie stores the unique session ID of the customer, and is arguably the most important piece of a FoxyCart implementation. If the fcsid isn't sent to FoxyCart when the cart is requested, the customer will lose the entire contents of their cart, and may see other errors as well.

How It Works: Overview

When a webpage with foxycart.js loads, foxycart.js attempts to set a fcsid cookie according to the sitedomain and cookiepath values discussed above. Most of this is handled automatically

How It Works: Details

The session_get method will look for and set an fcsid cookie with the value retrieved from (in this order):

  1. A hash in the loaded URL (ie. #fcsid=abc123).
  2. An fcsid cookie.
  3. The FC.session_id in the JSON.

How To Use It: JSONP and Dynamically Modified Elements

If you're generating actions (cart-adds, JSONP requests, dynamically changing an add-to-cart link's href, etc.), you'll need to manually add the fcsid to your request. Luckily, this is fairly easy with the session_get() method. Assuming a normal foxycart.complete.js or foxycart.js inclusion in your template, you would create the link or JSONP URL like this (in javascript):

// Just the link to the cart itself
var cart_request = 'https://'+storedomain+'/cart?'+fcc.session_get();
// Adding a product
var cart_request = 'https://'+storedomain+'/cart?name=Test_Product&price=9.99'+fcc.session_get();
// Retrieving the cart via JSONP
jQuery.getJSON('https://'+storedomain+'/cart?'+fcc.session_get()+'&output=json&callback=?', function(data) {
	// callback function goes here
});

The fcc.session_get() call will return something like &fcsid=abc123su2eoba8r9oknf7qa4b3. If you just need the fcsid value itself you can easily retrieve it from the JSON with FC.session_id.

Are you creating or modifying elements? If you're dynamically creating add-to-cart links or forms, you don't need to bother with this at all. It will be handled automatically. If however you're modifying the href of an add-to-cart link that was present on pageload you do need to append the fcsid. This has to do with how FoxyCart binds onclick handlers to elements while also making it easy to add new add-to-cart link or form elements.

1)
More about JSON on Wikipedia and json.org.
2)
While this shouldn't need a setTimeout, as of v0.7.0 it does. We'll be updating that in future versions.

Site Tools