Theme From Scratch

In this tutorial you will learn how to create a Onigi theme from scratch.

What we need to get started

Partner Accounts allows you to create a free Onigi store you can test on after you sign up. Login into your account and click on the “Referral” tab and click “Create a new affiliate store”.

If you use Textmate on OSX, checkout Meeech’s Textmate bundle so you can edit live Shopify stores from a localhost environment.

If you are wondering the urls in the screenshots use localhost it’s because the screenshots in this tutorial use Vision. Vision allows you to develop Onigi themes on a localhost environment, but it is no longer officially supported by Shopify and it doesn’t support Onigi’s newer features.

5 things you need to know about Onigi

There are 5 fundamental concepts you need to understand before you make a theme

Liquid

Liquid is Onigi’s super simple programming language. There are 2 types of Liquid tags:

  • {% %} this is a logic tag, nothing will visually appear on the screen
  • {{ }} this is an output tag, something will visually appear on the screen

If we want to display our shop’s name, this is the Liquid we use to do it:

<h1>{{ shop.name }}<h1>
Your shop name

Notice how we use {{ }} brackets, if we used
{% %} brackets nothing would’ve appeared on
the screen

Templates

Templates control the CSS and HTML of you shop’s content. Every part of your Onigi website is rendered by a different template. For example, when customer views one of your shop’s products, Onigi will use the product.liquid template to render the product page.

Template Variables

Template variables are the pieces of data we can use in your shop. If we want to get the name of a product we use the product.name variable. If we want to get the name of your store we use the shop.name variable.

Filters

Filters manipulate the output of template variables. If you want to show a customer a price of a 125.000 product and you use the template variable Template:Product.price, Onigi will display the price as 125.000,00 IDR. So we need to use a filter to manipulate the output of this template variable.

The syntax for a filter looks like this: Template:Variablename. Out of all the filters I can choose from, the money_with_currency filter makes the most sense for the example problem. Your code should look like this:

{{ product.price | money_with_currency }}
125.000,00 IDR
Logic

Logic statements are conditional Liquid statements. If we are working on product.liquid template and want to display the message “Free shipping”, but only on products whose price is greater than 1. Since the product will either have a price greater than 1 or less than 1 the if logic statement is the most appropriate statement to use.

{% if product.price > 100 %}
  Free Shipping
{% else %}
  No free shipping
{% end if %}
Summary
  • Liquid – We use Liquid to tell Onigi what to do.
  • Templates – Control the look and feel of your shop.
  • Template variables – Are pieces of data we can use.
  • Filters – Manipulate the outputs of template variables.
  • Logic – Advanced Liquid statements

Let’s Create a theme from scratch

Theme.liquid

What is Theme.liquid? Think of theme.liquid as the master template – all other templates are rendered inside of theme.liquid. If you have any HTML elements that are repeated in your theme (ex: site navigation), put it in theme.liquid.

There are 1 thing that every theme.liquid file needs. The first thing is {{ content_for_layout }} and that belongs in <body></body>.

<!DOCTYPE html>
<html>
<body>
<h1>This is a blank theme</h1>
{{ content_for_layout }}
</body>
</html>
Your first line of Liquid

Lets output the name of our shop using the “shop” template variable with the “name” attribute. Put them both together and you get “shop.name

<h1>{{ shop.name }}</h1>

Now lets add a title tag. page_title is a weird variable. We won’t cover it in this tutorial. We won’t cover those in this tutorial.

<title>{{ shop.name }} - {{ page_title }}</title>

Page.liquid

Page.liquid template generates all of your page content.

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

{{ page.content }} will be where all the content from the page will be generated. The page.title variable returns the title of the page. Try out some more page template variables.

If you want to display snippet contact.liquid, you can add this code:

<div class="detail">

    <div class="clearfix"></div>

    <div class="detailc span6" style="padding: 20px;width: 95%;">
        <h1 style="margin-bottom:15px;padding-bottom:10px;" class="borderBottom">{{page.title}}</h1>

        <div class="clearfix"></div>

        <div>
            <p style="margin-bottom:25px;">

                {% if page.title =='Contact' %}
                {% include 'contact' %}
                {% else %}
                {{page.content}}
                {% endif %}

            </p>
        </div>

    </div>
</div>

Products.liquid

Products.liquid is used for displaying collections of your products (collections can also be thought of “product categories”). In most cases collections will be something like “Shoes” or “Shirts”. To access an example of a collection click on “catalog” in our main navigation.

