Themes
Liquid objects
Liquid objects
These are the variables a template, section or snippet can read. Many share Shopify's names, but their contents are Eekaam's. A property that doesn't exist renders as an empty string rather than raising an error, so a Shopify property missing from the tables below fails silently.
Two rules hold throughout:
- Prices are in major units.
1500means Rs. 1,500, not Rs. 15.00. Format them withmoney. The AJAX Cart API is different and uses minor units. - Prices are already resolved for the visitor's market, including exchange rate, adjustment and rounding (Markets and localization).
Scope at a glance
| Object | Available on |
|---|---|
shop, settings, request, routes, template, localization, linklists, cart_count, page_title, canonical_url, content_for_header, powered_by_link, editor_mode, sections, section_list | Every storefront page |
content_for_layout | layout/theme.liquid |
product, related_products, reviews, max_cart_quantity | product |
collection | collection |
products | index, collection, page, 404 |
collections | index, collections, page |
posts | index, blog, page |
post | article |
page_object | page |
cart_items, cart_total | cart |
search_query, search_results, result_count | search |
page_content, last_updated | legal |
Sections and snippets see everything their template sees.
shop
| Property | Value |
|---|---|
name | Store name |
logo | Logo URL from the store's brand settings |
email, phone, description | From store settings |
domain | The domain in store settings. It may be empty, so use request.host for the current host |
currency | ISO code of the visitor's market currency, for example AED |
money_format | The default format for that currency, for example Rs. {{amount_no_decimals_with_comma_separator}} |
language | The store's language code, for example en |
markets | Active markets: id, name, currency_code, currency_name, is_primary |
current_market | ID of the visitor's market, or empty |
navigation | Menus by handle. The same data as linklists |
payment_methods | The store's (or market's) enabled payment methods |
shop.url, shop.secure_url, shop.locale and shop.enabled_currencies are not set. Use request.origin, request.locale.iso_code and localization.available_markets instead.
<a href="{{ routes.root_url }}" class="logo">
{% if shop.logo != blank %}
<img src="{{ shop.logo }}" alt="{{ shop.name }}">
{% else %}
{{ shop.name }}
{% endif %}
</a>settings
The global theme settings: the merchant's saved values, with config/settings_data.json filling in anything unsaved. Read them as settings.<id>, or settings.<group>.<id> when your settings_data.json nests them. settings.favicon falls back to the store's favicon.
request
| Property | Value |
|---|---|
path | Request path, for example /products/linen-shirt |
host, origin | Current host, and https:// + host |
page_type | See the route table in Building a theme |
locale.iso_code, locale.endonym_name | Store language, for example en and English |
design_mode | Always false. Use editor_mode to detect the theme editor |
routes
| Property | Value | Property | Value |
|---|---|---|---|
root_url | / | account_url | /account |
cart_url | /cart | account_login_url | /account/login |
cart_add_url | /cart/add | account_logout_url | /account/logout |
cart_change_url | /cart/change | account_register_url | /account/register |
cart_update_url | /cart/update | account_addresses_url | /account/addresses |
cart_clear_url | /cart/clear | account_recover_url | /account/recover |
collections_url | /collections | search_url | /search |
all_products_collection_url | /collections/all | predictive_search_url | /search/suggest |
product_recommendations_url | /recommendations/products |
These are fixed strings. They are not locale- or market-aware, and some have no page behind them: /cart/change, /cart/update, /cart/clear, /account/addresses and /account/recover do not exist. Use the .js endpoints from the AJAX Cart API for cart changes.
template
{{ template }} prints the template name. template.name is the same value, and template.directory is templates. template.suffix is currently always empty, even when a suffixed JSON template supplied the sections.
{% if template.name == 'product' %}
{{ 'product.js' | asset_url | script_tag }}
{% endif %}localization
The visitor's market, country and the store's markets. The full table is in Markets and localization.
linklists
Menus by handle. Each menu has a title and links. Each link has title, url and type, plus links for its children (children is an alias). If the store has no main-menu, a default one is supplied with Home, Catalog, Blog, About and Contact.
<nav>
{% for link in linklists['main-menu'].links %}
<a href="{{ link.url }}">{{ link.title }}</a>
{% if link.links.size > 0 %}
<ul>
{% for child in link.links %}<li><a href="{{ child.url }}">{{ child.title }}</a></li>{% endfor %}
</ul>
{% endif %}
{% endfor %}
</nav>cart and cart_count
cart_count is the number of items in the visitor's cart, and it is correct on every page. Use it for the header badge.
The cart object is a placeholder. On every page it reports item_count: 0, total_price: 0 and an empty items, whatever the visitor has added. Do not render cart contents from it:
- On the
carttemplate, usecart_itemsandcart_total. - Everywhere else, including cart drawers, fetch
/cart.js.
<a href="{{ routes.cart_url }}" class="cart-link">
Cart <span data-cart-count>{{ cart_count }}</span>
</a>customer
customer is nil on storefront pages, including the account templates. Account pages load customer data client-side after login. Use {% if customer %} only as a guard, not to show a name or orders.
Page and layout variables
| Variable | Value |
|---|---|
page_title | Page title, with the product's or collection's SEO title where set |
page_description | Meta description, where one exists |
page_image | Share image on product, collection and article |
canonical_url | Canonical URL of the page |
content_for_header | Platform head markup. Required in the layout (The layout file) |
content_for_layout | The rendered template, in the layout only |
section_list | Sections from the page's JSON template, in order (Sections and schema) |
sections | The store's global sections by key, such as sections.header.menu, plus sections.announcement_bars |
editor_mode | true inside the theme editor preview |
powered_by_link | A "Powered by Eekaam" link |
additional_checkout_buttons | Always false |
current_tags | Always empty |
product
| Property | Value |
|---|---|
id | Product ID, a UUID string |
title, slug | Title and URL handle. There is no handle or url, so build links as /products/{{ product.slug }} |
description | HTML. Plain-text descriptions are converted to paragraphs |
price, compare_at_price | Market-resolved prices in major units |
available | true if inventory is not tracked, or any stock remains |
quantity | Total stock, summed across variants |
sku | Product-level SKU |
featured_image, featured_image_alt | Image URL and its alt text |
images | id, url, alt_text, position |
has_variants, variants | See the variant table below |
options | name, position, values for up to three options |
selected_or_first_available_variant | The first in-stock variant, or the first variant. For a product without variants, a stand-in with the product's id, price, available and quantity |
collections, collection_ids | Collections the product is in: id, title, slug, image |
tags | Array of strings |
rating, review_count | Average approved rating to one decimal place, and the review count |
care_instructions, shipping_info, returns_policy, product_details, material, size_and_fit | HTML content fields |
meta_title, meta_description | SEO fields |
custom_metafields | Array of name and value |
metafields | product.metafields.<namespace>.<key>. Set on the product template only |
Each item in variants has:
| Property | Value |
|---|---|
id | Variant ID, a UUID string |
title, sku | Variant title and SKU |
price, compare_at_price | Market-resolved prices in major units |
available, quantity, inventory_quantity | Stock state and level |
inventory_management | shopify when inventory is tracked, otherwise empty |
inventory_policy | Always deny |
option1_name, option1_value … option3_name, option3_value | Option names and values |
image_url, is_default | Variant image URL, and whether it is the default variant |
Products in lists (products, related_products, search_results) have the same shape, without metafields.
reviews on the product template lists approved reviews: id, author, rating, title, body, photos, verified and created_at (preformatted, for example Jan 2, 2006). max_cart_quantity is the store's per-product cart limit, or 0 for no limit.
<h1>{{ product.title }}</h1>
<p class="price">
{{ product.selected_or_first_available_variant.price | money }}
{% if product.compare_at_price > product.price %}
<s>{{ product.compare_at_price | money }}</s>
{% endif %}
</p>
<select name="variant_id">
{% for variant in product.variants %}
<option value="{{ variant.id }}" {% unless variant.available %}disabled{% endunless %}>
{{ variant.title }}
</option>
{% endfor %}
</select>collection and products
collection has title, description, image, slug and metafields. On /collections/all and /products it is { title: "All Products", slug: "all" } with no metafields.
The collection's products are not on the collection. They are the top-level products, already filtered to the visitor's market.
On index and page, products holds the products the page's featured-products and product-grid sections ask for. On 404 it holds four suggestions.
<h1>{{ collection.title }}</h1>
{% for product in products %}
{% render 'product-card', product: product %}
{% else %}
<p>No products in this collection yet.</p>
{% endfor %}collections
On the collections template, each item has title, slug, description, image and url. On index and page each item has id, title, slug and image.
Cart page
| Variable | Value |
|---|---|
cart_items | id, title, vendor, variant_title, price, compare_at_price, quantity, line_total, image, product.slug |
cart_total | Sum of line_total, in major units |
cart_count | Total quantity |
Search
search_query is the q parameter, HTML-escaped. search_results holds up to 20 matching products, and result_count is their number. Only products are searched on this page. Predictive search also returns collections and pages.
Blog and articles
posts items have title, slug, excerpt, featured_image, author, tags, published_at and created_at. On the article template the post is post, with content, meta_title, meta_description and metafields as well. There is no article or blog object.
<article>
<h1>{{ post.title }}</h1>
<p>{{ post.author }} · {{ post.created_at | date: '%d %B %Y' }}</p>
{{ post.content }}
</article>Pages
On the page template the page is page_object, not page. It has title, slug, content, template, meta_title, meta_description and metafields. The legal template gets page_title, page_content (HTML) and last_updated instead.
Not available
| Shopify object | On Eekaam |
|---|---|
paginate | Not populated. {% paginate %} does not paginate platform lists (Tags) |
cart.items, cart.total_price | Use cart_items and cart_total on the cart page, and /cart.js elsewhere |
customer, customer.orders | Not populated on storefront pages |
article, blog, page | Use post and page_object |
product.url, product.handle, product.vendor, product.type | Use product.slug. Vendor and type are not exposed |
block.shopify_attributes | Only on blocks rendered by {% section %}. Write data-block-id="{{ block.id }}" instead |
Updated 15 September 2026