Table of Contents
FoxyCart's Javascript: foxycart.js
FoxyCart's foxycart.js
file is full of goodies that you probably won't ever need to think twice about. If default configurations are an anathema to you, if you need to get advanced for a custom integration, or if you're just curious about what's under the hood please explore this page and the “raw” version of the foxycart.js
, and let us know if you have any questions.
What It Does
The foxycart.js
file:
- Handles all cross-domain sessions, ensuring sessions don't get lost regardless of browser privacy settings (so long as some cookies are enabled).
- Automatically (mostly) handles determining at what level to set your store's FoxyCart cookie. (ie. Determines to set it at
.example.com
or.example.co.uk
or.custom.example.com
.) - Makes it easy for custom events or validation to be run before products are added to the cart.
- Makes it easy for custom events or validation to be run after products are added to the cart.
- Automatically attaches
onclick
andonsubmit
handling to all links and forms (even dynamically created elements) pointing to your store's FoxyCart cart URL. - Keeps the FoxyCart JSON object (
FC.json
) current before and after cart requests. - Alerts if jQuery isn't loaded.
Available Files
http://cdn.foxycart.com/YOURDOMAIN/foxycart.colorbox.js
: Compressed. Includes the code to automatically set your store's domain, your store's FoxyCart domain, to initialize theFC
object asfcc
, and to attach Colorbox to all add-to-cart links and forms.http://cdn.foxycart.com/YOURDOMAIN/foxycart.js
: Compressed. Includes the code to automatically set your store's domain, your store's FoxyCart domain, and to initialize theFC
object asfcc
. Note that thepreprocess
andprocess
events don't actually have any behavior in this version of the file, and thatpostprocess
is not referenced at all, sincepostprocess
should be called by whateverprocess
events you've defined.http://cdn.foxycart.com/YOURDOMAIN/foxycart.raw.js
: Uncompressed. Does not set your store's domain, your store's FoxyCart domain, nor does it initialize thefcc
object. This will generally only be used for special circumstances or advanced users needing access to the uncompressed code.
What's Different from Previous Versions
Almost everything but some of the ways that sessions are set has been rewritten, but here are the main changes from the foxycart_includes.js
in v0.6.0:
- No more
.foxycart
class necessary for add-to-cart links and forms. Instead it relies on thehref
oraction
of the link or form pointing to your FoxyCart's domain. - The
fc_json
object is now accessible asFC.json
. fc_PreProcess()
has been changed to apreprocess()
method that's more flexible, called differently, expecting different arguments.fc_BuildFoxyCart()
has similarly been changed to apostprocess()
method described below.- Setting the FoxyCart Session ID (
fcsid
) at a subdomain, third-level domain, or specific path is now possible without rewriting core functions. fc_AddSession
doesn't exist anymore, the current session can be retrieved usingfcc.session_get()
. Note that the new javascript uses jQuery'slive()
event to find any links or forms that are directed at FoxyCart and adds the session to them automatically, so you don't generally have to use this. If you are altering the href of a link dynamically though, you will need to re-add the session to the updated href, otherwise FoxyCart will assume its a new link and you'll get double ups on the process functions (ie: 2 carts in colorbox).fc_tb_show
doesn't exist anymore as 070 now uses colorbox as the default modal window. If you check out thefoxycart.js
you add to your page, you can see the colorbox being initialized there. Its just a vanilla colorbox implementation so you can use colorbox for whatever else you need modals for too.
How It Works & Configuration
While most of this should happen automatically, especially if you're using the foxycart.js
or foxycart.colorbox.js
versions (as opposed to the foxycart.raw.js
), there are a few things that need to be configured correctly.
''storedomain'': How Your Links and Forms Are Handled
The first configuration that the FC
object in foxycart.js
takes is the path to your store's FoxyCart cart, like yourstorename.foxycart.com
. This setting is critical (and usually set automatically unless you're using the “raw” version of foxycart.raw.js
), as this is how the script determines which links to attach the click or submit events to, as well as when and how to add the session ID to any and all requests to your store's FoxyCart requests.
Without this setting configured correctly it is highly likely that your customers will lose their cart contents when they attempt a checkout.
''sitedomain'': The Domain on Which Your Visitor's FoxyCart Cookies Are Set
The sitedomain
is the second argument required, but unlike the storedomain
, the sitedomain
is only used to determine where to set the cookie for the visitor's FoxyCart session. If your sitedomain
is passed in as example.com
or www.example.com
, the fcsid
(FoxyCart Session ID) cookie is set at the second-level domain, which is .example.com
. If your sitedomain
is a third-level domain like example.co.uk
or subdomain.example.com
, the cookie would be set at .example.co.uk
or .subdomain.example.com
.
This setting is only important if your site isn't at the second-level domain, or if you want to restrict your FoxyCart sessions by subdomain. For example, if your site is example.co.uk
, you don't want the cookie set at .co.uk
. Or if you want to have different FoxyCart sites at donations.example.com
and products.example.com
, you'd need the cookies not to be set at .example.com
or the sessions would overlap with unexpected results. (Another example would be if your site is at a 3rd party provider like example.squarespace.com
, you don't want all *.squarespace.com
sites sharing your FoxyCart sessions.)
The only two things to keep in mind are:
- The
www
subdomain is effectively ignored, so if you do want to lock your sessions down to.www.example.com
you'll need to set thesitedomain
value to something likewww1.example.com
. The actual value doesn't matter; it's only counting the dots in the value after it strips thewww
. - You cannot have the FoxyCart javascript at any other subdomains if you are isolating by subdomain. For example, if you have two separate stores at
products.example.com
anddonations.example.com
you cannot also have yourfoxycart.js
atwww.example.com
orexample.com
, as that will set the session cookie at.example.com
, which will override theproducts
anddonations
session cookies.
''cookiepath'': The Path on Which Your Visitor's FoxyCart Cookies Are Set
The cookiepath
determines the fcsid
cookie's path. This is almost always going to be empty, so the cookies would be set at .example.com
, but if you do need to have multiple FoxyCart sessions on the same domain you could use this setting to restrict cookies to something like .example.com/en/
and .example.com/es/
(to split English and Spanish FoxyCart stores, for example).
The cookiepath
value must end in a /
or you may run into issues, especially with Internet Explorer. The leading slash is automatically applied by the foxycart.js
, so if you want a path of /en/
you would enter cookiepath = 'en/';
.
*Example:* Suppose you have a donations section and a bookstore, located at http://example.com/donations/
and http://example.com/bookstore/
. (Note that the trailing slash is critical. If you have something like http://example.com/bookstore
and http://example.com/donations
this method will not work and the sessions will collide.) Add the following code before your calls to foxycart.complete.js
or foxycart.js
. Obviously, change out the “donations” with “bookstore” depending on where you're placing this code.
<script type="text/javascript" charset="utf-8"> if (typeof(cookiepath) == 'undefined') { var cookiepath = 'donations/'; } </script>
Helper Functions
Loading the Cart on Page Load
If you find yourself needing to have the default Colorbox-powered FoxyCart cart load itself when your site is loaded, the foxycart.colorbox.js
file has a helper function that loads the cart with a cart=view
command. To accomplish this, simply link to a page on your site (one that has the foxycart.colorbox.js
linked on it) with fc_open=true
in the anchor. So the href
in a link to your site might look like this:
http://example.com/landing_page.html#fc_open=true
That will call fcc.events.cart.process.execute
with your FoxyCart cart's “view” parameter.
"Mini-Cart" Display and HTML Helper Functionality
When the FC
class is initialized (via the .init()
method) and on the .cart_update()
method, elements with the following classes or IDs are modified:
#fc_minicart
,.fc_minicart
: If theFC.json.product_count
is greater than 0, these elements will be shown. Otherwise they'll be hidden#fc_quantity
,.fc_quantity
: The inner HTML will be replaced by the value inFC.json.product_count
.#fc_total_price
,.fc_total_price
: The inner HTML will be replaced by the value inFC.json.total_price
, formatted using the_currency_format
function (which adds decimals but doesn't add currency symbols).#fc_singular
,.fc_singular
: The inner HTML will be shown if value inFC.json.product_count
is equal to 1, and is hidden otherwise. It can be useful if you want to show “Item/Product” instead of “Items/Products” forFC.json.product_count
= 1.#fc_plural
,.fc_plural
: The inner HTML will be shown if value inFC.json.product_count
is greater than 1 or less than 1 (zero), and is hidden otherwise.
<a href="https://yourdomain.foxycart.com/cart?cart=view" id="fc_minicart"> <span id="fc_quantity">0</span> <span id="fc_singular"> item </span> <span id="fc_plural"> items </span> in cart </a>
''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
.
Developer Note: if you are developing with Chrome and on an IP address, Chrome won't let you save cookies to that IP or to localhost so it's best to do any session_get() calls with another browser during development. http://code.google.com/p/chromium/issues/detail?id=56211
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.
Adding Your Own Events
The following “events” below have the following methods:
add
: Adds the function to the event's function array.add_pre
: Adds the function to the event's function array before any other functions in the array.resume
: Resumes a previously “paused” event. Ifpause
is returned, execution of the event function array stops, but it keeps its place. This is very useful if you need to ensure that a requestexecute
: Execute's all the functions in the array, stopping iffalse
is returned. (This is mostly an internal method, and won't likely be used by even very advanced integrations.)
If you want to keep the colorbox modal implementation and extend with custom events be sure to add any fcc
customization after that. (You don't need to include both foxycart.js
and foxycart.colorbox.js
, as foxycart.colorbox.js
has the entirety of foxycart.js
inside of it already.)
<script src="//cdn.foxycart.com/YOURDOMAIN/foxycart.colorbox.js?ver=2" type="text/javascript" charset="utf-8"></script> <script type="text/javascript" charset="utf-8"> fcc.events.cart.preprocess.add(function(e, arr) { console.log(arr); return true; }); </script>
''ready'': When the Cart is Ready on Pageload
What It Is
If you need to execute javascript on pageload, but you require the cart contents, the ready
event will allow you to execute code once the FoxyCart cart object is ready.
How It Works: Overview
When the foxycart.js
is loaded on a page, it will retrieve the cart data when the page is ready (on jQuery's document.ready
event).
How It Works: Details
Unlike the other events, the ready
event's execute()
method does not get called with any arguments.
''preprocess'': Before an Add-To-Cart
What It Is
Attaching a custom event to be run before an item is added to the cart can be useful if you need to do client-side validation of a form or value before allowing the cart-add to happen. For example, you may have a “Custom Note” field on an add-to-cart form that's required. Or a “Gift Recipient Email Address” field that must be completed for the item to be added to the cart. Using the preprocess
event allows all of this and more.
How It Works: Overview
When a link or form pointing to your FoxyCart's cart URL (ie. https://example.foxycart.com/cart
) is clicked or submitted, foxycart.js
first checks to see if any functions have been added to your preprocess
array. If any functions exist, they are run in order of entry (first-in-first out) passing in two arguments:
- The submitted element itself.
- An array of name/value pairs to be submitted to the cart-add request. This array is built using an “unserialize” function inside the
FC
object.
If any function in the preprocess
array returns false
, the cart-add is aborted. (The actual onclick
or onsubmit
event of the add-to-cart link or form returns false
, so the default behavior of the element is bypassed as well.) No other indication is given, so if you have a preprocess
function that returns false it should also alert the user.
If no preprocess
functions are added, this step is effectively skipped.
How It Works: Details
Assuming the default fcc
object, the first step is to create a function and add it to the preprocess
array:
foxycart_ga = function(e, arr) { var href = ''; if (e.tagName == 'A') { href = e.href; } else if (e.tagName == 'FORM') { href = 'https://'+storedomain+'/cart?'+jQuery(e).serialize(); } if (!href.match("cart=(checkout|updateinfo)") && !href.match("redirect=")) { pageTracker._trackPageview('/cart'); console.info('foo1'); return true; } } fcc.events.cart.preprocess.add(foxycart_ga);
Or just create an anonymous function straight in the array, like this:
fcc.events.cart.preprocess.add(function(e, arr) { var href = ''; if (e.tagName == 'A') { href = e.href; } else if (e.tagName == 'FORM') { href = 'https://'+storedomain+'/cart?'+jQuery(e).serialize(); } if (!href.match("cart=(checkout|updateinfo)") && !href.match("redirect=")) { pageTracker._trackPageview('/cart'); console.info('foo1'); return true; } });
That function fires off a request to Google Analytics's _trackPageview()
function before the cart is added, and returns true
. Because it returns true
the .execute()
method of the preprocess
object will continue on to the next function in its array. If the execute()
method runs all the functions in the preprocess
array without hitting a return of false
, the cart-add request moves on to the process
event.
''process'': The Actual Add-To-Cart Event
What It Is
The process
event is where you can define what happens when a visitor to your site clicks an “add to cart” link or form. You may want to display an unobtrusive indication that the item has been added to their cart; you may wish to display a modal window (like the default Colorbox script); you may want to send the visitor directly to checkout if certain products are in the cart; or you may want to do a combination of all that and more. All of this functionality can be defined in the process
event.
Skipping It Entirely
If you don't want anything fancy and just want your links and forms to load the cart up straight, just don't add any functions to process
. It's that easy. If no functions are present then your add-to-cart links and forms will behave normally.
How It Works: Overview
The process
functionality is nearly identical to the preprocess
functionality described above, but whether true
or false
is returned may be a bit more nuanced. Generally you'll only want _one_ event in the process
array, though you can have more if necessary.
One thing to keep in mind is that a return false;
is probably desired if you actually do anything here, such as a JSONP request or a modal window call, since that is where the item is added to the cart. If you don't return false
then the add-to-cart link or form will fire and the request will likely be duplicated.
How It Works: Details
After any preprocess
events have been run, the process
event is first checked to determine if any functions have been added. If the process
array is empty, true
is returned and the default behavior of the add-to-cart element that was submitted continues.
Adding a function to the process
array is the same as with the preprocess
examples above, but obviously replacing preprocess
with process
. Here's an example of the way Colorbox is attached to cart-add requests in the default foxycart.complete.js
file:
fcc.events.cart.process.add(function(e){ var href = ''; if (e.tagName == 'A') { href = e.href; } else if (e.tagName == 'FORM') { href = 'https://'+storedomain+'/cart?'+jQuery(e).serialize(); } if (href.match("cart=(checkout|updateinfo)") || href.match("redirect=")) { return true; } else { jQuery.colorbox({ href: href, iframe: true, width: "700px", height: "70%", onClosed: function(){fcc.events.cart.postprocess.execute(e);} }); return false; } });
This example first checks to see if the element that was submitted is a link (A
) or form (FORM
). It then sets the URL
to be submitted to the cart. If that cart request should bypass the cart, however, it returns true
, thus allowing the link or form to complete its behavior unimpeded (and bypassing the modal window entirely). If the cart-add request does belong in a modal window the code instantiates a Colorbox and loads the cart in an iframe
. It then returns false
, preventing the link or form from submitting again (since loading it in the Colorbox's iframe has already made our cart request.
Notice the onClosed
function. That comes next. Onward, ho!
''postprocess'': After the Add-To-Cart
What It Is
The postprocess
event is not called directly by foxycart.js
, but is available to use if you need it. This can be useful, for example, if you want to refresh the FC.json
when your modal window is closed, as is the case with the default foxycart.colorbox.js
.
How It Works: Overview
Just like the preprocess
and process
, you can add multiple functions to the postprocess
even. Notice the call to postprocess
in the process
example above, in the onClosed
parameter. That's telling Colorbox to run the postprocess
events when the modal window is closed. If we add a function like below, then the cart_update()
method will be called (which refreshes the FC.json
and updates the “minicart” helper functions).
fcc.events.cart.postprocess.add(function(){ fcc.cart_update.call(fcc); });
(The .call(fcc)
is necessary to prevent the this
keyword in JavaScript from going wonky.)
Pausing and Resuming Event Execution
The need for pausing and resuming an event is most often seen in adding products to the cart. Sometimes you may need to add or remove a product silently before a cart request is sent, or you may need to add custom fields to the session for affiliate or analytics tracking. Because JavaScript is a non-blocking language, it's likely that a request to a 3rd party affiliate tracking system might return slower than the add-to-cart request, which could cause problems.
In order to work around this problem, FoxyCart supports pausing and resuming an event. To pause an event, for example, the preprocess
event, you'd return “pause”
(as a string) instead of true
or false
. Here's a heavily commented example of adding a product to the cart silently:
fcc.events.cart.preprocess.add_pre(function(e, arr) { if (arr['cart'] != "view") { console.log("Preprocess - adding a product silently"); var jsonString = ""; jsonString = 'https://' + fcc.storedomain + '/cart?output=json&1:quantity=2&1:name=Add%20in%20preprocess&1:price=3.23&1:weight=5&1:code=pre1'; $.getJSON(jsonString+'&callback=?' + fcc.session_get(), function(data) { console.log("And added.") console.info(this); FC.json = data; // fcc.cart_update(); console.log('= = = = = = = = = = = = = = = = = = = = ='); console.info(this); fcc.events.cart.preprocess.resume(); }); return "pause"; } else { return true; } });
Notice the return “pause”;
. That halts the further execution of the preprocess
event. So how to resume? Notice the fcc.events.cart.preprocess.resume();
. That's similar to calling fcc.events.cart.preprocess.execute();
, but instead of starting at the beginning, it resumes from where it was last paused.
If you have any questions on any of this, please don't hesitate to post on our forum. We're happy to help.