We are going to use the Tablerow logic statement to generate our collection. In it’s basic form a tablerow logic statement looks like this

<table>
  {% tablerow something in something %}
    do this
  {% endtablerow %}
</table>

Now let’s take the above code and specify what data we want the tablerow to use. In this case we are going to specify all products (products.items). If we wanted to specify a specific collection we could use collection.snowboard or whatever the collection’s handle name might be.

<table>
  {% tablerow  product in products.pagination %}
    do this
  {% endtablerow %}
</table>

Let’s add product images and product prices associated with this collection.

<table>
  {% tablerow product in products.pagination %}

  <div class="image">
    <a href="{{ product.url | within: collection }}" title="{{ product.title }}">

    <img src="{{ product.pictures | product_img_url: 'small' }}" alt="{{ product.name }}" />

    </a>
  </div>

  <div class="description">
    <a href= "{{ product.url | within: collection }}">{{ product.name }}</a>
    <br />
    <small>{{ product.price }}</small>
  </div>

  {% endtablerow %}
</table>

There are some issues with the above code. The first one is our table doesn’t have any columns. To fix that we use an attribute called “cols”. An attribute is something that modifies the output of a logic statement (in this case our logic statement is a tablerow). This is how we add an attribute:

{% tablerow product in products.pagination cols:3 %}

Another problem is our price for the products is messed up. That’s because we need to use a filter to modify the output of the template variable. In other words we need to apply the “money” filter to the “product.price” variable.

<small>{{ product.price | money_without_currency }}</small>

Let’s add some more filters…

 <div class="image">
    <a href="{{ product.url | within: collection }}" title="{{ product.name }}">
      <img src="{{ product.pictures.first | product_img_url: 'small' }}" alt="{{ product.name }}" />
    </a>
  </div>

  <div class="description">
    <a href= "{{ product.url | within: collection }}">{{ product.name | truncate: 30 }}</a><br />
    <small>{{ product.price | money }}</small>
  </div>

Here is a quick description on what they do

  • within:collection – If the product is in a custom collection it will put the collection name in the url instead of the regular /products url.
  • product_img_url: ‘small’ – we are specifying the image size from the three sizes we can use.
  • truncate: 30 – truncate the number of characters by 30
  • money – makes prices look nice

Sometimes our collections will have too many products in them and we need to use multiple pages. To create multiple pages we use pagination.

{% paginate products.pagination by 12 %}

<table class = "products">
 ... your table code ....
</table>

{% if products.pagination > 1 %}
  <div id="paginate">
    {{ paginate | default_pagination }}
  </div>
{% endif %}
{% endpaginate %}

If a collection is empty we want to make sure the user doesn’t just see a blank page, so we add a simple “if” logic statement

{% paginate products.pagination by 12 %}

{% if products.pagination == 0 %}
No products found in this collection.
{% else %}

...table stuff...

....pagination stuff...

{% endif %}

{% endpaginate %}

The following code example lists all products.

{% assign idx = 1 %}
{% for product in products.items %}
{% if idx == 1 %}
<div class="products row">
    {% endif %}

    <li class="span2">
        <div class="thumbnail">
            <div style="width:236px;height:163px;text-align: center">
                <a href="{{product.link}}">
                    <img src="{{product.picture}}" alt="Toko Online Onigi {{product.name}}" style="max-width:236px;height: 163px; margin-top: 10px;">
                </a>
            </div>

            <div class="caption" style="height:50px;text-overflow:ellipsis;margin-top: 10px;">
                <a href="{{product.link}}"><h5 style="font-weight: normal;text-align: center; margin-bottom: 5px;font-size:14px;">{{product.name}}</h5>
                </a>
                <h4 style="text-align: center;">{% if product.is_discount %}{{product.discount_price  | money}}{% else %}{{product.price  | money}}{% endif %}</h4>
            </div>
            <div class="shares" rel="{{product.url}}">
                <div class="fb">
                    <a href="#"> 0</a>
                </div>
                <div class="comment">
                    <a href="{{product.url}}#fb-comment"> 0</a>
                </div>

                <div class="share">
                    <div class="btn-group dropup">
                        <a href="#" class="dropdown-toggle" data-toggle="dropdown"> Share </a>
                        <ul class="dropdown-menu">
                            <li>
                                <div class="fb-like" data-href="{{product.url}}" data-send="false" data-layout="button_count" data-width="80" data-show-faces="false"></div>
                                <a href="https://twitter.com/share" class="twitter-share-button" data-url="{{product.url}}" data-text="[Product Name]" data-via="onigiid" data-related="onigiid">Tweet</a>
                            </li>
                        </ul>
                    </div></div>

            </div>
        </div>
    </li>
    {% assign idx = (idx + 1 % 3) %}
    {% if idx == 0 %}
