Table of Contents
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:
- Use Firefox to open up your website to a page where you have FoxyCart-powered add-to-cart links or forms.
- Add a product to your cart.
- Open Firebug's “console” tab and paste the above code into the command line, then run it.
- Look at your “Net” tab in Firebug to examine the request and response. Notice how the request substituted the
?
in thecallback=?
with something likejsonp1287171163698
. Then notice that theJSON
response is wrapped inside ajsonp1287171163698()
function call. That's the magic ofJSONP
.
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):
- A hash in the loaded URL (ie.
#fcsid=abc123
). - An
fcsid
cookie. - 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.