Shopify Theme Guide

From Shopify Wiki

(Redirected from The Shopify Theme Guide)
Jump to: navigation, search

Contents

General

This guide is intended for people who want to create a theme for their own or for a client's shopify-shop. In this case, this guide is written so that everyone can make a theme, with a basic knowledge of HTML, CSS and a bit programming, and of course the gift of creativity. ;)

Think like a Customer

The most essential step in designing your shop is to think from the perspective of the customer, but also keep in mind what kind of shop you are designing. In most cases you want to sell products, in some cases you want to present your products. There are two kinds of customers: The informed customer that already knows what he wants to buy, and the other one who wants to find more detail about the product(s).

Liquid - The Templating Engine

What is Liquid?

Liquid is the templating engine developed for and used by Shopify, which processes template files with the ".liquid" extension. The template engine searches in the template file for specified placeholders in the file and processes them. This simply enables you to create your own customized templates.

Liquid files are just HTML files with embedded code in them. This embedded code is tagged with different Markups.

Markups

Liquid uses two different types of markup: Output and Tag.

Output

The Output markup is used to output a variable or a string. This variable has to be surrounded by two curly brackets.

Example:

{{ variable }}
{{ string }}

Simple Output

The developers of an application may assign, as I guess they do, different variables to be used in a Liquid template. These variables can be

A Shopify Example:

{{ product.title }}

This would return the contents of the variable product.title.

Filters (Advanced Output)

With Filters, you can process the given variable or string in an output. Filters are very helpful, most of them support creating URLs or different HTML-Tags. Some also provide simple methods to transform text.

A simple example: {{ 'picture.gif' | img_tag }} generates the following HTML: <img src="picture.gif" alt="" />

You may also use more than one filter. In this case, you have to consider that the result of the previous filter is the first parameter of the current one.

Example:

{{ 'picture.gif' | asset_url | img_tag }
# gives you the following HTML
<img src="/files/shops/random_number/assets/picture.gif" alt="" />

Explanation: 'picture.gif' is the given to asset_url, the result of the filter "asset_url", in this case "/files/shops/random_number/assets/picture.gif", will be given to the filter "img_tag" as the first variable. "img_url" uses the first variable as the "src"-attribute in the img-tag, the second variable that you can give the "img_tag"-filter is to be used as the "alt"-attribute. The above example would look like this:

 {{ 'picture.gif' | asset_url | img_tag: 'The Picture' }
# gives you the following HTML
<img src="/files/shops/random_number/assets/picture.gif" alt="The Picture" />

Image:chain_of_filters.jpg You can find all supported filters in Shopify at the end of this document [Link]

2.4. Tags

Liquid also allows you to "program" your theme. It provides simple expressions which are very useful in your template. These Tags are surrounded by curly brackets and percent signs:

 
 {% tag %}
 

One of the simplest tags in Liquid is the "comment" / "endcomment" pair which only swallows the content within it.

Example:

     
{% comment %}
 Comment Content
{% endcomment %}

#->

Comment Content

 

If/Else

Let's get more advanced! The If/Else conditional statements should be well known from other programming languages. It is used as follows:

An in words example:

 
If the product has images
-> show them
if not
-> show the "has no images"-image
end
 

In code:

 
{% if product.images != nil %}
   {{ product.image | product_img_url: 'small' | img_tag }}
{% else %}
   {{ 'empty.gif' | asset_url | img_tag }}
{% endif %}
 

If the statement expression results "true" it will be executed; otherwise the "else" will be executed.

As in every other programming language, you can use different operators for an if-expression. There are several operators in Liquid:

== equal to != not the same as > bigger than >= bigger than or equal to < smaller than <= smaller than or equal to

If you do not set an operator in the condition, it will simply test whether the collection or variable is not nil, so we can write the above example like this:

 
{% if product.images %}
   {{ product.image | product_img_url: 'small' | img_tag }}
{% else %}
   {{ 'blank.gif' | asset_url | img_tag }}
{% endif %}
 

Case Statement

The case statement is another important expression in programming languages. It is used to pass a variable through different "if" clauses.

In Words:

 
Is the current template...
...a blog
-> give the body the id "page-blog"
...a product-page
-> give the body the id "page-product"
...a collection-page
-> give the body the id "page-collection"
...the index page
-> give the body the id "page-index"
...if nothing matched above
-> give the body the id "page-page"
 

In Code:

 
{% case template %} 
{% when 'blog' %} 
    <body id="page-blog">
{% when 'product' %}
    <body id="page-product">
{% when 'collection' %}
    <body id="page-collection">
{% when 'index' %}
    <body id="page-index">
{% else %}
    <body id="page-page">
{% endcase %}
 

Unlike if/else statements, case statements do not support operators, so you can only use exact matchings.

For loop

The variable product.images gives you back an array, with all product-images in it. To output all the images you will need the for-loop.

In Words:


for all images in product.images
-> make a image tag

In Code:

 
{% for image in product.images %}
 {{ image | product_img_url | img_tag }}
{% endfor %}
 

The variable image after "for", hasn't to be image, or in an other case, the singular of the following. you can assign almost every string.

Example:

 
{% for m in product.images %}
   {{ m | product_image_url | img_tag }}
{% endfor %}
 

As you can see, you can use the variable after "for" within the loop as a reference for the item in the product.images-array.

There are also pre-defined variables in Liquid you can use (only) in a For-loop:

forloop.length Gives you the number of loops, it has to do.

forloop.index Gives you the index number of the current iteration.

forloop.index0 Is only the zero based version of forloop.index. For Example: 02

forloop.rindex Gives you the number of iterations are still left.

forloop.rindex0 Zero based version of forloop.rindex

forloop.first If the current iteration is the first one it will give you true.

forloop.last If the current iteration is the last on it will give you true.

You can also define the attributes offset to tell the for-loop with which item it should start. Or you can define a limit to tell how many items it should loop.

For the following Examples we use an array of numbers.

Example for offset:

 
{% for number in number-array offset: 3%}
  {{ number }}
{% endfor %}
 

The result would be: 4, 5, 6, 7 ...

Example for limit:

 
{% for number in number-array limit: 2 %}
  {{ number }}
{% endfor %}
 

The result would be: 1, 2

Example for offset and limit:

 
{% for number in number-array limit: 3 offset: 3%}
  {{ number }}
{% endfor %}
 

The result would be: 4, 5, 6

Cycle

The best Example of using Cycle: you want to give every first row the class "green" and every second the class "yellow"

Example:

 
<table>
    <tr {% cycle: 'green', 'yellow' %}>
       <td>The Green Row</td>
    </tr>
    <tr {% cycle: 'green', 'yellow' %}>
       <td>The Yellow Row</td>
    </tr>
    <tr {% cycle: 'green', 'yellow' %}>
       <td>Another Green Row</td>
    </tr>
    <tr {% cycle: 'green', 'yellow' %}>
       <td>Another Yellow Row</td>
    </tr>
</table>
 

What happens? By calling {% cycle: 'green', 'yellow' %} Liquid creates a group and returns the first variable, if you call the group a second time, it will return the second variable and if you call it a third time it will return the first variable and so on, and so on. You can give the group as many variables as you need. Every group you create will be available throughout the whole template, so if you would call this group a fourth time anywhere in your template it will return the second variable.

If you need more than one group in a template, I highly recommend giving them group-names!

Example:

 
{% cycle 'group 1': 'green', 'yellow' %}
{% cycle 'otherone': 'nice', 'bad' %}
 

Assign

The Assign tag makes it possible to assign a name to a variable which you can then use in your template.

Example:

 
{% assign short = shop.name %}
{{ short }}
 

I actually can't imagine why and in which case you would use this, but if you use it be careful by naming the new variable. For example if you assign shop.name to the new variable shop all following shop. variables in the current template will become useless!

Vision - The Designer Toolkit

That is what you came for, I guess. Vision is a very cool tool! It lets you run a "virtual" instance of a Shopify Shop, to develop and test your theme. It actually comes with a little database of a "Snowboard"-shop.

Get it!

Downloads for Vision are available at the official website under "http://vision.shopify.com/":http://vision.shopify.com/. The changelog for Vision is located "here":http://vision.shopify.com/update.html. The current Vision version is 3.4.0 (17 Oct 2008).

Preview a Sample Theme

After downloading and extracting Vision, open the folder "themes". You will see there are already two themes. Open one of them.

The Assets Folder

In the assets folder you store every image, .css, and .js files you need for your theme. In the templates you can access them with the "asset_url" filter.

The Assets folder is flat: it cannot contain subfolders. Be aware of this when you edit your theme on your local machine using Vision!

The Layout Folder and The Theme Template

The folder "layout" includes just one file, named "theme.liquid". This file combines all other templates. In this file you give your theme the layout. The other templates are included by the output {{ content_for_layout }} .

Recommended items for your template:

Navigation Shop Name Cart status

I'll show you later how to accomplish this.

The Templates Folder

In this folder you find every other template file, for each section in Shopify there is an other file. Page pages are equal to page.liquid Blog pages are equal to blog.liquid Product pages are equal to product.liquid Collection pages are equal to collection.liquid The Cart page is equal to cart.liquid

The Blog Template

A shop can have a blog. And every blog has articles. You can get the collection of blog articles with blog.articles. Each article has the following attributes:

id title content author created_at

created_at gives you the date in this format 2005-04-04 16:00, but you can simply reformat it by the date filter this would look like this:

 
{{ article.created_at | date: '%A, %d.%m.%y }}
 

This returns the above mentioned date in this Format: "Monday, 04.04.05"


I don't have to explain the others, or?

The Cart Template

At this page the user gets a summary of all his added products, which you get by the collection cart.items. The items in the cart.items collection have the attributes:

id variant product title subtitle price line_price tax quantity

Each product has, or might have, different variants with variant you get all attributes of this variant. With product you also get all attributes of the current product.

The price attribute is given to you as a number, which you have to reformat with the money filter or the money_with_currency filter. The attribute line_price, which returns the quantity times price.

The Index Template

Also known as frontpage, this is the first page the user will see. The frontpage can have "featured" products and articles from a blog. The featured products collection you get with collections frontpage.products and have all product attributes. The articles come from blogs.frontpage.articles; they also have the same attributes as the articles in the blog-template. Keep in mind that having articles and/or featured products on the frontpage is optional.

The Collection Template

The collection page is an overview of products, which are reachable in the collection products.

The Page Template

A page is just content which has a title and content.

The Product Template

It has all relevant information about a product. Such as vendor, variants or type.

The Logic

To understand how shopify handles products, product-types or the vendor. You might ask, "Where is the vendor page with all of this vendor's products?" or "How do I get there?" Let me explain. Shopify has a SmartCollection system. This SmartCollections system is very simple. Let's say you have a "category" 'Records', now you have different types of records, like 'CDs', 'Vinyl' or 'Tapes'. You create a SmartCollection and add the product types CD, Vinyl and Tape. A Tape will be present in "/collections/tapes" as well as "/collections/records". That's not all. The system also has also a "collections" page for the vendor, so if the vendor is "xy", the tape would also be present in "/collections/xy". Very simple, isn't it?

Start it!

Ok, enough theory, let's start Vision by double-clicking the nice icon. On Mac OS X the .app, and on Windows the .exe file. In Linux, run the /vision/vision.rb in your shell file.

The Dashboard

The Dashboard is the page you actually should see after Vision started. You see there are three sections, "Create", "Modify" and "Export". Select a theme in the "Modify" box.

The Designer Toolbar

It allows you to switch between template-files and between the themes.

Play around and than go ahead with reading

[Tutorial] A Shopify Theme from scratch

Now, we will create a fresh new theme we will make it "text"-based so that you can easily go ahead and modify it to your believe.

First of all we need a template folder. Create a folder in the "themes" folder and open it. You may remember we also need three other folders in the folder we just created. Your folder structure should be as follows:

scratch-folder ' assets ' layout ' templates

Next we will create the file 'theme.liquid' in the folder 'layout'.

your file should look like this:

 
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
	"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
	<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
	<title> </title>
</head>

<body>


</body>
</html>
 

I hope you use XHTML We only need the base construct of XHTML only in this file the others will get wrapped by this one.

Next we are going to add the main navigation. All links for this navigation are in the linklists.main-menu.links collection. We are simply doing a for loop and to return all links and separate them by a | symbol. The code we add after the body tag looks like this:

 
<div id="navigation">
 {% for link in linklists.main-menu.links %}
    {{ link.title | link_to: link.url }} {% if forloop.rindex != 1 %} | {% endif %}
 {% endfor %}
</div>
 

We have now added the main navigation. I have put it into a div and with the id "navigation". I also told Liquid in the "for-loop" to add a "|" if the current iteration is not the last one.

Now we need to add the "content" by adding {{ content_for_layout }} , I think we also should put it into a div and give it the id "content". We add:

 
<div id="content">
 {{ content_for_layout }} 
</div>
 

The last things we add is the shop.name variable in the title-tag and somewhere on the page. We are also adding a footer:

 
<div id="footer">
{% for link in linklists.footer.links %}
    {{ link.title | link_to: link.url }} {% if forloop.rindex != 1 %} | {% endif %}
{% endfor %}
</div>
 

theme.liquid should look like this:

 
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
	"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
	<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
	<title>{{ shop.name }}</title>
        {{ content_for_header }}
</head>

<body>
<div id="header">
	{{shop.name}}
</div>
<div id="navigation">
 {% for link in linklists.main-menu.links %}
    {{ link.title | link_to: link.url }} {% if forloop.rindex != 1 %} | {% endif %}
 {% endfor %}
</div>

<div id="content">
 {{ content_for_layout }} 
</div>

<div id="footer">
{% for link in linklists.footer.links %}
    {{ link.title | link_to: link.url }} {% if forloop.rindex != 1 %} | {% endif %}
{% endfor %}
</div>
</body>
</html>
 

The next file we are going to create is the file "index.liquid" in the "templates" folder. I told you this site can have featured products so let's add the code to display them.

 
{% for product in collections.frontpage.products cols:3  %}
   <h3><a href="{{product.url}}">{{product.title}}</a></h3>
   <a href="{{product.url}}"><img src="{{ product.featured_image | product_img_url: 'small' }}" /></a>
   <div class="money">{{product.price_min | money}}</div>
{% endfor %}
 

So, it's your turn! I told you on the frontpage are also articles so add them... ... did you get code like this:

 
{% for article in blogs.frontpage.articles  %}
   <h3>{{ article.title }}</h3>      
   {{ article.content }}     
{% endfor %}
 

... than we can create the next file 'collection.liquid'

 
<table id="products" cellspacing="0" cellpadding="0">
{% tablerow product in products cols:3  %}
  <div class="product">
     <h3><a href="{{product.url}}">{{product.title}}</a></h3>
     <div class="product-image"><a href="{{product.url}}"><img src="{{ product.featured_image | product_img_url: 'small' }}" alt="{{ product.title }}" /></a></div>
     <div class="money">
       {{product.price_min | money}}
     {% if product.price_min != product.compare_at_price %}
       <div class="original-price">            
       {{product.compare_at_price | money}}
       </div>
     {% endif %}
     </div>
  </div>
{% endtablerow %}
</table>
 

Add code like this.

I didn't tell you about tablerow? it's just a for loop that generates a tablerow for each iteration. Nothing really special.

What else is needed? The following pages are left:

 page.liquid
 blog.liquid
 cart.liquid
 product.liquid

Let's go ahead with the easy ones, let's create 'blog.liquid'

 
  <h2>{{page.title}}</h2>
   {% for article in blog.articles  %}
      <h4>{{ article.created_at | date: '%d %b' }} {{ article.title }}</h4>
      {{ article.content }}
  {% endfor %}
 

next very easy... 'page.liquid'

 
<h2>{{page.title}}</h2>
  {{ page.content }}
 

for the template 'product.liquid' we use the following code:

 
<img src="{{product.featured_image | product_img_url: 'large'}}" alt="{{product.title}}" />
<h2>{{ product.title }}</h2>
<ul>
    <li>Vendor: {{product.vendor | link_to_vendor }}</li>
    <li>Type: {{product.type | link_to_type }}</li>
</ul>  
{{ product.price_min | money }}{% if product.price_varies %} - {{ product.price_max | money }}{% endif %}
    {{ product.body }}

    <form action="/cart/add" method="post">
      <!-- Return to product instead of going to cart
      <input type="hidden" name="return_to" value="back" />
      -->
      <h3>Variations of this product</h3>
      <ul>
        {% for variant in product.variants %}
        <li>
          {% if variant.available == true %}
            <input type="radio" name="id" value="{{variant.id}}" id="radio_{{variant.id}}" style="vertical-align: middle;" {%if forloop.first%} checked="checked" {%endif%} />
            <label for="radio_{{variant.id}}">{{ variant.price | money_with_currency }} - {{ variant.title }}</label>
          {% else %}
            <span>Sold Out! - {{ variant.title }}</span>
          {% endif %}
        </li>
        {% endfor %}
      </ul>
        <input type="submit" name="add" value="Add to Cart" id="add" class="primary" />  
    </form>

 

In this example code we use only the featured image, modify it to use all images.

last but not least: 'cart.liquid'

 
{% if cart.item_count == 0 %} 
    <p>Your shopping cart is empty...</p>
{% else %}
  <form action="/cart" method="post" id="cartform">
  <input type="submit" value="Continue to checkout" name="checkout" /> %uFFFD  
  <h3>You have selected the items below for purchase</h3>
      {% for item in cart.items %}
      <h3>{{ item.title }}</h3>
        <div>
          <img src="{{item.product.featured_image | product_img_url: 'thumb' }}" alt="{{item.title}}" title="{{item.title}}" />
        </div>
       <span>{{ item.line_price | money}} each.</span>
       <label for="updates">Quantity</label> 
          <input type="text" size="4" name="updates[]" id="updates_{{item.variant.id}}" value="{{item.quantity}}" onfocus="this.select();"/><br />
      {% endfor %}
      <p>
        <input type="submit" id="update-cart" name="update" value="Update My Cart" />
        Subtotal: 
        <span>{{ cart.total_price | money_with_currency }}</span>
      </p>
  </form>
{% endif %}
 

You might have noticed this example has no possibility to remove an item or to modify the quantity in an easy way. To remove a item you have to set the quantity to 0 and update the cart. So be creative! You have now a very very simple theme to modify.

So, I hope you enjoyed reading.