</div>
{% elsif forloop.index == forloop.length %}
</div>
{% endif %}
{% endfor %}

If you want to show products items where category is 12, show per page is 12, page is 5 :

{% assign idx = 1 %}
{% for product in products.items category:12 per_page: 12 page:5 %}
{% if idx == 1 %}
<div class="products row">
    {% endif %}

    <li class="span2">
        <div class="thumbnail">
            <div style="width:236px;height:163px;text-align: center">
                <a href="{{product.link}}">
                    <img src="{{product.picture}}" alt="Toko Online Onigi {{product.name}}" style="max-width:236px;height: 163px; margin-top: 10px;">
                </a>
            </div>

            <div class="caption" style="height:50px;text-overflow:ellipsis;margin-top: 10px;">
                <a href="{{product.link}}"><h5 style="font-weight: normal;text-align: center; margin-bottom: 5px;font-size:14px;">{{product.name}}</h5>
                </a>
                <h4 style="text-align: center;">{% if product.is_discount %}{{product.discount_price  | money}}{% else %}{{product.price  | money}}{% endif %}</h4>
            </div>
            <div class="shares" rel="{{product.url}}">
                <div class="fb">
                    <a href="#"> 0</a>
                </div>
                <div class="comment">
                    <a href="{{product.url}}#fb-comment"> 0</a>
                </div>

                <div class="share">
                    <div class="btn-group dropup">
                        <a href="#" class="dropdown-toggle" data-toggle="dropdown"> Share </a>
                        <ul class="dropdown-menu">
                            <li>
                                <div class="fb-like" data-href="{{product.url}}" data-send="false" data-layout="button_count" data-width="80" data-show-faces="false"></div>
                                <a href="https://twitter.com/share" class="twitter-share-button" data-url="{{product.url}}" data-text="[Product Name]" data-via="onigiid" data-related="onigiid">Tweet</a>
                            </li>
                        </ul>
                    </div></div>

            </div>
        </div>
    </li>
    {% assign idx = (idx + 1 % 3) %}
    {% if idx == 0 %}
</div>
{% elsif forloop.index == forloop.length %}
</div>
{% endif %}
{% endfor %}

If you want to show pagination:

<ul>
    {% for pg in products.pagination %}
    <li {% if pg.class == 'current'%} class="active" {% endif%}><a href="{{pg.link}}">{{pg.index}}</a></li>
    {% endfor %}
</ul>

Product.liquid

This template will display the individual products to the customer. For the sake of space this tutorial will not cover products with multiple options (products with more than one attribute, like a product with size and color).

Let’s generate our product title and product description and test to see if the product is available

<h2>{{ product.name }}</h2>
{{ product.description }}

{% if products.items %}
   This product is available!
{% else %}
   Sorry, the product is not available
{% endif %}

If you want to show product picture:

{% for picture in product.pictures%}
 <div class="item {% if forloop.index == 1 %} active{% endif %}">
   <a href="#" class="thumbnail">
      <img src="{{picture.large}}" alt="Toko Online Onigi {{ product.name }}" style="max-height:268px;max-width:360px;">
   </a>
 </div>
{% endfor %}

If you want to show detail product:

