−Table of Contents
Advanced Template Customisations
Working with FoxyCart Templates
- Basic Customizations
Utilising the new configuration option for common changes - Intermediate Customizations
Incorporating your own designs in the FoxyCart templates - Advanced Customizations
Altering the raw templates - Template View Data
Cheatsheet for the variables accessible on the templates
This section is for people with intermediate to advanced CSS, HTML, and JS abilities. We're happy to help you if you get stuck, but if it's your first rodeo, this stuff might be a bit head-spinning :)
Getting even more advanced with Twig
If you'd like to customize your templates beyond what you can do with HTML, CSS, and JavaScript, FoxyCart allows you to use the Twig template language as well. Twig is flexible template language that's either near identical or relatively similar to a variety of other template languages. This functionality is very advanced, and most users should be able to achieve very seamless visual integrations without this. If you have super specific needs, however, you can dig into Twig.
Templates and Caching: How it all works
- We use the BEM methodology for CSS naming.
- All template variables used exist in the
FC.json
object. You'll see references to variables in the template files. That's where they live, but there are helper methods to work with that data. - We have a system we call AutoMagiCache, which scrapes a template file on your site and will cache it (and all assets) securely on our systems, so you don't need SSL on your own server to reference assets (images, css, js). Details on working with AutoMagiCache here.
- We're currently using Twitter Bootstrap 3 as a base for our default theme, but we're using SASS
@extend
functionality so you won't see any Bootstrap classnames. - Doing advanced customizations can get involved, but there are “easier” and “more difficult” ways to accomplish things within our templating approach. When in doubt please, please just reach out. We're happy to help.
Additionally, in previous versions of FoxyCart there was no clear separation of concerns between content (HTML), presentation (CSS), and dynamic behavior (Javascript). With v2.0 we're doing our best to help each aspect be a separate concern, so that you can override or customize the specific aspects your customers need without worrying about breaking things.
Recommended Reading
Before you proceed any further, we recommend looking over our Templates and Caching Primer page to get an understanding of the different pieces involved. Some parts may be already familiar to you - but having a grasp of the different pieces of the puzzle will make working deep within our templates all the more easier.
We also strongly recommend taking a look at the Twig overview documentation over at their site at https://twig.symfony.com/doc/2.x/templates.html. Understanding the basics of Twig will help you to be able to read our templates.
Below, you'll find our best attempt at explaining each aspect of our templates and how you can override, hook into, or remove the aspects that you're interested in. If you have questions, please don't hesitate to contact our support.
FoxyCart Template Structure
There are two levels to the FoxyCart templates, both of which are rendered using the Twig templating language, which are the Page Templates and the Partial Includes.
Page Templates
The Page Templates are the templates that form the base of the actual page being output - this is where you'll find html
, head
and body
tags. These are also the templates that you'll find under the 'templates' menu in your store's FoxyCart administration. These templates are also the different steps to the checkout flow that a customer could experience.
The Page Templates include:
- Cart Include
- Cart - Full page cart (
yourstore.foxycart.com/cart
) - Checkout
- Receipt
- Email (HTML and Text)
One key thing to note is the “Cart Include” template. It is technically a partial include template - but is used for the Sidecart functionality on your own website, so is a page template in that regard. The template also performs duties as the cart partial as displayed within the cart, checkout, receipt and HTML email templates though as well. The “Cart Include” template therefore doesn't have the traditional HTML structure in terms of html
, head
or body
tags.
Partial Include Templates
Within the page templates, are one or more partial includes that output different sections of the respective templates. Partials can also be stacked - a given partial may include one or more other partials within itself if required. The different partials may seem confusing at first - but we've broken the templates up into modular reusable pieces. As a quick overview of the different partials includes we have, look over the following cascading lists of our partials as they're included.
cart.inc.twig
svg.inc.twig
errors.inc.twig
postal_code.inc.twig
regions.inc.twig
checkout.inc.twig
cart.inc.twig
errors.inc.twig
address.checkout.inc.twig
postal_code.inc.twig
regions.inc.twig
receipt.inc.twig
cart.inc.twig
address.receipt.inc.twig
postal_code.inc.twig
regions.inc.twig
address.email.inc.twig
- included inresponsive.email.twig
address.email.inc.txt.twig
- included inemail.txt.twig
cart.inc.txt.twig
- included inemail.txt.twig
Outputting Partial Includes
A page template on it's own is just a normal page. If you want to include FoxyCart functionality within it, you'll need to output one or more partial includes within the template. You can output a Twig include file in one of two ways, include
and use
. Which you use will depend on what you're wanting to do.
Include - directly output the include into the page
If you use include
, that will take the whole contents of that file, and output it at that spot in the template. This is perfect if you're just wanting to output the default approach to that section, but you're wanting to include it somewhere specific. View include in the Twig documentation.
Example:
{% include 'cart.inc.twig' %}
Embed - output the include on the page, but allowing for overriding blocks within it
Loading an include using embed
behaves similar to include
above in that it will output the whole contents of the file into the page. Within the embed
tags though, you can also define block
tags for blocks that exist within that included file, and overwrite them. Any code not contained with a pre-existing block, or any custom blocks, will be ignored. View embed in the Twig documentation.
Example:
{% embed 'checkout.inc.twig' %} {% endembed %}
Use - load the blocks contained within ready for placement and modifying
Referencing an include using use
, with just that tag in isolation will output nothing into the page. What it will do is gather all the blocks within that include and load them into memory for you to manually include as desired. Anything not contained inside blocks will be ignored. View use in the Twig documentation.
Example:
{% use 'cart.inc.twig' %} {# Nothing output yet #} {{ block('logo') }} {# Logo block output into page #}
Blocks
Within the partial templates, we make use of Twig's block functionality to wrap certain chunks of our code into a named block. For an example, let's say you have a partial include called widgets.inc.twig
with blocks that look like this:
{% block block_a %} <div class="title-container"> <h1>{{ widget_title }}</h1> <img src="{{ widget_image }}" /> </div> {% endblock block_a %} {% block block_b %} <h2>{{ widget_subtitle }}</h2> {% endblock block_b %}
As you can see, there are two blocks within that markup enclosing two headers. If you wanted to just include that whole partial in your page template, you would just use the include
approach to do that. What if you wanted to include that partial, but make some changes to one of the blocks? That's where use
comes into play - allowing you to reference whole blocks with a single tag.
Editing blocks with ''embed''
As an example, let's say that we wanted to output our widgets.inc.twig
partial within our page, but we wanted to change block_b
to output the widget_subtitle
in a paragraph tag instead of a heading. We don't want to change block_a
at all. We could simply copy the whole widgets.inc.twig
code into our partial and just ignore the blocks, which would work. A better way though is to make use of the embed
tag, and overwrite blocks from the partial. By doing that - our code is cleaner within our page template, and if we make changes to our widgets.inc.twig
partial file later on, we'll still get those changes (apart from anything we overwrite).
So to follow on with our example, changing the h2
element to a paragraph would look like this in our page template:
{% embed 'widgets.inc.twig' %} {% block block_b %} <p>{{ widget_subtitle }}</p> {% endblock block_b %} {% endembed %}
In the code above - the widgets.inc.twig
template will be output as it is in the original file, but block_b
will be output as we redefined it within the embed
. This would result in HTML like this:
<div class="title-container"> <h1>{{ widget_title }}</h1> <img src="{{ widget_image }}" /> </div> <p>{{ widget_subtitle }}</p>
Embedding also allows you to still output the block as it is - and just add something before or after it. For example, if we wanted to add some additional content after the h2
title in block_b
, but leave the heading as it is, we can do that by outputting {{ parent() }}
like this:
{% embed 'widgets.inc.twig' %} {% block block_b %} {{ parent() }} <p>{{ widget_date }}</p> {% endblock block_b %} {% endembed %}
This set up would result in HTML like this:
<div class="title-container"> <h1>{{ widget_title }}</h1> <img src="{{ widget_image }}" /> </div> <h2>{{ widget_subtitle }}</h2> <p>{{ widget_date }}</p>
If you're wanting to make changes to how the cart template is displayed on the checkout or receipt - you should make changes directly to the “cart include” template. We don't currently support using an embed
tag of the cart.inc.twig
template within the checkout or receipt embed
calls.
Allowed Twig Tags and Functionality
At present, the only allowed functionality for Twig is as follows:
Need a tag, filter or function not listed here? Simply get in touch and we can look at adding it.
We also have some custom Twig filters and functions we've added to meet specific needs:
Tags
-
money_format
- Description: Formats a given number into the formatting of the store
- Example:
{{ total_item_price|money_format }}
-
pad
- Description: Adds a specific character
- Parameters:
- Integer representing the length to pad (Default
30
) - String of the value to pad the variable with (Default
" "
) - String of the delimiter between the variable and the padding (Default
":"
) - Direction of the padding from the variable
"left"
or"right"
(Default"right"
)
- Example:
{{ key|pad(20) }}
or{{ key|pad(30, "-", "", "left") }}
-
fc_output_data
- Description: Used to customise email subjects, from and bcc, as documented here.
Functions
-
selected
- Description: Used to add the
selected
HTML attribute to select dropdowns - Parameters: Two strings for comparison
- Example:
<option value="{{ value }}" {{ selected(saved_value, value) }}>
-
checked
- Description: Used to add the
checked
HTML attribute to checkboxes and radio inputs - Parameters: Boolean to equal
true
if the input should be checked - Example:
<input type="checkbox" name="my_checkbox" value="1" {{ checked(my_checkbox == '1') }} />
-
formatCityOption
- Description: Used to return a city/state string
- Params: Object containing
city
, and optionallyregion
andregion_name
- Example:
{{ formatCityOption({"city": "Nashville", "region": "TN", "region_name": "Tennessee"}) }}
-
getPostalCodeLabel
- Description: Used to get the correct language string for a given countries state or postcode
- Parameters: String representing 2 character country code
- Example:
{{ getPostalCodeLabel(address.country) }}
-
generate_sso_token
- Description: Used to generate a SSO token useful for quick purchases from the receipt or reverse SSO logins, as documented here.
- Example:
{{ generate_sso_token(timestamp) }}
- Notes: Only generated server-side, won't run with client-side Twig.js
Accessing FoxyCart's Templates
All of our page and partial templates are available from our 2.0 templates Github Repository. You can simply use the repository to view the different templates and copy out the templates that you need. If you're familiar with Git though, you can also fork our repository and apply any changes to the templates as needed - and when we apply any updates you can merge those new commits into your edited templates to keep your custom templates up to date.
If you're customising any of the partial includes, you can be updated of changes to the templates in a few ways. Firstly, you can “star” or “watch” the repository to receive notifications through Github. You can also view a RSS feed of all commits to the repository in a RSS viewing tool.
Errors
A big part of an online checkout is error handling. We have some conventions and helper functions if you'd like to customize error handling.
Required Fields & Inline Errors
Required fields will generate an error if a user tabs off of them. Our goal in FoxyCart 2.0 has been to create a default client-side validation system that unobtrusively alerts users to problems with the form, while also giving you as much room to customize as possible. With that in mind inline errors now have three parts:
- Field highlighting
- Error bar updating
- Error event firing
Each of these parts are designed to be independent so you can utilize just one or both in whichever way works best for you. Below you'll find in depth explorations of each step.
1. Field Highlighting
The specific field will be highlighted by adding a class to the element, which allows CSS styling to highlight the field. FoxyCart gives you flexibility in customizing both the error class applied, and which element it is applied to through the use of data attributes. The error class is defined with the data-fc-error-class
attribute.
If you are adding the error class to an element other than the input (such as a parent element), then you need to include a data-fc-error-for
attribute on that element, with the value being the name
of the input. So for the shipping first name field, the parent
has both attributes, looking like this:: data-fc-error-class=“invalid”
data-fc-error-for=“shipping-last-name”
. In case of an error on the field, the class invalid
will be added to the
, and once the error is resolved, the class will be removed.
data-fc-error-class
is required if you wish to utilize the FoxyCart inline-error functionality. If no class is found, a fallback method of rerendering the block will be triggered. For the default templates, the fallback method will evaluate the twig context, find the error, and apply the styling to the field. This rerendering is expensive from a browser perspective, so we attempt to avoid it whenever possible.
The data-fc-error-for
is not required on the input itself - you can just add the data-fc-error-class
attribute alone and FoxyCart will apply it to the input when an error occurs.
Error classes are cleared in the same way they are added: FoxyCart checks the input to see if it has a data-fc-error-class
attribute and removes the defined class from the input, if present, and then checks for a data-fc-error-for=“FIELD_NAME”
and if one is found, removes the data-fc-error-class
defined on the element, if present.
The data-fc-error-class
typically just takes a single class name as a string, but an additional “success” class can be added after a comma, like this:
<div class="alert alert-danger" data-fc-error-for="cc_cvv2" data-fc-error-class="show,hidden"></div>
This will not only add the show
class on error, but it will also remove the hidden
class as well. When the error is cleared, it will toggle show
off and toggle hidden
on.
2. Error bar updating
Once the field markup has been updated, FoxyCart updates the notifier bar at the top of the page to alert the user that a field has an error on it. This only occurs if the notifier bar is present. The markup for the bar is very simple, here's what it looks like in the default checkout template:
<section data-fc-error-notifier> <h3 data-fc-notifier-text></h3> </section>
The data-fc-error-notifier
attribute needs no value. Adding it to an element tells FoxyCart that all error messages should be added to this element. The data-fc-notifier-text
attribute is optional, by default the message will be appended as a <p>
element, if you wish to use a different text element, use the data-fc-notifier-text
attribute.
When a message is sent to the notifier bar, it checks the length of FC.JSON.messages.errors, and if there are errors present, the bar updates the count and adds the classes “alert alert-danger.” All appearance and animations are handled with CSS and can be defined/overridden in your custom style sheets.
Class that is appended to be active user-definable.
3. Error Event Firing
The last step in error handling is firing a jQuery event that you can listen for to add your own customizations. notificationUpdate
is fired on the <body>
tag every time a message is sent or removed from FC.JSON.messages.errors. Listening for this event allows you to design custom ways of alerting the user that there are errors on the form, such as jGrowl or something custom.
Hard errors more info coming soon