Documentation You are here: start » v » 2.0 » templates » primer

FoxyCart Templates and Caching Primer

Working with FoxyCart 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, post on our forum and let us know what is confusing, or email support if you have a suggestion on how this documentation can be more helpful.

Looking to customise your templates? Take a look at the Advanced Customisations page.

Introduction to Templating

If you've used a template language before, you can probably skip this section. If you haven't, it's probably useful to go through this section to understand how and why templating works the way it does.

FoxyCart 2.0 takes advantage of Twig javascript templates to allow you the freedom to customize all aspects of the eCommerce experience. Templates allow you to quickly and fairly easily add dynamic aspects to your HTML pages. Here's a quick example of how templates will make your life easier. With a simple HTML page, you'd have this:

<h1 class="product-title">Product 1</h1>
<p class="description">Description about Product 1</p>
<p class="cost">Cost: $25</p>
<a href="#" class="add-link">Add to Cart</a>

The classes make it really easy to style the presentation of the different elements with CSS, but CSS and HTML alone do not allow you to change dynamically update the contents of the HTML. That's why web developers use Javascript, to add interactivity to the sites they design. Commonly this is done with jQuery, so let's examine how that might work. Perhaps you want a product that has two options, and the second option adds 10% to the cost. First, you'd start with your HTML:

<h1 class="product-title">Product 1</h1>
<p class="description">Description about Product 1</p>
<ul class="options">
  <li class="option1"><input type="radio" value="default">Default</input></li>
  <li class="option2"><input type="radio" value="premium">Premium</input></li>
</ul>
<p class="cost">Cost: $<span class="number">25</span></p>
<a href="#" class="add-link">Add to Cart</a>

Then you'd add the javascript to watch the radio buttons:

$( document ).ready( function () {
  $('.options').click( function () {
    var option2 = $('.option2:checked').length;
    if (option2 > 0) {
      $('.number').text('35');
     } else {
      $('.number').text('25');
  });
});

That's potentially ok for one or two products, but it doesn't scale well. That's why smarter engineers than us have created worked on building Javascript templates that help abstract some of this work. The basic concept is you take some JSON data, insert it into a Javascript template, and then insert the combined output into the client document. It works like this. First, you create a template. In this example we're using Twig syntax:

<h1 class="product-title">{{ title }}</h1>
<p class="description">{{ description }}</p>
<ul class="options">
  {% for option in options %}
  <li><input type="radio" value="{{ name }}">{{ name }}</input></li>
  {% endfor %}
</ul>
<p class="cost">Cost: ${{ cost }}</p>
<a href="#" class="add-link">Add to Cart</a>

Now, we can just render the template by providing some JSON data that matches the variables:

var templateData = {
  title: "A product",
  description: "This is a product description",
  options: {[
    option1: {
      cost: 25,
      name: "Default"
    },
    option2: {    
      cost: 35,
      name: "Premium
    }
  ]}
}

No longer do we need to write custom Javascript for each product option. Now we can just let the template rendering engine handle it. The default HTML output of this code looks like this:

<h1 class="product-title">A product</h1>
<p class="description">This is a product description</p>
<ul class="options">
  <li><input type="radio" value="default">default</input></li>
  <li><input type="radio" value="premium">premium</input></li>
</ul>
<p class="cost">Cost: $25</p>
<a href="#" class="add-link">Add to Cart</a>

Now all we have to do is listen for a click, and then re-render the template with the current context. This makes it much easier to scale our code - now we can have as many options as we need. We could also pass in products as data and add new products easily, which it turns out is exactly what happens in FoxyCart templates.

Class, ID, and Data Conventions

  • .fc-* classes are for styling purposes only. They aren't required for functionality. (See more in the BEM section immediately below.)
  • #fc-* IDs are for styling purposes. #fc- IDs are used sparingly, and mostly for namespacing CSS. (See more in the BEM section immediately below.) Our recommendation is to not use these IDs for javascript selectors. Use the data-fc-* attribute(s) instead and stick with our conventions.
  • data-fc-* attributes are for functional purposes and template rendering.
  • input elements (and select and other form elements) have some caveats:
    • Their name attributes have underscores. These can't be changed without breaking serverside functionality, so don't change them in template customizations.
    • Per HTML requirements, label elements operate based on the id attribute of the related input. For ease of implementation and because name and id values almost always match in most HTML, the id values for form inputs also have underscores, and are not prefixed with fc-.
    • Inputs should be selected (in javascript) using the name and value (if necessary) selectors, not the id attribute. Yes, theoretically IDs would be faster, but selector speed isn't really a concern at this point with modern browsers.

CSS Class and ID Naming Principles with BEM

To help make the base FoxyCart theme easily modifiable, we've adopted the BEM methodology for element naming. BEM stands for Block, Element, Modifier and it introduces a funky identifier scheme that we've tried to apply consistently in our templates.

This article will give you an extensive background on the BEM philosophy we used. Basically, Blocks are defined as distinct elements of a template, Elements are the individual HTML elements that make up the Block, and Modifiers are variations of the Elements. They are represented like so:

block--element__modifier

And they can be strung together:

block--block--element__modifier

FoxyCart templates now have as much separation of concerns as possible, which means all classes are only used for presentation styling and have no impact on actual functionality. The goal with BEM styling is that all elements can be custom styled with a the #fc namespace selector plus at most two class names. Custom CSS can be added to the Admin, or you can hook into the BEM naming to easily apply your own styles.

Specific IDs and Data Attributes

  • #fc: This is used to namespace CSS for default themes. For the main default theme to function properly but not to interact with a user's own CSS, this keeps the default FoxyCart CSS separate. It may be on the html element (for the fullpage cart, checkout, and receipt templates) or on a div container when rendered on client sites.
  • data-fc-container=“cart”: The cart will be rendered (via Twig.js) inside of this element.
  • data-fc-container-for=“…”:
  • data-fc-messaging-for=“…”:
  • data-fc-error-for=“…”:
  • data-fc-id=“…”: For tagging specific DOM elements you want to access via code.
  • data-fc-container-id=“…”: When a data-fc-id element takes an action on the DOM (for example, when a coupon code is removed, quantity is changed, or an item is removed from the cart), the corresponding element will be acted upon.

Frameworks & Extending

FoxyCart 2.0 has an underlying foundation of Bootstrap - but you can't tell by looking at the HTML. Our Bootstrap CSS is custom compiled with an #fc namespace and then applied to the DOM via Sass's @extend functionality. CSS Tricks covers the basics of Extending in this article. In the FoxyCart Sass, we provide a partial called _fc-to-bootstrap.scss that maps Bootstrap classes on to the correlating FoxyCart classes. If you are building off of the default responsive theme for your customization, it would behoove you to look in that file to see grid classes applied to elements for responsiveness.

This dependency should not be considered permanent. Future updates to FoxyCart may remove Bootstrap for lighter CSS, thus the reason it is not exposed in templates.

Twig Templates & Conventions

All our templates are available (and automatically kept up-to-date) at GitHub: https://github.com/FoxyCart/2.0-templates You'll notice some conventions in those templates, and you'll need to be aware of those as you do your own customization.

  • The Twig block names from the default templates must remain in place even with if you rewrite the template entirely.
  • The checkout template must include a block named checkout, and the endblock tag must also include the name. So
    {% block checkout %}
    {# stuff goes here #}
    {% endblock checkout %}

    If you haven't done any customizations inside the checkout block (like if you're using {{ block("checkout") }}), this is already present. Unless you're doing major customizations, you won't have to worry about this.

  • Twig filenames are partial.context.inc.twig, like address.checkout.inc.twig. The context piece is optional.

Site Tools