<div class="detailc">
    <div class="leftdetail" style="margin-left: 30px;">
        <ul>
            <li>
                <div id="productCarousel" class="carousel">
                    <!-- Carousel items -->
                    <div class="carousel-inner">
                        {% for picture in product.pictures%}
                        <div class="item {% if forloop.index == 1 %} active{% endif %}">
                            <a href="#" class="thumbnail">
                                <img src="{{picture.large}}" alt="Toko Online Onigi {{ product.name }}" style="max-height:268px;max-width:360px;">
                            </a>
                        </div>
                        {% endfor %}
                    </div>

                </div>
            </li>
            {% if product.pictures%}
            {% for picture in product.pictures%}
            {% if forloop.index > 1 %}

            <li style="width:115px; float:left; margin-top:10px;margin-right:4px;margin-left:4px;">
                <a href="#" class="thumbnail" onclick="$('#productCarousel').carousel({{forloop.index0}})">
                    <img src="{{picture.small}}" alt="Toko Online Onigi  photo_{{forloop.index}}" style="max-width: 60px;max-height: 60px;">
                </a>
            </li>
            {% endif %}
            {% endfor %}
            {% endif %}
            </li>

    </div>

    <div class="well rightdetail">

        <h2 style="margin-bottom:5px;" class="borderBottom"><a href="#"></a><a href="#">{{product.name}}</a></h2>
        <h3 style="margin-bottom:10px;margin-top:15px;"> {% if product.is_discount %}<strike>{{product.price | money}}</strike>{{product.discount_price  | money}}{% else %}{{product.price  | money}}{% endif %}</h3>
        <div class="description">{{product.description}}</div>

        <form method="POST" id="product_cart">
            {% if product.variations %}
            {% for variation in product.variations %}

            {{variation.name}}: 

            <select name="variations[]" onchange="product_cart.submit();">
                {% if variation.values %}
                {%  for value in variation.values %}
                <option value="{{value.id}}" {% if value.selected %}selected=""{% endif %}>{{value.name}}</option>
                {% endfor %}
                {% endif %}
            </select>

            <div class="clearfix" style="margin-top:10px"></div>

            {% endfor %}
            {% endif %}

            {% if shop.package == 'shopping' %}
            <div style="float:left; margin-right:10px;margin-top:5px;">
                Quantity:
            </div>

            <input class="span1" name="quantity" type="text" placeholder="1" value="1" style="width: 25px;text-align: center;">

            <div class="clearfix" style="margin-top:30px"></div>
            {% if product.stock > 0 %}
            <button id="fat-btn" type="submit" name="add_to_cart" class="btn btn-success btn-large">
                <i class="icon-shopping-cart icon-white"></i> Add to cart
            </button>
            {% else %}
            <input id="fat-btn" class="btn btn-danger disabled" type="button" value="Out of stock" class="add_cart_button"/>
            {% endif %}
            {% else %}
            <a href="{{product.link}}" target="_blank"  class="btn btn-success btn-large">
                <i class="icon-shopping-cart icon-white"></i> Go to product
            </a>
            {% endif %}

        </form>

    </div>

    <div class="clearfix"></div>

    <div class="holder">
        <div style="width:785px; margin-left:28px; margin-top:20px;">
            <ul class="pager">
                <li class="previous">
                    <a href="{{product.prev_url}}">&larr; Previous</a>
                </li>
                <li class="next">
                    <a href="{{product.next_url}}">Next &rarr;</a>
                </li>
            </ul>
        </div>
    </div> 	

    <div class="span6" style="margin-left:28px; margin-top:30px;" id="fb-comment">
        <div class="fb-comments" data-href="{{shop.current_url}}" data-num-posts="2" data-width="790"></div>

    </div>

</div>
Add to cart

Use a <form> with the action=”/cart/add”. You need to loop through any variants a product may have. Variants are just variations of an individual product like size or color

...{% if products.items %}

<form action="/cart/add" method="post">
    <select id="product-select" name='id'>

      {% for variant in product.variations %}
      <option value="{{ product.id }}">{{ product.name }} - {{ product.price | money }}</option>
      {% endfor %}

    </select>
  <input type="submit" value="Add to cart" id="addtocart" />
</form>

{% else %}....
Adding images

First we need to loop through all the images in product.images and if the image is the first image we want to make that a big image

{% for image in product.pictures %}

 {% if forloop.first %}

  <div id="first-image">
  <a href="{{ image | product_img_url: 'large' }}" title="{{ product.name }}">
  <img src="{{ image | product_img_url: 'medium' }}" alt="{{ product.name | escape }}" /></a>
 </div>

  {% else %}

   <div class="product-images">
     <a href="{{ image | product_img_url: 'large' }}"  title="{{ product.name }}">
     <img src="{{ image | product_img_url: 'small' }}" alt="{{ product.name | escape }}" /></a>
</div>

 {% endif %}

{% endfor %}

Cart.liquid

This is the shopping cart template.

What if the cart’s empty?

Definitely room for you to be creative here, but let’s keep it short and sweet

<h2>Shopping Cart</h2>
{% if cart.items == 0 %}
  <p>Your shopping basket is empty.</p>
{% else %}
  do stuff
{% endif %}
The fat ass Cart table

The only 3 important things to pay attention to is the

uses the action /cart, we loop through each of the items in the user’s cart by using {% for item in cart.items %} and the 2 submit buttons at the bottom to update and checkout.

