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}}">← Previous</a>
</li>
<li class="next">
<a href="{{product.next_url}}">Next →</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
