> ## Documentation Index
> Fetch the complete documentation index at: https://docs.sellauth.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Theme Template Variables

> The data SellAuth passes into theme templates, globally and per page.

## Overview

Every render receives three layers of data:

1. **Globals**, available on every page.
2. **Page data**, specific to the template being rendered.
3. **Scope variables**, injected by the layout, component, and snippet mechanisms.

Page data wins if a name appears in more than one layer.

<Tip>
  While developing, `{{ someVariable | dump }}` prints the JSON representation of anything, which is the fastest way to see the real shape of a value.
</Tip>

## Scope variables

| Variable | Where | Description |
| - | - | - |
| `templateName` | Everywhere | The current template key, for example `product`. Custom pages get their settings key, for example `custom-page-1712345678901`. |
| `global` | Everywhere | The `global` object from `settings.json`. Use `global.properties.<id>` for theme settings and `global.components.<type>` for global component settings. |
| `templateContent` | Layouts | The rendered template body. Output it with the `safe` filter applied. |
| `components_order` | Templates | Array of component instance IDs, in the order the merchant arranged them. |
| `components` | Templates | Map of instance ID to component definition. Normally you loop `components_order` instead. |
| `properties` | Components, snippets | The current component's settings values. |
| `componentId` | Components | The current component's instance ID. Useful as a DOM `id`. |

## Globals

Available on every page.

| Variable | Description |
| - | - |
| `shop` | The shop. See the table below. |
| `shop_customer` | The logged-in customer, or `null`. |
| `currency` | The shop's default currency code. |
| `currency_rates_usd` | Map of currency code to USD rate, with the shop currency first. |
| `currency_symbols` | Map of currency code to display symbol. |
| `categories` | The category tree. Each node carries its `children`. |
| `latest_feedbacks` | Up to 24 recent feedbacks. |
| `latest_blog_posts` | Up to 24 recent blog posts. |
| `latest_orders` | Up to 5 recent orders, for purchase notifications. Only includes products with sales notifications enabled. |
| `images` | Map of image ID to URL. Consumed by the `imageUrl` filter rather than read directly. |
| `hostname` | The host the request came in on. |
| `isBuilder` | `true` when the page is rendering inside the visual editor preview. Use it to skip animations, tracking, and anything else that should not run in the editor. |

Most pages also get:

| Variable | Description |
| - | - |
| `breadcrumbs` | Array of `{ name, url }`. The last entry has a `null` URL. |
| `schemaOrg` | Pre-encoded JSON-LD for the page. Output inside a `<script type="application/ld+json">` with the `safe` filter applied. |

### shop

The fields themes actually use:

| Field | Description |
| - | - |
| `id`, `name`, `url`, `subdomain` | Identity |
| `description` | Shop description |
| `meta_title`, `meta_description`, `meta_image_url`, `meta_twitter_card` | SEO and social tags |
| `image_url`, `favicon_url`, `background_image_url` | Branding images |
| `products_sold`, `total_customers`, `total_completed_invoices` | Sales counters |
| `total_feedbacks`, `average_rating` | Review counters |
| `payment_methods` | Enabled payment methods |
| `max_cart_limit` | Maximum items per cart |
| `customer_balance_enabled`, `subscriptions_enabled` | Feature switches |
| `tickets_enabled` | Legacy alias of `settings.tickets.enabled`, kept for older themes |
| `legal_pages` | Published [legal pages](/guides/legal-pages), in display order. Each entry has `type`, `slug`, `path`, `url`, `title` (the merchant's title or `null`) and `default_title`. Content is not included. |
| `discord_url`, `telegram_url`, `instagram_url`, `tiktok_url`, `youtube_url` | Social links |
| `settings.affiliate.*` | Affiliate program configuration |
| `settings.reseller.*` | Reseller program configuration |
| `settings.feedback.*` | Feedback options |
| `settings.tickets.*` | `enabled` and `attachments_enabled` (customer image uploads) |

`shop` also carries the merchant's own third-party IDs (`gtag_id`, `gtm_id`, `meta_pixel_id`, `crisp_website_id`, `tawkto_id`) so themes can drop in the corresponding script tags. These belong to the merchant, not to SellAuth.

<Note>
  `shop.settings` is a filtered view intended for the storefront, not the shop's full settings. Do not assume an arbitrary setting is present.
</Note>

The official footers use `shop.legal_pages` to list every published legal page after the merchant's own links, gated on the footer's `legal_links_auto` property (on when absent):

```njk components/footer.njk theme={null}
{% set ft = global.components.footer %}
{% for link in ft.links %}
  <a href="{{ link.link }}">{{ link.text }}</a>
{% endfor %}
{% if ft.legal_links_auto != false %}
  {% for page in shop.legal_pages %}
    <a href="{{ page.path }}">{{ page.title if page.title else (('legal.' ~ page.type ~ '.title') | t) }}</a>
  {% endfor %}
{% endif %}
```

Skip pages whose `path` you already link by hand, so a merchant's manual links are not repeated.

## Page data

Everything below is in addition to the globals.

### Storefront

| Template | Variables |
| - | - |
| `shop` | No extras. Use the globals. |
| `cart` | No extras. |
| `products` | `category`, `category_links`, `filters`, `items`, `items_paginator` |
| `product` | `product`, `feedbacks`, `liveStats`, `productAddons`, `productUpsells`, `quantity_deals`, `bundle_offers` |
| `feedback` | `feedbacks`, `feedbacks_paginator`, `feedback_stats`, `orderColumn`, `orderDirection` |
| `status` | `statuses` |
| `faq` | No extras. |
| `legal-page` | `legal_page` |
| `terms`, `privacy-policy`, `refund-policy` (older theme copies only) | `terms_of_service` / `privacy_policy` / `refund_policy`, `legal_page` |
| `blog` | `blog_posts`, `blog_posts_paginator` |
| `blog-post` | `blogPost`, `related_posts`, `featured_products`, `prev_post`, `next_post` |
| `maintenance` | No extras. |
| `custom-page` | `custom_page` (`key`, `name`, `path`) |

Notes:

* `filters` on the products page holds the active filter state: `keyword`, `in_stock`, and `price` (`currency`, `from`, `to`).
* `liveStats` on the product page only contains the counters the merchant enabled, so check before rendering.
* The policy pages give you raw HTML. Output with `| safe`.
* `legal_page` on the `legal-page` template is `{ type, slug, path, url, title, default_title, meta_title, meta_description, content }`. `type` is one of `terms`, `privacy_policy`, `refund_policy`, `shipping_policy`, `cookie_policy`, `impressum`, `withdrawal`; `title` is the merchant's own title or `null`, so fall back to `default_title`; `meta_title` is the merchant's meta title, or their title, or `null`; `meta_description` is `null` unless set, so fall back to your own text; `content` is raw HTML, output with `| safe`. A theme copy without the `legal-page` template still renders the `terms`, `privacy-policy` and `refund-policy` templates, which receive the same object without `content`, since their content arrives in the older variable.
* `prev_post` and `next_post` on the blog post page are the neighbouring posts in publish order (`prev_post` is older, `next_post` is newer) and are `null` at the ends. They carry the same fields as an entry in `related_posts`.
* `featured_products` on the blog post page holds the products the merchant picked for that post, in their chosen order. Each entry has the same shape as a product in `items`, so it renders with your product card snippet. Empty when nothing was picked.

### Customer area

| Template | Variables |
| - | - |
| `customer-dashboard` | `latest_invoice`, `has_multiple_sessions`, `has_password`, `tfa_enabled` |
| `customer-invoices` | `invoices`, `reseller_filter` |
| `customer-subscriptions` | `subscriptions` |
| `customer-tickets` | `tickets`, `tickets_paginator` |
| `customer-ticket` | `ticket` (with `messages`) |
| `customer-balance` | `balance_transactions`, `balance_transactions_paginator`, `balance_product_id`, `balance_product_variant_id`, `topup_amounts`, `topup_allow_custom`, `topup_min`, `topup_max` |
| `customer-affiliate` | `referred_customers`, `referred_customers_paginator`, `affiliate_tier`, `public_tiers`, `affiliate_wallet_transactions`, `payout_requests`, `has_pending_payout`, `lifetime_earnings` |
| `customer-reseller` | `reseller_status`, `reseller_enrollment_mode`, `reseller_tier`, `reseller_next_tier`, `reseller_public_tiers`, `reseller_catalog`, `reseller_catalog_paginator`, `reseller_total_spent_usd`, `reseller_total_completed`, `latest_reseller_invoice`, plus flags describing the reseller's API setup |

<Warning>
  The reseller page includes credential-shaped values so the built-in themes can show a reseller their own integration details. Render them only inside the reseller's own dashboard view, never in shared markup, and never log them.
</Warning>

## Paginators

Any variable ending in `_paginator` is a paginator object with these fields:

| Field | Description |
| - | - |
| `total` | Total number of records |
| `from`, `to` | Range shown on the current page |
| `prev_page_url`, `next_page_url` | `null` at the ends |
| `links` | Array of `{ url, label, active }` for numbered page links |

The official themes render all of this with a shared snippet:

```njk theme={null}
{% render_snippet "pagination.njk", paginator=items_paginator %}
```

## Legacy variables

These still work but should not be used in new themes:

| Legacy | Use instead |
| - | - |
| `feedbacks` on the `shop` template | `latest_feedbacks` |
| `blogPosts` on the `shop` template | `latest_blog_posts` |
| `has_password`, `tfa_enabled`, `has_multiple_sessions` on `customer-dashboard` | The same fields on `shop_customer` |
| `sortedItems` | Page-specific data such as `items`, or `helpers.components.products.getItemsByIds` for handpicked selections |

<Note>
  `sortedItems` contains every public product and group, and it is loaded on every page. It exists because older themes depend on it. Reach for the page's own data first.
</Note>


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.