Product
The product object and all of its properties.
The product object holds everything about a single product. It is available on product pages and inside loops when you work with collections.
Core properties
| Property | Type | Description |
|---|---|---|
product.id | number | The unique product ID |
product.title | string | The product title |
product.handle | string | The URL slug (e.g. classic-gold-ring) |
product.description | string | The full HTML description |
product.content | string | Alias for description |
product.type | string | The product type (e.g. physical, digital, service) |
product.brand | string | The brand name |
product.vendor | string | Alias for brand |
product.url | string | The URL path to the product page |
product.available | boolean | true if at least one variant is in stock |
product.published_at | string | The date the product was published |
product.created_at | string | The date the product was created |
product.has_only_default_variant | boolean | true if the product has just one variant |
Pricing
Prices are in the smallest currency unit (pence, cents). Use the money filter to format them.
| Property | Type | Description |
|---|---|---|
product.price | number | The lowest variant price |
product.price_min | number | The lowest variant price (same as price) |
product.price_max | number | The highest variant price |
product.price_varies | boolean | true if price_min differs from price_max |
product.compare_at_price | number | The highest compare-at price across all variants |
product.compare_at_price_min | number | The lowest compare-at price across variants |
product.compare_at_price_max | number | The highest compare-at price across variants |
product.compare_at_price_varies | boolean | true if compare-at prices differ across variants |
<p class="price">{{ product.price | money }}</p>
{% if product.compare_at_price > product.price %}
<p class="compare-price">Was {{ product.compare_at_price | money }}</p>
{% endif %}Price ranges
When a product has variants at different prices, show a range:
{% if product.price_varies %}
<p>{{ product.price_min | money }} - {{ product.price_max | money }}</p>
{% else %}
<p>{{ product.price | money }}</p>
{% endif %}Images
| Property | Type | Description |
|---|---|---|
product.featured_image | image | The first image |
product.images | array | All product images |
Each image object has src, alt, width, height, and position properties. See the Image object for details.
{% if product.featured_image %}
{{ product.featured_image | image_tag }}
{% endif %}
{% for image in product.images %}
<img src="{{ image | img_url: '400x400' }}" alt="{{ image.alt }}" />
{% endfor %}Variants
| Property | Type | Description |
|---|---|---|
product.variants | array | All variants for this product |
product.options | array | Option names (e.g. ["Size", "Color"]) |
product.options_with_values | array | Options with their available values |
product.selected_variant | variant | The variant the visitor has picked, if any |
product.first_available_variant | variant | The first variant that is in stock |
product.selected_or_first_available_variant | variant | The selected variant, or falls back to the first available |
See the Variant object for all variant properties.
Options with values
Each entry in options_with_values has a name and values array:
{% for option in product.options_with_values %}
<label>{{ option.name }}</label>
<select>
{% for value in option.values %}
<option>{{ value }}</option>
{% endfor %}
</select>
{% endfor %}Variant picker
<select name="variant_id">
{% for variant in product.variants %}
<option value="{{ variant.id }}" {% unless variant.available %}disabled{% endunless %}>
{{ variant.title }} - {{ variant.price | money }}
</option>
{% endfor %}
</select>Tags and collections
| Property | Type | Description |
|---|---|---|
product.tags | array | Tags assigned to this product |
product.collections | array | Collections this product belongs to |
Each collection in the array is a lightweight reference with id, title, handle, and url.
{% if product.tags contains 'sale' %}
<span class="badge">On Sale</span>
{% endif %}
{% for collection in product.collections %}
<a href="{{ collection.url }}">{{ collection.title }}</a>
{% endfor %}Shipping and fulfillment
| Property | Type | Description |
|---|---|---|
product.requires_shipping | boolean | true if any variant requires shipping |
product.ships_to_countries | array | Country codes this product ships to, or nil if it ships everywhere |
product.qty_step | number | Quantity step increment (e.g. 1, 5, 10) |
{% if product.ships_to_countries %}
<p>Ships to {{ product.ships_to_countries | join: ', ' }}</p>
{% else %}
<p>Ships worldwide</p>
{% endif %}Product details
| Property | Type | Description |
|---|---|---|
product.product_details | object | Structured specs and attributes set in the admin |
Product details hold data like size, weight, or care info:
{% if product.product_details.material %}
<p>Material: {{ product.product_details.material }}</p>
{% endif %}Metafields
| Property | Type | Description |
|---|---|---|
product.metafields | object | Custom data fields set in the admin |
Access metafields by namespace and key:
{% if product.metafields.custom.care_instructions %}
<p>{{ product.metafields.custom.care_instructions }}</p>
{% endif %}Full example
A product card that shows the image, title, price, and a sale badge:
<div class="product-card">
{% if product.featured_image %}
<a href="{{ product.url }}">
{{ product.featured_image | image_tag: class: 'product-card__image' }}
</a>
{% endif %}
<h3><a href="{{ product.url }}">{{ product.title }}</a></h3>
<p>{{ product.brand }}</p>
{% if product.compare_at_price > product.price %}
<span class="price price--sale">{{ product.price | money }}</span>
<span class="price price--compare">{{ product.compare_at_price | money }}</span>
{% else %}
<span class="price">{{ product.price | money }}</span>
{% endif %}
{% unless product.available %}
<span class="badge badge--soldout">Sold Out</span>
{% endunless %}
{% if product.tags contains 'new' %}
<span class="badge">New</span>
{% endif %}
</div>