<div id="table_cart"><!--table cart starts-->
<table id="shop_cart">
  <tr class="cart_header">
	<th>No.</th>
	<th>Product Name</th>
	<th>Quantity</th>
	<th>Price</th>
	<th>Subtotal</th>
	<th>&nbsp;</th>
  </tr>

  {% if carts.items %}
	{% for cartitem in carts.items %}
	  <tr>
		<td>{{forloop.index}}</td>
		<td>
		  {{cartitem.product_name}}
		  {% if cartitem.product_variation %}
			<br/>
			<small>{{cartitem.product_variation}}</small>
		  {% endif %}
		</td>
		<td><form method="POST" id="frm-cart-{{cartitem.cart_id}}"><input type="hidden" name="id" value="{{cartitem.cart_id}}"/><input type="hidden" name="action" value="update"/> <input type="text" name="quantity" value="{{cartitem.quantity}}" style="width:50px;"/></form></td>
		<td style="text-align: right">{{cartitem.price | money}}</td>
		<td style="text-align: right">{{cartitem.subtotal | money}}</td>
		<td><form method="POST" style="display:inline"><input type="hidden" name="id" value="{{cartitem.cart_id}}"/><input type="hidden" name="action" value="remove"/><button type="submit" style="background: none;border: none;"><img src="images/bstop.png" title="Remove"/></button></form><a href="#" onclick="document.getElementById('frm-cart-{{cartitem.cart_id}}').submit()"><img src="images/reload.png" title="Refresh"/></a>
		</td>
	  </tr>
	{% endfor %}
	<tr>
	  <th colspan="4" style="text-align: right">
		SUBTOTAL
	  </th>
	  <th style="text-align: right" >
		{{carts.price | money}}
	  </th>
	  <th >&nbsp;</th>
	</tr>
	{% else %}
	  <tr>
		<td colspan="5">No Product In Your Cart</td>
	  </tr>
  {% endif %}
</table>
</div><!--table cart-->

<div style="clear:both;"></div>
<div id="button">
<a class="checkout_button" href="{{shop.url}}"><span> Continue Shopping</span></a>
<a class="checkout_button" href="{{checkout_url}}"><span> Check Out</span></a>
</div>  <!--button- ends-->

If you want to checkout shopping:

<table class="checkout span6" style="margin-left:0;">
                <thead>
                    <tr>
                        <th class="titleproduct"><h3 class="first">Product</h3></th>
                <th class="titlequantity"><h3>Quantity</h3></th>
                <th class="titleprice"><h3>Price</h3></th>
                <th class="titlesubtotal last"><h3 class="last">Subtotal</h3></th>
                </tr>
                </thead>
                <tbody>
                    {% for cartitem in carts.items %}
                    <tr>
                        <td class="product first"><img src="{{cartitem.product_picture}}" width="55px"/> {{cartitem.product_name}}</td>
                        <td class="quantity"><form method="POST" id="frm_update_{{cartitem.cart_id}}" style="display:inline" name="frm_update_{{cartitem.cart_id}}">
                                <div class="quantity">
                                    <input type="hidden" name="id" value="{{cartitem.cart_id}}"/>
                                    <input type="hidden" name="action" value="update"/>
                                    <input style="width:30px;text-align:center;" type="text" name="quantity" placeholder="1" value="{{cartitem.quantity}}">
                                    <a href="#" onclick="document.frm_update_{{cartitem.cart_id}}.submit()"><i class="icon-refresh"></i></a>
                            </form>
                            <form method="POST" id="frm_remove_{{cartitem.cart_id}}" style="display:inline" name="frm_remove_{{cartitem.cart_id}}">
                                <input type="hidden" name="id" value="{{cartitem.cart_id}}"/>
                                <input type="hidden" name="action" value="remove"/>
                                <a href="#" onclick="document.frm_remove_{{cartitem.cart_id}}.submit()"><i class="icon-trash"></i></a>
                            </form>
                            <div>
                        </td>
                        <td class="price">{{cartitem.price | money}}</td>
                        <td class="subtotal last">{{cartitem.subtotal | money}}</td>
                    </tr>
                    {% endfor %}
                </tbody>
            </table>

The End

This is the end of the tutorial for now. I missed out a few Shopify templates like search and blog – I’ll write about those eventually, but I’m sure you can figure them out by yourself. I recommend visiting the Onigi theme store and downloading a free theme like Woodland or Oynx so you can see other designer’s Onigi code.

So what’s next?

Learn how to display an image in your theme
Make your theme customizable with theme settings
Learn more about the variables , Filters or Logic statements you can use in Onigi.
Bookmark the Onigi Cheat Sheet
If you have questions on liquid or having trouble making your code work then head over to the designer forums.