eekaam.docs

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. 1500 means Rs. 1,500, not Rs. 15.00. Format them with money. 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

ObjectAvailable on
shop, settings, request, routes, template, localization, linklists, cart_count, page_title, canonical_url, content_for_header, powered_by_link, editor_mode, sections, section_listEvery storefront page
content_for_layoutlayout/theme.liquid
product, related_products, reviews, max_cart_quantityproduct
collectioncollection
productsindex, collection, page, 404
collectionsindex, collections, page
postsindex, blog, page
postarticle
page_objectpage
cart_items, cart_totalcart
search_query, search_results, result_countsearch
page_content, last_updatedlegal

Sections and snippets see everything their template sees.

shop

PropertyValue
nameStore name
logoLogo URL from the store's brand settings
email, phone, descriptionFrom store settings
domainThe domain in store settings. It may be empty, so use request.host for the current host
currencyISO code of the visitor's market currency, for example AED
money_formatThe default format for that currency, for example Rs. {{amount_no_decimals_with_comma_separator}}
languageThe store's language code, for example en
marketsActive markets: id, name, currency_code, currency_name, is_primary
current_marketID of the visitor's market, or empty
navigationMenus by handle. The same data as linklists
payment_methodsThe 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

PropertyValue
pathRequest path, for example /products/linen-shirt
host, originCurrent host, and https:// + host
page_typeSee the route table in Building a theme
locale.iso_code, locale.endonym_nameStore language, for example en and English
design_modeAlways false. Use editor_mode to detect the theme editor

routes

PropertyValuePropertyValue
root_url/account_url/account
cart_url/cartaccount_login_url/account/login
cart_add_url/cart/addaccount_logout_url/account/logout
cart_change_url/cart/changeaccount_register_url/account/register
cart_update_url/cart/updateaccount_addresses_url/account/addresses
cart_clear_url/cart/clearaccount_recover_url/account/recover
collections_url/collectionssearch_url/search
all_products_collection_url/collections/allpredictive_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 cart template, use cart_items and cart_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

VariableValue
page_titlePage title, with the product's or collection's SEO title where set
page_descriptionMeta description, where one exists
page_imageShare image on product, collection and article
canonical_urlCanonical URL of the page
content_for_headerPlatform head markup. Required in the layout (The layout file)
content_for_layoutThe rendered template, in the layout only
section_listSections from the page's JSON template, in order (Sections and schema)
sectionsThe store's global sections by key, such as sections.header.menu, plus sections.announcement_bars
editor_modetrue inside the theme editor preview
powered_by_linkA "Powered by Eekaam" link
additional_checkout_buttonsAlways false
current_tagsAlways empty

product

PropertyValue
idProduct ID, a UUID string
title, slugTitle and URL handle. There is no handle or url, so build links as /products/{{ product.slug }}
descriptionHTML. Plain-text descriptions are converted to paragraphs
price, compare_at_priceMarket-resolved prices in major units
availabletrue if inventory is not tracked, or any stock remains
quantityTotal stock, summed across variants
skuProduct-level SKU
featured_image, featured_image_altImage URL and its alt text
imagesid, url, alt_text, position
has_variants, variantsSee the variant table below
optionsname, position, values for up to three options
selected_or_first_available_variantThe 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_idsCollections the product is in: id, title, slug, image
tagsArray of strings
rating, review_countAverage approved rating to one decimal place, and the review count
care_instructions, shipping_info, returns_policy, product_details, material, size_and_fitHTML content fields
meta_title, meta_descriptionSEO fields
custom_metafieldsArray of name and value
metafieldsproduct.metafields.<namespace>.<key>. Set on the product template only

Each item in variants has:

PropertyValue
idVariant ID, a UUID string
title, skuVariant title and SKU
price, compare_at_priceMarket-resolved prices in major units
available, quantity, inventory_quantityStock state and level
inventory_managementshopify when inventory is tracked, otherwise empty
inventory_policyAlways deny
option1_name, option1_valueoption3_name, option3_valueOption names and values
image_url, is_defaultVariant 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

VariableValue
cart_itemsid, title, vendor, variant_title, price, compare_at_price, quantity, line_total, image, product.slug
cart_totalSum of line_total, in major units
cart_countTotal quantity

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 objectOn Eekaam
paginateNot populated. {% paginate %} does not paginate platform lists (Tags)
cart.items, cart.total_priceUse cart_items and cart_total on the cart page, and /cart.js elsewhere
customer, customer.ordersNot populated on storefront pages
article, blog, pageUse post and page_object
product.url, product.handle, product.vendor, product.typeUse product.slug. Vendor and type are not exposed
block.shopify_attributesOnly on blocks rendered by {% section %}. Write data-block-id="{{ block.id }}" instead

Updated 15 September 2026