This tutorial will walk you through creating your first custom theme template. You’ll learn the core concepts by building a simple product page layout with dynamic content.
Prerequisites : Basic knowledge of HTML and CSS. Access to your Quickbutik Control Panel.
What we’ll build
By the end of this tutorial, you’ll have created a custom product page that:
✅ Displays product information dynamically
✅ Shows product images in a gallery
✅ Handles product variants and stock status
✅ Includes an add-to-cart button
Step 1: Access the Theme Editor
First, let’s access your theme files:
Open Control Panel
Log into your Quickbutik store and navigate to Appearance → Theme
Access Code Editor
Click “Under the hood” to open the theme code editor
Find Product Template
Look for the product.html
file in the file list - this controls how individual product pages are displayed
Step 2: Understanding the Basic Structure
Let’s start with a simple product page template:
<!DOCTYPE html>
<html>
<head>
<title>{{product.title}} - {{shop.name}}</title>
<meta name="description" content="{{seo.description}}">
</head>
<body>
<div class="product-page">
<!-- We'll build our product content here -->
</div>
</body>
</html>
Understanding the template tags
Now let’s add the core product information:
Basic Product Info
Stock Status
<div class="product-info">
<h1 class="product-title">{{product.title}}</h1>
<div class="product-price">
{{#product.has_before_price}}
<span class="before-price">{{product.before_price}}</span>
{{/product.has_before_price}}
<span class="current-price">{{product.price}}</span>
<span class="currency">{{product.currency}}</span>
</div>
<div class="product-description">
{{&product.description}}
</div>
</div>
What’s happening here?
Price Display We show both regular and sale prices, with the has_before_price
conditional showing sale pricing only when relevant.
Stock Status Using #
and ^
operators to show different content based on whether the product is sold out.
Localization The {{#lang}}
wrapper automatically translates text based on your store’s language settings.
HTML Content The &
symbol in {{&product.description}}
renders HTML content without escaping it.
Step 4: Product Image Gallery
Let’s create a dynamic image gallery:
<div class="product-gallery">
{{#product.images}}
<div class="gallery-item">
<img src="{{#img}}{{image}}_800x600{{/img}}"
alt="{{alttext}}"
data-id="{{image_id}}">
</div>
{{/product.images}}
{{^product.images}}
<!-- Fallback for products without images -->
<div class="no-image">
<span>{{#lang}}No image available{{/lang}}</span>
</div>
{{/product.images}}
</div>
The {{#img}}
wrapper automatically optimizes images. The _800x600
suffix resizes the image to 800x600 pixels.
Step 5: Product Variants
If your product has variants (like size or color), let’s display them:
{{#product.hasOptions}}
<div class="product-options">
<h3>{{#lang}}Options{{/lang}}</h3>
{{#product.options}}
<div class="option-group">
<label>{{option_title}}</label>
<select name="variant_{{option_title}}">
{{#option_values}}
<option value="{{id}}">{{name}}</option>
{{/option_values}}
</select>
</div>
{{/product.options}}
</div>
{{/product.hasOptions}}
Finally, let’s add a functional add-to-cart button:
<div class="add-to-cart-section">
{{^product.soldOut}}
<form action="/cart/add" method="post">
<input type="hidden" name="product_id" value="{{product.id}}">
{{#product.hasOptions}}
<!-- Include variant selection -->
<div class="variant-selection">
<!-- Variant dropdowns will go here -->
</div>
{{/product.hasOptions}}
<div class="quantity-selector">
<label for="quantity">{{#lang}}Quantity{{/lang}}</label>
<input type="number" name="quantity" value="1" min="1" id="quantity">
</div>
<button type="submit" class="btn-add-to-cart">
{{#lang}}Add to Cart{{/lang}}
</button>
</form>
{{/product.soldOut}}
{{#product.soldOut}}
<button class="btn-sold-out" disabled>
{{#lang}}Out of Stock{{/lang}}
</button>
{{/product.soldOut}}
</div>
Step 7: Complete Example
Here’s your complete product page template:
<!DOCTYPE html>
<html>
<head>
<title>{{product.title}} - {{shop.name}}</title>
<meta name="description" content="{{seo.description}}">
<style>
/* Basic styling */
.product-page { max-width: 1200px; margin: 0 auto; padding: 20px; }
.product-gallery img { max-width: 100%; height: auto; }
.before-price { text-decoration: line-through; color: #888; }
.current-price { font-weight: bold; font-size: 1.2em; }
.out-of-stock { color: #e74c3c; }
.in-stock { color: #27ae60; }
.btn-add-to-cart { background: #3498db; color: white; padding: 12px 24px; border: none; cursor: pointer; }
.btn-sold-out { background: #95a5a6; color: white; padding: 12px 24px; border: none; }
</style>
</head>
<body>
<div class="product-page">
<!-- Product Gallery -->
<div class="product-gallery">
{{#product.images}}
<img src="{{#img}}{{image}}_800x600{{/img}}" alt="{{alttext}}">
{{/product.images}}
</div>
<!-- Product Information -->
<div class="product-info">
<h1 class="product-title">{{product.title}}</h1>
<div class="product-price">
{{#product.has_before_price}}
<span class="before-price">{{product.before_price}}</span>
{{/product.has_before_price}}
<span class="current-price">{{product.price}}</span>
<span class="currency">{{product.currency}}</span>
</div>
<div class="stock-status">
{{#product.soldOut}}
<span class="out-of-stock">{{#lang}}Out of stock{{/lang}}</span>
{{/product.soldOut}}
{{^product.soldOut}}
<span class="in-stock">{{#lang}}In stock{{/lang}}</span>
{{/product.soldOut}}
</div>
<div class="product-description">
{{&product.description}}
</div>
<!-- Product Options -->
{{#product.hasOptions}}
<div class="product-options">
{{#product.options}}
<div class="option-group">
<label>{{option_title}}</label>
<select name="variant_{{option_title}}">
{{#option_values}}
<option value="{{id}}">{{name}}</option>
{{/option_values}}
</select>
</div>
{{/product.options}}
</div>
{{/product.hasOptions}}
<!-- Add to Cart -->
<div class="add-to-cart-section">
{{^product.soldOut}}
<form action="/cart/add" method="post">
<input type="hidden" name="product_id" value="{{product.id}}">
<div class="quantity-selector">
<label for="quantity">{{#lang}}Quantity{{/lang}}</label>
<input type="number" name="quantity" value="1" min="1" id="quantity">
</div>
<button type="submit" class="btn-add-to-cart">
{{#lang}}Add to Cart{{/lang}}
</button>
</form>
{{/product.soldOut}}
{{#product.soldOut}}
<button class="btn-sold-out" disabled>
{{#lang}}Out of Stock{{/lang}}
</button>
{{/product.soldOut}}
</div>
</div>
</div>
</body>
</html>
Step 8: Test Your Template
Save your changes
Click Save in the theme editor
Preview the page
Use the preview function to see your changes on a test product
Test different scenarios
Products with/without images
Products with/without variants
Products that are in stock vs. sold out
Publish when ready
When you’re satisfied, publish your changes to make them live
🎉 Congratulations!
You’ve successfully created your first custom Quickbutik theme template! You now understand:
✅ How to display product data dynamically
✅ How to use conditionals for different states
✅ How to handle product variants and options
✅ How to create functional form elements
Next Steps
Common Issues