Building Your Zippy Courses Theme Part 6: Advanced Features and Components

Advanced Forms, Core Components, and Smart Attributes, Oh My!

Zippy Courses is a pretty robust system, and custom themes give you immense amounts of control on how your site looks and acts.

Aside from the required layouts, we don't have a whole lot of "rules" for you to follow when it comes to building a theme.

Do you want to use Twitter's Bootstrap framework to build your theme? Awesome, that's a snap. Do you prefer Zurb's Foundation framework? Also, not a problem.

So what areas of the system do have rules?

We'll continue to keep it simple: e-commerce, marketing, tables, and interactivity.

e-Commerce and marketing both fall into the categories of Advanced Forms, while tables and interactivity fall under the umbrella of Core Components. Let's look at how each works with Zippy Courses and what's required to make them work.

Advanced Forms

There are two types of forms in Zippy Courses that we consider to be "advanced":

  • Checkout Forms
  • Opt In Forms

Why are they advanced? Because they offer you a whole lot of bang for your buck. Checkout forms allow you to accept payments using any of the gateways Zippy Courses integrates with, right on your checkout page, while opt in forms support nearly a dozen separate email marketing services from a single form.


Instead of using traditional <form></form> tags, we upgraded both the checkout form and opt-in forms. As long as you follow the rules for each, you'll be golden.

Checkout Forms

So you want to make a checkout form. How do you do that? Let's take a look:

<checkout-form> ... </checkout-form>

Pretty easy, right? Did you notice the <checkout-form> tag itself? That's the upgrade we were talking about.

Now just using the tag isn't enough, and by itself, it doesn't give you a whole lot of control. The rules for successfully using the checkout form are pretty simple though:

All you have to do is include HTML inputs with the correct name attribute, and it will work. Like magic.

What are the fields?

We're glad you asked. Here's the list:

  • _token - use {{ forms.token }} to access the current token.
  • firstName
  • lastName
  • email
  • emailConfirmation
  • address.line1
  • address.line2
  • address.state
  • - the value must be the two digit country code, we recommend using {{ utilities.countries }} to create a dropdown of countries to choose from.
  • address.postalCode

And if you will be using any gateway other than PayPal, you will need 4 more fields:

  • - The cardholder's name
  • card.number
  • card.cvc
  • card.expiration

Need to see a field or two in action? No problem, here's a sample Payment Details section from a checkout page:

<div class="card-header">
	<h4 class="card-title">Payment Details</h4>
<div class="card-block">
	<div class="row">
		<div class="col col-12 form-group">
			<label for="ccName">Name on Card</label>
			<input class="form-control" type="text" name="">
		<div class="col col-12 col-md-6 form-group">
			<label for="cardNumber">Card Number</label>
			<input type="text" class="form-control" name="card.number" placeholder="•••• •••• •••• ••••">
		<div class="col col-6 col-md-3 form-group">
			<label for="cardCvc">CVC</label>
			<input type="text" class="form-control" placeholder="123" name="card.cvc">
		<div class="col col-6 col-md-3 form-group">
			<label for="cardExp">Exp Date</label>
			<input type="text" class="form-control" placeholder="•• / ••" name="card.expiration">

Look at each of the <input> elements. Every single one matches a required field from the list above.

And don't worry! If you miss any of the inputs, the <checkout-form> element is smart enough to let you know when you preview the page.

Opt In Forms

The way that opt in forms work is very similar to checkout forms. The only differences are where they are used and what the required fields are.

What are the required fields? It's a short list:

  • firstName
  • email


Here's a snippet from one of our opt in form modal blocks:

	<div class="row">
	    <div class="col col-12 col-md-6 form-group">
	        <label for="optInFirstName">First Name</label>
	        <input class="form-control" type="text" name="firstName" placeholder="Your First Name" id="optInFirstName">
	    <div class="col col-12 col-md-6 form-group">
	        <label for="optInEmail">Email</label>
	        <input type="text" class="form-control" name="email" id="optInEmail" placeholder="">

Other Forms

Those aren't the only two forms you'll use on your Zippy Courses site. You've got to allow your users to register, login, update their accounts, and more.

For the full list, you can refer to the form's section of our Template Data guide. While they are standard HTML forms, each of them has expected and required fields. If you build them and forget a field, submitting them won't work. Let's go through each one so you can have a list of each form's expectations:

Note: To see these forms in action, head over to forms components in our Starter Theme on GitHub, and you'll be able to see them ready for use.


  • email
  • password
  • _token (as a hidden field, using {{ forms.token }})


  • firstName
  • lastName
  • email
  • email_confirmation
  • password
  • password_confirmation
  • order (as a hidden field, using {{ request.order }})
  • _token (as a hidden field, using {{ forms.token }})

Forgot Password:

  • email
  • _token (as a hidden field, using {{ forms.token }})

Reset Password:

  • password
  • password_confirmation
  • reset_token (as a hidden field, using {{ }})
  • user (as a hidden field, using {{ entity.user }})
  • _token (as a hidden field, using {{ forms.token }})

Affiliate Apply/Register:

  • paymentMethod
  • paypalAddress
  • address[line1]
  • address[line2]
  • address[city]
  • address[state]
  • address[country] - the value must be the two digit country code, we recommend using {{ utilities.countries }} to create a dropdown of countries to choose from.
  • address[postalCode]
  • agreesToTerms - has a value of yes, recommended to use a checkbox
  • _token (as a hidden field, using {{ forms.token }})

Change Password:

  • password
  • password_confirmation
  • userId (as a hidden field, using {{ }})
  • _token (as a hidden field, using {{ forms.token }})

Contact Details

  • firstName
  • middleName
  • lastName
  • userId (as a hidden field, using {{ }})
  • _token (as a hidden field, using {{ forms.token }})

