Free gift offers in the cart

Show the free gifts a shopper has unlocked, let them add a gift, and mark gift lines.

When a store runs a free gift discount, the cart tells your theme about every gift the shopper has unlocked in cart.gift_offers, and marks a gift in the cart with line.is_free_gift. Show both in the cart drawer and on the cart page; a shopper who unlocks a gift your theme does not show never sees it. Read them from any section that declares cart in its ctx_needs.

Two kinds of gift#

  • offer: the shopper has unlocked the gift, but it is not in the cart yet. Show it and let the shopper add it.

  • auto_add: the store adds the gift to the cart by itself. It appears as a cart line with line.is_free_gift; there is nothing to claim.

Fields#

Field

Type

Meaning

discount_id

String

The discount that grants the gift.

discount_name

String

The discount's name, to show beside the gift.

mode

String

offer or auto_add.

product_id

Integer

The gift product.

variant_id

Integer or null

The exact variant, or null when the gift is a whole product with no variants.

quantity

Integer

How many of the gift the cart may hold.

claimed_quantity

Integer

How many are already in the cart.

remaining_quantity

Integer

How many the shopper can still add.

product

Object or null

id, title, slug, url and media for display. Null when the product is no longer available on the storefront; show nothing for that gift.

variant

Object or null

id, title, options and media when the gift is a variant.

Gift offers are worked out again on every cart change, so an offer disappears from cart.gift_offers as soon as the cart stops qualifying or the gift is fully claimed. The full list of fields is in the Context Reference under Cart, wishlist, and reviews.

Show an unlocked gift#

Show an offer when its mode is offer, remaining_quantity is above zero and product is not null. Adding the gift is an ordinary cart_add form: send the product, the variant when there is one, and remaining_quantity. The store accepts it only while the cart qualifies, and your theme's usual add-to-cart handling refreshes the drawer.

cart-drawer.vasc vascula
{%- for gift in cart.gift_offers -%}
  {%- if gift.mode == 'offer' and gift.remaining_quantity > 0 and gift.product -%}
    {%- assign gift_media = gift.variant.media | default: gift.product.media -%}
    <div class="cart-gift">
      {%- if gift_media.url -%}
        <img src="{{ gift_media.url | image_url: width: 160 }}" alt="" loading="lazy">
      {%- endif -%}
      <div>
        <p>{{ 'cart.gift_unlocked' | t }}</p>
        <p>{{ gift.product.title }}{% if gift.variant %} · {{ gift.variant.title }}{% endif %}</p>
        <p class="muted">{{ gift.discount_name }}</p>
      </div>
      {% form 'cart_add' %}
        <input type="hidden" name="product_id" value="{{ gift.product_id }}">
        {%- if gift.variant_id -%}<input type="hidden" name="variant_id" value="{{ gift.variant_id }}">{%- endif -%}
        <input type="hidden" name="quantity" value="{{ gift.remaining_quantity }}">
        <button type="submit">{{ 'cart.claim_gift' | t }}</button>
      {% endform %}
    </div>
  {%- endif -%}
{%- endfor -%}

Mark gift lines#

A gift in the cart, claimed or added automatically, is a cart line with line.is_free_gift set to true. Label it as a free gift and leave out the quantity control, because the gift's quantity is set by the offer. Keep the remove control so the shopper can decline the gift.

cart-lines.html vascula
{%- for line in cart.lines -%}
  <div class="cart-line">
    <p>{{ line.title }}</p>
    {%- if line.is_free_gift -%}
      <span class="badge">{{ 'cart.free_gift' | t }}</span>
    {%- else -%}
      {%- comment -%} your quantity stepper {%- endcomment -%}
    {%- endif -%}
    {%- comment -%} your remove button, for every line {%- endcomment -%}
  </div>
{%- endfor -%}

Checklist#

  • The cart drawer and the cart page both show offers and gift lines.

  • Gift text (the heading, the add button and the badge) comes from your locale files, not from the template.

  • A gift whose product is null is skipped.

  • In the theme editor, the offer appears only when the cart really has one; do not show placeholder gifts.