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
Make sure you clicked Save and try clearing your browser cache. Some changes may take a few minutes to appear.
Check that you’re viewing the template on a product page. Some data is only available on specific page types.
Remember that your theme’s CSS file controls the visual appearance. The template only handles the HTML structure and dynamic content.