Email Preferences

  • preferredFormat - either "html" or "text"
  • marketable - either "yes" or "no"
  • userId (as a hidden field, using {{ }})
  • _token (as a hidden field, using {{ forms.token }})
  • subscriptions - either "subscribed" or "unsubscribed". subscriptions is an advanced field built to handle each subscription your student has for their courses. An individual subscription name must follow the format of subscriptions[{{id}}][status], where {{id}} is the ID of the subscription.

    The layout in a template will look like this:

    	{{#each }}
    	<div class="form-group row c-subscription">
    	    <label for="subscription-{{ id }}" class="col col-12 col-md-8 col-form-label">{{ title }}</label>
    	    <div class="col col-12 col-md-3 offset-md-1">
    	        <select name="subscriptions[{{ id }}][status]" id="subscription-{{ id }}" class="form-control">
    	            <option value="subscribed" {{#eq status "subscribed" }}selected{{/eq}}>Subscribed</option>
    	            <option value="unsubscribed" {{#eq status "unsubscribed" }}selected{{/eq}}>Unsubscribed</option>

Core Components

Now that you've seen the goodies available to you with Advanced Forms, you're probably wondering what a Core Component is.

As mentioned in the introduction, Core Components serve two primary areas: Tables and Interactivity.

Tables are used in a few areas of your site, specifically to show users a list of all of their orders, the payments that are a part of each order, and then to show affiliates various metrics of their performance, like referrals and commissions.

Interactivity relates to interactive course content, such as quizzes, triggering a video player to begin playing, or toggling areas of text to be visible or hidden with the click of a link or button.

Note: Core Components are bundles of HTML or JavaScript. No CSS. Instead of attempting to enforce or apply particular styles for all Core Components, we have left the styling largely up to you. Check out our Component Structure and Style Guide for a deeper look at how they are built and how you can style them.

Let's walk through how to use components, and then we'll review the various components available to you.

Using Core Components

Components often require the page to send additional requests for data, so we use a component loader to display a loading message, while everything is retrieved.

Here's one in action:

<entity-component-loader id="{{ }}" component="affiliate-commissions-table" loading-message="Loading Commissions..."></entity-component-loader>

The above example loads a table (you'll see more of these soon) that display all of the commissions for an affiliate.

The foundation of the component loader is very simple and works similar to many other HTML tags:


In addition to the entity-component-loader tag, there are a few required attributes:

  • id: This is the id of the entity that you are fetching data about. This could be a user, an order, an affiliate, or other entity types.
  • loading-message: What you'd like to display while the data is being retrieved. This will usually display for less than 1 second. The default is "Loading Data...".
  • component: The identifier for which component to use. Examples are "user-orders-table" or "user-payments-table". See below for more examples.

Combine the <entity-component-loader> tag with the attributes listed above, and you're ready to see some dynamic components in action!

Tables in Zippy Courses

Zippy Courses comes pre-loaded with a variety of tables that are designed to be interactive: filterable, sortable, and searchable. This can be very useful for your customers and your affiliates as they review the numerous rows of data in a table.

So what tables are available to you?

  • user-orders-table: A table to display all of a user's orders.
  • user-payments-table: A table to display all of the payments for a particular order.
  • affiliate-commissions-table: A table to show all of the commissions that an affiliate has earned.
  • affiliate-payouts-table: A table that shows all of the payouts that have been made to an affiliate.
  • affiliate-referrals-table: A table that shows all of the referrals that an affiliate has generated.

Quizzes in Zippy Courses

Quizzes in Zippy Courses allow a student to answer all of the questions in a quiz, review and change their answers, and view their results, all without ever having to reload the page.

There are two options for creating the Core Component that will display the quiz in your templates:

  1. Use the pre-generated HTML available to you: {{ entity.quiz.html }}. This will only work for a template that will be used by lessons or quizzes.
  2. Generate your own and include it in a template: <entry-quiz id="{{ }}" lesson-id="{{ }}"></entry-quiz>.

Once one of those two options are in your layout or component, your students will be able to take a quiz!

Additional Components

In addition to the dynamic table components and quiz components, there are a few others that can be used on your site:

  • affiliate-summary: Show the paid, pending, and unpaid amounts that an affiliate has earned. Example: <affiliate-summary id="{{ }}></affiliate-summary>
  • affiliate-link: Show the referral link for an affiliate with a convenient "copy" button. Example: <affiliate-link id="{{ }}></affiliate-link>
  • course-product-dropdown: Show a dropdown of the available products for a course. Example: <course-product-dropdown course="{{ }}></course-product-dropdown>
  • course-product-selector: Show all products for a course in a list, and allow people to select which they would like to purchase. Example: <course-product-selector course="{{ }}></course-product-selector>
  • video-player: Display a video player that can handle videos from YouTube, Vimeo, and Wistia. Example: <video-player url=""></video-player>
  • audio-player: Display an audio player that can handle mp3 and wav files. Example: <audio-player url="" title="Test Audio File"></audio-player>

Smart Attributes

In a few places, Zippy Courses has taken the extra step of adding new attributes to HTML. Our heads aren't so big that we think we're going to change all of HTML everywhere, but at least in your themes, you can have access to some convenient functionality without having to resort to building your own JavaScript to pull it off.

Let's look at a few examples, then walk through them.

Starting a Video Player with an External Button

	<!-- Show the Video Player -->
	<video-player url="" id="featuredMediaVideoPlayer"></video-player>
	<!-- Create a button to start the video player -->
	<a href="" class="btn btn-primary" play-video="#featuredMediaVideoPlayer" hide=".c-featured-media .c-media-overlay"><i class="fa fa-play-circle"></i> Start the Video</a> ```

You may ask yourself, "Why not just use the play button on the video player?" That's a good question. One of the interesting use cases we discovered in our 1k Students theme, which is intended to be used with video, is that having an external button allows us to create a media overlay that is visible before the video is played but is hidden when the button is pressed.

The following attributes are available to help you create a similar solution:

  • play-video (required): Accepts the id of the <video-player> tag. Warning: Be careful not to confuse this with an Entity ID, which is different. Look at the example where featuredMediaVideoPlayer is present as an id attribute on the video-player tag and set in the play-video property of the trigger.
  • hide (optional): A CSS selector, either a class or an ID. When the video begins to play, this selector will be hidden.

Toggling Content Visibility

Sometimes, you would like to control the visibility of content on your page using a link or a button.

How would you do that using Zippy Courses "Smart Attributes"?

	<!-- The link to toggle the content visibility -->

	<a href="" class="btn btn-primary btn-sm" toggles="terms-and-conditions-box" alt-text="Hide Terms">Show Terms</a>

<!-- The content that we are going to be able to toggle -->
<div id="terms-and-conditions-box" class="js-is-closed">
	{{{ settings.affiliate.terms.content }}}

Toggling is composed of two elements: the trigger that controls the visibility of the content and the content that is being toggled.

For the trigger, the following attributes are available:

  • toggles (required): Accepts the HTML id of the content that should be toggleable.
  • alt-text (optional): If you include the alt-text attribute, the content of your trigger will swap between the default value and the alternative whenever it is clicked and the content is toggled.

For the content, the following attributes should be used:

  • id (required): A standard HTML id. It must be unique on your page.
  • class (optional): If you would like your content to initialize being open, use the js-is-open class. For closed, use js-is-closed.

Anything Else?

Not yet! But as Zippy Courses gets bigger and better, we'll be adding more forms, Core Components, and Smart Attributes for you to use in your themes.

We're almost at the end of this support guide series (We know. We'll be sad when it's over too). When you're ready, let's move on to the final part, Core Component Structure and Style.