⌕
No references found
Try a broader term or switch back to all references.
Reset search
The smallest useful map from a blank folder to a valid Jualify theme package.
Package Required
Minimum theme package
Place theme.json at the ZIP root. Wrapper folders are rejected.
theme.json
layout/theme.liquid
templates/index.json
sections/hero.liquid
config/settings_schema.json
config/settings_data.json
locales/en.default.json
assets/theme.css
Syntax
Output, logic, filters
Output uses double braces. Logic uses tag delimiters. Filters transform values.
{{ product.title }}
{% if product.available %}In stock{% endif %}
{{ product.price | money }}
02 Files that fit together
Theme structure
Jualify uses a manifest, JSON templates, Liquid layouts, ordered sections, snippets, settings, locales, and assets.
theme.json
Manifest
Declare the Liquid engine, API version, default layout, capabilities, and every supported template.
{
"name": "Aurora",
"handle": "aurora",
"version": "1.0.0",
"author": "Your studio",
"engine": "liquid",
"theme_api_version": "1",
"layout": "theme",
"capabilities": ["ecommerce", "json_templates", "sections"],
"templates": ["index", "collection", "product", "cart"]
}
templates/*.json
Ordered JSON template
Every ordered section ID must exist and its type must map to a Liquid section file.
{
"layout": "theme",
"sections": {
"header": {"type": "header", "settings": {}},
"hero": {"type": "hero", "settings": {"heading": "Hello"}},
"footer": {"type": "footer", "settings": {}}
},
"order": ["header", "hero", "footer"]
}
layout/theme.liquid
Default layout shell
Render application header content and the ordered template sections in the layout.
<!doctype html>
<html lang="{{ localization.language.code }}">
<head>
<meta charset="utf-8">
<title>{{ page_title }}</title>
{{ content_for_header | raw }}
<link rel="stylesheet" href="{{ 'theme.css' | asset_url }}">
</head>
<body>{{ content_for_layout | raw }}</body>
</html>
Templates
Supported handles
indexcollection
productcart
checkoutorder-success
searchpage
password404
customers/*
03 Language essentials
Liquid basics
Core Liquid provides variables, conditions, loops, capture, comments, and safe output escaping.
Variables
Assign and capture
{% assign card_title = product.title %}
{% capture price_label %}
{{ product.price | money }}
{% endcapture %}
<h3>{{ card_title }}</h3>
<span>{{ price_label }}</span>
Logic
Conditionals
{% if product.available %}
<span>Ready to ship</span>
{% elsif product.inventory_policy == 'continue' %}
<span>Pre-order</span>
{% else %}
<span>Sold out</span>
{% endif %}
Iteration
Loops with empty state
{% for item in products limit: 8 %}
<a href="{{ item.url }}">{{ item.title }}</a>
{% else %}
<p>No products found.</p>
{% endfor %}
Output Safe by default
Escaping and raw
Output is escaped by default. Reserve raw for renderer-owned or Jualify-sanitized HTML.
{{ settings.heading }}
{{ product.description | raw }}
{{ page.body | raw }}
{{ content_for_layout | raw }}
04 Transform and compose
Filters & tags
These are the Jualify-specific additions to Liquid core. Use only the helpers documented in this contract.
Assets
asset_url and image_url
<link rel="stylesheet" href="{{ 'theme.css' | asset_url }}">
<script src="{{ 'theme.js' | asset_url }}" defer></script>
<img src="{{ product.image | image_url }}"
alt="{{ product.image.alt | default: product.title }}">
Responsive media
Choose an image size
Pass a product, collection, or blog feature-image object to image_url and choose the most appropriate stored size. An omitted, unsupported, or unavailable size safely uses the original image.
originalUploaded source image
large1024px wide
medium600px wide
thumbnail300px wide
small100px wide
{% assign product_image = product.image %}
<img src="{{ product_image | image_url: 'medium' }}"
alt="{{ product.image.alt | default: product.title }}">
{{ product_image | image_url: 'thumbnail' }}
{% assign product_icon = product.image | image_url: 'small' %}
{% assign collection_card = collection.image | image_url: 'thumbnail' %}
{% assign article_icon = blog.featured_image | image_url: 'small' %}
small is a 100px-wide variant for compact UI. collection.image and blog.featured_image support the same five size options; blog.image remains a compatibility URL alias.
Prices
money
Formats a numeric value with the tenant base currency symbol and configured symbol position.
{{ product.price | money }}
{% if product.compare_at_price > product.price %}
<s>{{ product.compare_at_price | money }}</s>
{% endif %}
Content
t, strip_html, truncate
{{ 'products.add_to_cart' | t }}
{{ product.description | strip_html | truncate: 120 }}
Locale lookup falls back to English when available.
URLs
route_url and tenant_url
{{ 'front.user.detail.view' | route_url }}
{{ '/collections/summer' | tenant_url }}
Prefer a supplied routes.* or object url value whenever one exists.
Composition
render, include, section
{% render 'product-card', product: product %}
{% include 'snippets/breadcrumbs.liquid' %}
{% section 'announcement' %}
References must be static and quoted. Dynamic paths and traversal are rejected.
Forms Required for POST
csrf_field
<form method="post" action="{{ cart.update_url }}">
{% csrf_field %}
…
</form>
05 Stable storefront data
Global objects
Top-level objects are normalized by Jualify. Use the documented contract rather than implementation internals.
Store
shop
shop.nameStore name
shop.urlCanonical tenant URL
shop.logo_urlMerchant logo
shop.currency_codeBase currency
shop.timezoneIANA timezone
shop.currency_symbolDisplay symbol
Customization
settings and section
{{ settings.brand_color }}
{{ section.id }}
{{ section.settings.heading }}
{% for block in section.blocks %}
{{ block.settings.title }}
{% endfor %}
Navigation & actions
routes
routes.root_urlHome
routes.search_urlProduct search
routes.cart_urlCart page
routes.checkout_urlCheckout display
routes.checkout_submit_urlCheckout POST
routes.account_urlCustomer account
Locale & menus
localization and menus.main
<html lang="{{ localization.language.code }}"
dir="{% if localization.language.rtl %}rtl{% else %}ltr{% endif %}">
{% for link in menus.main %}
<a href="{{ link.url }}" target="{{ link.target }}">
{{ link.title }}
</a>
{% endfor %}
Page context
template, request, theme
template.nameCurrent template handle
request.canonical_urlSEO-safe page URL
request.pathCurrent path
request.queryQuery values
theme.versionInstalled theme version
06 Catalog presentation
Products & discovery
Products, variants, collections, search, media, and pagination arrive as presentation-safe objects.
Product
Core product fields
product.titleLocalized title
product.slugStable SEO slug
product.urlCanonical supplied URL
product.priceActive numeric price
product.compare_at_priceOriginal sale price
product.availablePurchasable state
product.inventory_policydeny / continue
Media
Normalized image objects
{% assign image = product.featured_media %}
{% if image.url %}
<img src="{{ image.url | image_url }}"
alt="{{ image.alt | default: product.title }}"
width="{{ image.width }}"
height="{{ image.height }}">
{% endif %}
Variants Use server URL
Variant matrix
{% unless product.has_only_default_variant %}
{% for variant in product.variants %}
<button data-url="{{ variant.add_to_cart_url }}"
{% unless variant.available %}disabled{% endunless %}>
{{ variant.title }} — {{ variant.price | money }}
</button>
{% endfor %}
{% endunless %}
Collections
collection
<h1>{{ collection.title }}</h1>
{% for product in products %}
<a href="{{ product.url }}">{{ product.title }}</a>
{% endfor %}
Use collection.url; canonical collection URLs are /collections/{slug}.
Search
search
<form action="{{ routes.search_url }}" method="get">
<input name="search" value="{{ search.term }}">
</form>
{% if search.performed %}
{{ search.results_count }} results
{% endif %}
Pagination
Stable pagination object
{% if pagination.has_previous %}
<a href="{{ pagination.previous_url }}">Previous</a>
{% endif %}
<span>{{ pagination.current_page }} / {{ pagination.last_page }}</span>
{% if pagination.has_next %}
<a href="{{ pagination.next_url }}">Next</a>
{% endif %}
07 Server-owned transactions
Cart & checkout
Render supplied values and post to supplied endpoints. Never calculate or authorize transaction state in the theme.
Cart
Cart summary
{% if cart.empty %}
<p>Your cart is empty.</p>
{% else %}
{% for item in cart.items %}
<a href="{{ item.url }}">{{ item.title }}</a>
<span>{{ item.line_price | money }}</span>
{% endfor %}
<strong>{{ cart.total_price | money }}</strong>
{% endif %}
Cart mutation
Update quantities
<form method="post" action="{{ cart.update_url }}">
{% csrf_field %}
{% for item in cart.items %}
<input type="number" name="qty[]"
value="{{ item.quantity }}" min="0">
{% endfor %}
<button type="submit">Update cart</button>
</form>
Checkout Presentation only
Checkout context
checkout.submit_urlSecure POST endpoint
customer_detailSafe customer summary
billing_addressBilling values
shipping_addressShipping values
shipping_methodsSelectable methods
payment_methodsCustomer-visible methods
checkout.total_priceDisplay-only total
Checkout POST
Keep checkout field names
<form method="post" action="{{ checkout.submit_url }}"
enctype="multipart/form-data">
{% csrf_field %}
<input name="billing_fname" value="{{ billing_address.first_name }}">
<select name="shipping_charge">…</select>
<input type="radio" name="payment_method" value="cod">
<button type="submit">Place order</button>
</form>
The compatibility shipping prefix is intentionally spelled shpping_*.
Customer
customer
{% if customer.logged_in %}
<p>Hello, {{ customer.name }}</p>
<a href="{{ customer.orders_url }}">
Orders ({{ customer.orders_count }})
</a>
{% else %}
<a href="{{ routes.login_url }}">Sign in</a>
{% endif %}
Confirmation
order_success
{% if order_success.has_order %}
<h1>Order {{ order_success.order_number }}</h1>
<p>{{ order_success.payment_status }}</p>
<p>{{ order_success.total | money }}</p>
<a href="{{ order_success.order_url }}">View order</a>
{% endif %}
08 Merchant customization
Sections & schemas
Every section file ends with exactly one static JSON schema block. The schema drives validation and customizer controls.
Embedded schema Final content
One schema per section
<section>
<h2>{{ section.settings.heading }}</h2>
</section>
{% schema %}
{
"name": "Feature",
"settings": [
{"id": "heading", "type": "text", "label": "Heading", "default": "Featured"}
],
"presets": [{"name": "Feature"}]
}
{% endschema %}
Controls
Supported setting types
texttextarearichtextcheckboxnumberrangeselectradiocolorurlimagecollectionproductpagemenuheaderparagraph
Blocks
Repeatable content blocks
{% for block in section.blocks %}
<article data-block-id="{{ block.id }}">
<h3>{{ block.settings.title }}</h3>
<p>{{ block.settings.text }}</p>
</article>
{% endfor %}
Define allowed block types and their settings in the same terminal schema object.
Validator rules
Schema guardrails
Exactly one block per section
Static, valid JSON only
Must be the file’s final content
Maximum 64 KiB
No adjacent *.schema.json file
IDs and types use safe handles
09 Publish with confidence
Safety & shipping
Compatibility, maintenance access, checkout boundaries, and a short preflight checklist.
Compatibility API v1 only
Use documented API features
Use only the tags, filters, forms, blocks, and storefront objects documented by Jualify Liquid API v1. Undocumented helpers and integrations are unsupported.
Maintenance
storefront_maintenance
{% if storefront_maintenance.password_required %}
<form method="post" action="{{ storefront_maintenance.unlock_url }}">
{% csrf_field %}
<input type="password" name="storefront_password" required>
<button type="submit">Enter store</button>
</form>
{% endif %}
Sensitive data Never render
Private means server-only
Gateway credentials or secret keys
Payment tokens or full card data
Passwords or password hashes
Callback payloads or transaction internals
Arbitrary merchant tracking HTML
Preflight
Before distributing
Validate every JSON and embedded schema.
Keep theme.json at ZIP root.
Upload and confirm the theme installs as a draft.
Preview populated and empty template states.
Test variants, sold-out, sale, and missing media.
Test keyboard, mobile, reduced motion, and no-JS.
Verify forms use server URLs and CSRF.
Keep nearby
Theme code is presentation.Jualify stays the source of truth.
When in doubt, use the documented object, URL, or mutation endpoint rather than recreating application behavior in Liquid or JavaScript.
Back to quick start ↑