product collection

Product Variant Collection - Show Variants As Separate Products

Log in or Sign up to ensure access to purchased code across multiple devices.

How to see the code

1. Please log in/create an account first. This is to ensure that all purchases are connected to an account and can be viewed on different devices.

2. Purchase the code using the "purchase box" on the specific page of the desired code.

3. After the purchase, please refresh the page.

Compatibility: All  Shopify 2.0 FREE themes  ONLYWorks from lower version to version 11

Due to the recent update in Dawn theme, Dawn version 7.0 will have far different code. See comment below.

You have only a few products but each product has multiple variants? Showcase your product in a collection but its variant. Show variants on collection pages as separate products.

We will displaying variants as products in collection pages with a secondary image on hover. The variant only allows one image currently right? We can add more image using metafield. 

This will show all variants in the product. If you want to use color only, please see this code instead.

Note: If your product does not have a variant image, it will display as one product. So make sure you assign an image to your variants. 

I used the following variant metafield below. NOTE: Make sure to edit the Namespace and key to match it below. 

Variant metafield

We have to add metafield to our variant. Then set up our metafield in our product variant. Please see the video for more information. 

What you are buying:

  • A collection of instead products, it will show ALL product variants
  • The filter works in filtering the product and NOT by variants
  • You will need to provide featured images to the variants
  • Use metafield variant image to provide hover image

What makes our code better:

  • We do not use external libraries, with that being said, our code will have no to minimal effect to your website's speed performance
  • We do not leave or add codes use to advertise for our website
  • Our code is mobile friendly

Any issues related to the code will be fix with no additional cost, excluding code customization requests. Simply contact us with "Chat with us." We are just a button away. 

 

To start:

1. Go to Admin store > Online Store > Themes > Actions > Edit code.

2. Go to Section folder, and click "add a new section", name it "variant-collection."

{{ 'template-collection.css' | asset_url | stylesheet_tag }}
{{ 'component-loading-overlay.css' | asset_url | stylesheet_tag }}
{{ 'component-card.css' | asset_url | stylesheet_tag }}
{{ 'component-price.css' | asset_url | stylesheet_tag }}
 
<link
  rel="preload"
  href="{{ 'component-rte.css' | asset_url }}"
  as="style"
  onload="this.onload=null;this.rel='stylesheet'"
>
{%- if section.settings.enable_quick_add -%}
  <link rel="stylesheet" href="{{ 'quick-add.css' | asset_url }}" media="print" onload="this.media='all'">
  <script src="{{ 'quick-add.js' | asset_url }}" defer="defer"></script>
  <script src="{{ 'product-form.js' | asset_url }}" defer="defer"></script>
{%- endif -%}
<noscript>{{ 'component-rte.css' | asset_url | stylesheet_tag }}</noscript>
{%- style -%}
  .section-{{ section.id }}-padding {
  padding-top: {{ section.settings.padding_top | times: 0.75 | round: 0 }}px;
  padding-bottom: {{ section.settings.padding_bottom | times: 0.75 | round: 0 }}px;
  }
 
  .variant-wrapper.card-wrapper {
  height: fit-content;
  }
 
  .card__inner.ratio .card__media {
  width: 100%
  }
 
  @media screen and (min-width: 750px) {
  .section-{{ section.id }}-padding {
  padding-top: {{ section.settings.padding_top }}px;
  padding-bottom: {{ section.settings.padding_bottom }}px;
  }
  }
{%- endstyle -%}
<div class="section-{{ section.id }}-padding">
  {% comment %} Sort is the first tabbable element when filter type is vertical {% endcomment %}
  {%- if section.settings.enable_sorting and section.settings.filter_type == 'vertical' -%}
    <facet-filters-form class="facets facets-vertical-sort page-width small-hide no-js-hidden">
      <form class="facets-vertical-form" id="FacetSortForm">
        <div class="facet-filters sorting caption">
          <div class="facet-filters__field">
            <h2 class="facet-filters__label caption-large text-body">
              <label for="SortBy">{{ 'products.facets.sort_by_label' | t }}</label>
            </h2>
            <div class="select">
              {%- assign sort_by = collection.sort_by | default: collection.default_sort_by -%}
              <select
                name="sort_by"
                class="facet-filters__sort select__select caption-large"
                id="SortBy"
                aria-describedby="a11y-refresh-page-message"
              >
                {%- for option in collection.sort_options -%}
                  <option
                    value="{{ option.value | escape }}"
                    {% if option.value == sort_by %}
                      selected="selected"
                    {% endif %}
                  >
                    {{ option.name | escape }}
                  </option>
                {%- endfor -%}
              </select>
              {% render 'icon-caret' %}
            </div>
          </div>
          <noscript>
            <button type="submit" class="facets__button-no-js button button--secondary">
              {{ 'products.facets.sort_button' | t }}
            </button>
          </noscript>
        </div>
        <div class="product-count-vertical light" role="status">
          <h2 class="product-count__text text-body">
            <span id="ProductCountDesktop">
              {%- if collection.results_count -%}
                {{
                  'templates.search.results_with_count'
                  | t: terms: collection.terms, count: collection.results_count
                }}
              {%- elsif collection.products_count == collection.all_products_count -%}
                {{ 'products.facets.product_count_simple' | t: count: collection.products_count }}
              {%- else -%}
                {{
                  'products.facets.product_count'
                  | t: product_count: collection.products_count, count: collection.all_products_count
                }}
              {%- endif -%}
            </span>
          </h2>
          <div class="loading-overlay__spinner">
            <svg
              aria-hidden="true"
              focusable="false"
              role="presentation"
              class="spinner"
              viewBox="0 0 66 66"
              xmlns="http://www.w3.org/2000/svg"
            >
              <circle class="path" fill="none" stroke-width="6" cx="33" cy="33" r="30"></circle>
            </svg>
          </div>
        </div>
      </form>
    </facet-filters-form>
  {%- endif -%}
  <div class="{% if section.settings.filter_type == 'vertical' %} facets-vertical page-width{% endif %}">
    {{ 'component-facets.css' | asset_url | stylesheet_tag }}
    <script src="{{ 'facets.js' | asset_url }}" defer="defer"></script>
    {%- if section.settings.enable_filtering or section.settings.enable_sorting -%}
      <aside
        aria-labelledby="verticalTitle"
        class="facets-wrapper{% unless section.settings.enable_filtering %} facets-wrapper--no-filters{% endunless %}{% if section.settings.filter_type != 'vertical' %} page-width{% endif %}"
        id="main-collection-filters"
        data-id="{{ section.id }}"
      >
        {% render 'facets',
          results: collection,
          enable_filtering: section.settings.enable_filtering,
          enable_sorting: section.settings.enable_sorting,
          filter_type: section.settings.filter_type
        %}
      </aside>
    {%- endif -%}
    <div
      class="product-grid-container{% if section.settings.filter_type == 'vertical' and section.settings.collapse_on_larger_devices %} product-grid-container-vertical{% endif %}"
      id="ProductGridContainer"
    >
      {%- paginate collection.products by section.settings.products_per_page -%}
        {%- if collection.products.size == 0 -%}
          <div class="collection collection--empty page-width" id="product-grid" data-id="{{ section.id }}">
            <div class="loading-overlay gradient"></div>
            <div class="title-wrapper center">
              <h2 class="title title--primary">
                {{ 'sections.collection_template.empty' | t -}}
                <br>
                {{
                  'sections.collection_template.use_fewer_filters_html'
                  | t: link: collection.url, class: 'underlined-link link'
                }}
              </h2>
            </div>
          </div>
        {%- else -%}
          <div class="collection{% if section.settings.filter_type != 'vertical' %} page-width{% endif %}">
            <div class="loading-overlay gradient"></div>
            <ul
              id="product-grid"
              data-id="{{ section.id }}"
              class="
                grid product-grid grid--{{ section.settings.columns_mobile }}-col-tablet-down
                grid--{{ section.settings.columns_desktop }}-col-desktop
              "
            >
              {%- for product in collection.products -%}
                {% assign variantImage = true %}
                {%- for variant in product.variants -%}
                  {% if variant.featured_image != blank %}
                    {% assign variantImage = true %}
                  {% else %}
                    {% assign variantImage = false %}
                  {% endif %}
                {%- endfor -%}
                {% if variantImage %}
                  {%- for variant in product.variants -%}
                    {% assign lazy_load = false %}
                    {%- if forloop.index > 2 -%}
                      {%- assign lazy_load = true -%}
                    {%- endif -%}
                    <li class="grid__item">
                      {% render 'variant-card',
                        card_product: product,
                        card_variant: variant,
                        hide_variant_info: section.settings.hide_variant_info,
                        show_secondary_image: section.settings.show_secondary_image,
                        media_aspect_ratio: section.settings.image_ratio,
                        show_vendor: section.settings.show_vendor,
                        show_rating: section.settings.show_rating,
                        lazy_load: lazy_load,
                        show_quick_add: section.settings.enable_quick_add,
                        section_id: section.id
                      %}
                    </li>
                  {%- endfor -%}
                {% else %}
                  {% assign lazy_load = false %}
                  {%- if forloop.index > 2 -%}
                    {%- assign lazy_load = true -%}
                  {%- endif -%}
                  <li class="grid__item">
                    {% render 'card-product',
                      card_product: product,
                      media_aspect_ratio: section.settings.image_ratio,
                      show_secondary_image: section.settings.show_secondary_image,
                      show_vendor: section.settings.show_vendor,
                      show_rating: section.settings.show_rating,
                      lazy_load: lazy_load,
                      show_quick_add: section.settings.enable_quick_add,
                      section_id: section.id
                    %}
                  </li>
                {% endif %}
              {%- endfor -%}
            </ul>
            {%- if paginate.pages > 1 -%}
              {% render 'pagination', paginate: paginate, anchor: '' %}
            {%- endif -%}
          </div>
        {%- endif -%}
      {%- endpaginate -%}
    </div>
  </div>
</div>
{% schema %}
{
"name": "t:sections.main-collection-product-grid.name",
"class": "section",
"settings": [
{
"type": "range",
"id": "products_per_page",
"min": 8,
"max": 24,
"step": 4,
"default": 16,
"label": "t:sections.main-collection-product-grid.settings.products_per_page.label"
},
{
"type": "range",
"id": "columns_desktop",
"min": 1,
"max": 5,
"step": 1,
"default": 4,
"label": "t:sections.main-collection-product-grid.settings.columns_desktop.label"
},
{
"type": "header",
"content": "t:sections.main-collection-product-grid.settings.header__3.content"
},
{
"type": "select",
"id": "image_ratio",
"options": [
{
"value": "adapt",
"label": "t:sections.main-collection-product-grid.settings.image_ratio.options__1.label"
},
{
"value": "portrait",
"label": "t:sections.main-collection-product-grid.settings.image_ratio.options__2.label"
},
{
"value": "square",
"label": "t:sections.main-collection-product-grid.settings.image_ratio.options__3.label"
}
],
"default": "adapt",
"label": "t:sections.main-collection-product-grid.settings.image_ratio.label"
},
{
"type": "checkbox",
"id": "show_secondary_image",
"default": false,
"label": "t:sections.main-collection-product-grid.settings.show_secondary_image.label"
},
{
"type": "checkbox",
"id": "show_vendor",
"default": false,
"label": "t:sections.main-collection-product-grid.settings.show_vendor.label"
},
{
"type": "checkbox",
"id": "hide_variant_info",
"label": "Hide variant title"
},
{
"type": "checkbox",
"id": "show_rating",
"default": false,
"label": "t:sections.main-collection-product-grid.settings.show_rating.label",
"info": "t:sections.main-collection-product-grid.settings.show_rating.info"
},
{
"type": "checkbox",
"id": "enable_quick_add",
"default": false,
"label": "t:sections.main-collection-product-grid.settings.enable_quick_buy.label"
},
{
"type": "header",
"content": "t:sections.main-collection-product-grid.settings.header__1.content"
},
{
"type": "checkbox",
"id": "enable_filtering",
"default": true,
"label": "t:sections.main-collection-product-grid.settings.enable_filtering.label",
"info": "t:sections.main-collection-product-grid.settings.enable_filtering.info"
},
{
"type": "select",
"id": "filter_type",
"options": [
{
"value": "horizontal",
"label": "t:sections.main-collection-product-grid.settings.filter_type.options__1.label"
},
{
"value": "vertical",
"label": "t:sections.main-collection-product-grid.settings.filter_type.options__2.label"
},
{
"value": "drawer",
"label": "t:sections.main-collection-product-grid.settings.filter_type.options__3.label"
}
],
"default": "horizontal",
"label": "t:sections.main-collection-product-grid.settings.filter_type.label",
"info": "t:sections.main-collection-product-grid.settings.filter_type.info"
},
{
"type": "checkbox",
"id": "enable_sorting",
"default": true,
"label": "t:sections.main-collection-product-grid.settings.enable_sorting.label"
},
{
"type": "header",
"content": "t:sections.main-collection-product-grid.settings.header_mobile.content"
},
{
"type": "select",
"id": "columns_mobile",
"default": "2",
"label": "t:sections.main-collection-product-grid.settings.columns_mobile.label",
"options": [
{
"value": "1",
"label": "t:sections.main-collection-product-grid.settings.columns_mobile.options__1.label"
},
{
"value": "2",
"label": "t:sections.main-collection-product-grid.settings.columns_mobile.options__2.label"
}
]
},
{
"type": "header",
"content": "t:sections.all.padding.section_padding_heading"
},
{
"type": "range",
"id": "padding_top",
"min": 0,
"max": 100,
"step": 4,
"unit": "px",
"label": "t:sections.all.padding.padding_top",
"default": 36
},
{
"type": "range",
"id": "padding_bottom",
"min": 0,
"max": 100,
"step": 4,
"unit": "px",
"label": "t:sections.all.padding.padding_bottom",
"default": 36
}
]
}
{% endschema %}
 

 

3. If you want  to assign this collection template as a default, then follow the video. 
If not, we need to create a new collection template. (Follow the video on how). Open and copy the code in the "collection.json" under the Template folder. Then paste the code to the newly created template. 

Inside the newly created template, find this code "main-collection-product-grid" and replace with the name "variant-collection".

 4. Next, we need to create a variant card. Open the Snippet folder, and click "Add a new snippet." Name it "variant-card." If you have Dawn version 6.0 below use the code below, if not, please use the next code. 

For Dawn 6.0 below

{% comment %}
  Renders a product card
 
  Accepts:
  - card_product: {Object} Product Liquid object (optional)
  - media_aspect_ratio: {String} Size of the product image card. Values are "square" and "portrait". Default is "square" (optional)
  - show_secondary_image: {Boolean} Show the secondary image on hover. Default: false (optional)
  - show_vendor: {Boolean} Show the product vendor. Default: false
  - show_rating: {Boolean} Show the product rating. Default: false
  - extend_height: {Boolean} Card height extends to available container space. Default: true (optional)
  - lazy_load: {Boolean} Image should be lazy loaded. Default: true (optional)
  - show_quick_add: {Boolean} Show the quick add button.
  - section_id: {String} The ID of the section that contains this card.
 
  Usage:
  {% render 'variant-card', show_vendor: section.settings.show_vendor %}
{% endcomment %}
 
{{ 'component-rating.css' | asset_url | stylesheet_tag }}
 
{%- if card_variant and card_variant != empty -%}
  {%- liquid
    assign ratio = 1
    if card_variant.featured_media and media_aspect_ratio == 'portrait'
      assign ratio = 0.8
    elsif card_variant.featured_media and media_aspect_ratio == 'adapt'
      assign ratio = card_variant.featured_media.aspect_ratio
    endif
    if ratio == 0 or ratio == null
      assign ratio = 1
    endif
  -%}
  <div class="variant-wrapper card-wrapper underline-links-hover">
    <div
      class="
        card
        card--{{ settings.card_style }}
        {% if card_variant.featured_media %} card--media{% else %} card--text{% endif %}
        {% if settings.card_style == 'card' %} color-{{ settings.card_color_scheme }} gradient{% endif %}
        {% if extend_height %} card--extend-height{% endif %}
        {% if card_variant.featured_media == nil and settings.card_style == 'card' %} ratio{% endif %}
      "
      style="--ratio-percent: {{ 1 | divided_by: ratio | times: 100 }}%;"
    >
      <div
        class="card__inner {% if settings.card_style == 'standard' %}color-{{ settings.card_color_scheme }} gradient{% endif %}{% if card_product.featured_media or settings.card_style == 'standard' %} ratio{% endif %}"
        style="--ratio-percent: {{ 1 | divided_by: ratio | times: 100 }}%;"
      >
        {%- if card_variant.featured_media -%}
          <div class="card__media">
            <div class="media media--transparent media--hover-effect">
              {% comment %}theme-check-disable ImgLazyLoading{% endcomment %}
              <img
                srcset="
                  {%- if card_variant.featured_media.width >= 165 -%}{{ card_variant.featured_media | image_url: width: 165 }} 165w,{%- endif -%}
                  {%- if card_variant.featured_media.width >= 360 -%}{{ card_variant.featured_media | image_url: width: 360 }} 360w,{%- endif -%}
                  {%- if card_variant.featured_media.width >= 533 -%}{{ card_variant.featured_media | image_url: width: 533 }} 533w,{%- endif -%}
                  {%- if card_variant.featured_media.width >= 720 -%}{{ card_variant.featured_media | image_url: width: 720 }} 720w,{%- endif -%}
                  {%- if card_variant.featured_media.width >= 940 -%}{{ card_variant.featured_media | image_url: width: 940 }} 940w,{%- endif -%}
                  {%- if card_variant.featured_media.width >= 1066 -%}{{ card_variant.featured_media | image_url: width: 1066 }} 1066w,{%- endif -%}
                  {{ card_variant.featured_media | image_url }} {{ card_variant.featured_media.width }}w
                "
                src="{{ card_variant.featured_media | image_url: width: 533 }}"
                sizes="(min-width: {{ settings.page_width }}px) {{ settings.page_width | minus: 130 | divided_by: 4 }}px, (min-width: 990px) calc((100vw - 130px) / 4), (min-width: 750px) calc((100vw - 120px) / 3), calc((100vw - 35px) / 2)"
                alt="{{ card_variant.featured_media.alt | escape }}"
                class="motion-reduce"
                {% unless lazy_load == false %}
                  loading="lazy"
                {% endunless %}
                width="{{ card_variant.featured_media.width }}"
                height="{{ card_variant.featured_media.height }}"
              >
              {% comment %}theme-check-enable ImgLazyLoading{% endcomment %}
 
              {% assign meta_image = card_variant.metafields.my_fields['secondary-image'] %}
              {% if meta_image != null and show_secondary_image %}
 
                <img
                  src="{{ meta_image | image_url: width: 533 }}"
                  sizes="(min-width: {{ settings.page_width }}px) {{ settings.page_width | minus: 130 | divided_by: 4 }}px, (min-width: 990px) calc((100vw - 130px) / 4), (min-width: 750px) calc((100vw - 120px) / 3), calc((100vw - 35px) / 2)"
                  alt="{{ meta_image.alt | escape }}"
                  class="motion-reduce"
                  loading="lazy"
                  width="{{ meta_image.width }}"
                  height="{{ meta_image.height }}"
                >
              {% endif %}
            </div>
          </div>
        {%- endif -%}
      </div>
      <div class="card__content">
        <div class="card__information">
          <h3
            class="card__heading{% if card_variant.featured_media or settings.card_style == 'standard' %} h5{% endif %}"
            {% if card_variant.featured_media or settings.card_style == 'card' %}
              id="title-{{ section_id }}-{{ card_product.id }}"
            {% endif %}
          >
            <a href="{{ card_variant.url }}" class="full-unstyled-link">
              {{ card_product.title | escape }}
              <br>
              {{ card_variant.title | escape }}
            </a>
          </h3>
          <div class="card-information">
            {%- if show_vendor -%}
              <span class="visually-hidden">{{ 'accessibility.vendor' | t }}</span>
              <div class="caption-with-letter-spacing light">{{ card_product.vendor }}</div>
            {%- endif -%}
 
            <span class="caption-large light">{{ block.settings.description | escape }}</span>
            {%- if show_rating and card_product.metafields.reviews.rating.value != blank -%}
              {% liquid
                assign rating_decimal = 0
                assign decimal = card_product.metafields.reviews.rating.value.rating | modulo: 1
                if decimal >= 0.3 and decimal <= 0.7
                  assign rating_decimal = 0.5
                elsif decimal > 0.7
                  assign rating_decimal = 1
                endif
              %}
              <div
                class="rating"
                role="img"
                aria-label="{{ 'accessibility.star_reviews_info' | t: rating_value: card_product.metafields.reviews.rating.value, rating_max: card_product.metafields.reviews.rating.value.scale_max }}"
              >
                <span
                  aria-hidden="true"
                  class="rating-star color-icon-{{ settings.accent_icons }}"
                  style="--rating: {{ card_product.metafields.reviews.rating.value.rating | floor }}; --rating-max: {{ card_product.metafields.reviews.rating.value.scale_max }}; --rating-decimal: {{ rating_decimal }};"
                ></span>
              </div>
              <p class="rating-text caption">
                <span aria-hidden="true">
                  {{- card_product.metafields.reviews.rating.value }} /
                  {{ card_product.metafields.reviews.rating.value.scale_max -}}
                </span>
              </p>
              <p class="rating-count caption">
                <span aria-hidden="true">({{ card_product.metafields.reviews.rating_count }})</span>
                <span class="visually-hidden">
                  {{- card_product.metafields.reviews.rating_count }}
                  {{ 'accessibility.total_reviews' | t -}}
                </span>
              </p>
            {%- endif -%}
            {% render 'price', product: card_variant, price_class: '' %}
          </div>
        </div>
        {%- if show_quick_add -%}
          <div class="quick-add">
            {%- assign product_form_id = 'quick-add-' | append: section_id | append: card_variant.id -%}
            {%- if card_product.has_only_default_variant -%}
              <product-form>
                {%- form 'product',
                  card_variant,
                  id: product_form_id,
                  class: 'form',
                  novalidate: 'novalidate',
                  data-type: 'add-to-cart-form'
                -%}
                  <input
                    type="hidden"
                    name="id"
                    value="{{ card_variant.id }}"
                    disabled
                  >
                  <button
                    id="{{ product_form_id }}-submit"
                    type="submit"
                    name="add"
                    class="quick-add__submit button button--full-width button--secondary"
                    aria-haspopup="dialog"
                    aria-labelledby="{{ product_form_id }}-submit title-{{ section_id }}-{{ card_variant.id }}"
                    aria-live="polite"
                    data-sold-out-message="true"
                    {% if card_variant.available == false %}
                      disabled
                    {% endif %}
                  >
                    <span>
                      {%- if card_variant.available -%}
                        {{ 'products.product.add_to_cart' | t }}
                      {%- else -%}
                        {{ 'products.product.sold_out' | t }}
                      {%- endif -%}
                    </span>
                    <span class="sold-out-message hidden">
                      {{ 'products.product.sold_out' | t }}
                    </span>
                    <div class="loading-overlay__spinner hidden">
                      <svg
                        aria-hidden="true"
                        focusable="false"
                        role="presentation"
                        class="spinner"
                        viewBox="0 0 66 66"
                        xmlns="http://www.w3.org/2000/svg"
                      >
                        <circle class="path" fill="none" stroke-width="6" cx="33" cy="33" r="30"></circle>
                      </svg>
                    </div>
                  </button>
                {%- endform -%}
              </product-form>
            {%- else -%}
              <modal-opener data-modal="#QuickAdd-{{ card_product.id }}">
                <button
                  id="{{ product_form_id }}-submit"
                  type="submit"
                  name="add"
                  class="quick-add__submit button button--full-width button--secondary"
                  aria-haspopup="dialog"
                  aria-labelledby="{{ product_form_id }}-submit title-{{ section_id }}-{{ card_product.id }}"
                  data-product-url="{{ card_product.url }}"
                >
                  {{ 'products.product.choose_options' | t }}
                  <div class="loading-overlay__spinner hidden">
                    <svg
                      aria-hidden="true"
                      focusable="false"
                      role="presentation"
                      class="spinner"
                      viewBox="0 0 66 66"
                      xmlns="http://www.w3.org/2000/svg"
                    >
                      <circle class="path" fill="none" stroke-width="6" cx="33" cy="33" r="30"></circle>
                    </svg>
                  </div>
                </button>
              </modal-opener>
              <quick-add-modal id="QuickAdd-{{ card_product.id }}" class="quick-add-modal">
                <div
                  role="dialog"
                  aria-label="{{ 'products.product.choose_product_options' | t: product_name: card_product.title | escape }}"
                  aria-modal="true"
                  class="quick-add-modal__content global-settings-popup"
                  tabindex="-1"
                >
                  <button
                    id="ModalClose-{{ card_product.id }}"
                    type="button"
                    class="quick-add-modal__toggle"
                    aria-label="{{ 'accessibility.close' | t }}"
                  >
                    {% render 'icon-close' %}
                  </button>
                  <div id="QuickAddInfo-{{ card_product.id }}" class="quick-add-modal__content-info"></div>
                </div>
              </quick-add-modal>
            {%- endif -%}
          </div>
        {%- endif -%}
        <div class="card__badge {{ settings.badge_position }}">
          {%- if card_variant.available == false -%}
            <span class="badge badge--bottom-left color-{{ settings.sold_out_badge_color_scheme }}">
              {{- 'products.product.sold_out' | t -}}
            </span>
          {%- elsif card_variant.compare_at_price > card_variant.price and card_variant.available -%}
            <span class="badge badge--bottom-left color-{{ settings.sale_badge_color_scheme }}">
              {{- 'products.product.on_sale' | t -}}
            </span>
          {%- endif -%}
        </div>
      </div>
    </div>
  </div>
{%- else -%}
  <div class="card-wrapper underline-links-hover">
    <div
      class="
        card
        card--{{ settings.card_style }}
        card--text
        {% if extend_height %} card--extend-height{% endif %}
        {% if settings.card_style == 'card' %} color-{{ settings.card_color_scheme }} gradient{% endif %}
        {% if card_variant.featured_media == nil and settings.card_style == 'card' %} ratio{% endif %}
      "
      style="--ratio-percent: 100%;"
    >
      <div
        class="card__inner {% if settings.card_style == 'standard' %}color-{{ settings.card_color_scheme }} gradient{% endif %}{% if settings.card_style == 'standard' %} ratio{% endif %}"
        style="--ratio-percent: 100%;"
      >
        <div class="card__content">
          <div class="card__information">
            <h3 class="card__heading">
              <a role="link" aria-disabled="true" class="full-unstyled-link">
                {{ 'onboarding.product_title' | t }}
              </a>
            </h3>
          </div>
        </div>
      </div>
      <div class="card__content">
        <div class="card__information">
          <h3 class="card__heading{% if settings.card_style == 'standard' %} h5{% endif %}">
            <a role="link" aria-disabled="true" class="full-unstyled-link">
              {{ 'onboarding.product_title' | t }}
            </a>
          </h3>
          <div class="card-information">
            {%- if show_vendor -%}
              <span class="visually-hidden">{{ 'accessibility.vendor' | t }}</span>
              <div class="caption-with-letter-spacing light">{{ 'products.product.vendor' | t }}</div>
            {%- endif -%}
            {% render 'price' %}
          </div>
        </div>
      </div>
    </div>
  </div>
{%- endif -%}

 

For Dawn 7.0 and higher 

{% comment %}
  Renders a product card
 
  Accepts:
  - card_product: {Object} Product Liquid object (optional)
  - media_aspect_ratio: {String} Size of the product image card. Values are "square" and "portrait". Default is "square" (optional)
  - image_shape: {String} Image mask to apply to the product image card. Values are "arch", "blob", "chevronleft", "chevronright", "diamond", "parallelogram", and "round". (optional)
  - show_secondary_image: {Boolean} Show the secondary image on hover. Default: false (optional)
  - show_vendor: {Boolean} Show the product vendor. Default: false
  - show_rating: {Boolean} Show the product rating. Default: false
  - extend_height: {Boolean} Card height extends to available container space. Default: true (optional)
  - lazy_load: {Boolean} Image should be lazy loaded. Default: true (optional)
  - show_quick_add: {Boolean} Show the quick add button.
  - section_id: {String} The ID of the section that contains this card.
  - horizontal_class: {Boolean} Add a card--horizontal class if set to true. Default: false (optional)
  - horizontal_quick_add: {Boolean} Changes the quick add button styles when set to true. Default: false (optional)
  - placeholder_image: {String} The placeholder image to use when no product exists. Default: 'product-apparel-2' (optional)
 
  Usage:
  {% render 'card-product', show_vendor: section.settings.show_vendor %}
{% endcomment %}
 
{{ 'component-rating.css' | asset_url | stylesheet_tag }}
 
{%- if card_product and card_product != empty -%}
  {%- liquid
    assign ratio = 1
    if card_variant.featured_media and media_aspect_ratio == 'portrait'
      assign ratio = 0.8
    elsif card_variant.featured_media and media_aspect_ratio == 'adapt'
      assign ratio = card_variant.featured_media.aspect_ratio
    endif
    if ratio == 0 or ratio == null
      assign ratio = 1
    endif
  -%}
  <div class="card-wrapper product-card-wrapper underline-links-hover">
    <div
      class="
        card
        card--{{ settings.card_style }}
        {% if card_variant.featured_media %} card--media{% else %} card--text{% endif %}
        {% if settings.card_style == 'card' %} color-{{ settings.card_color_scheme }} gradient{% endif %}
        {% if image_shape and image_shape != 'default' %} card--shape{% endif %}
        {% if extend_height %} card--extend-height{% endif %}
        {% if card_variant.featured_media == nil and settings.card_style == 'card' %} ratio{% endif %}
        {% if horizontal_class %} card--horizontal{% endif %}
      "
      style="--ratio-percent: {{ 1 | divided_by: ratio | times: 100 }}%;"
    >
      <div
        class="card__inner {% if settings.card_style == 'standard' %}color-{{ settings.card_color_scheme }} gradient{% endif %}{% if card_variant.featured_media or settings.card_style == 'standard' %} ratio{% endif %}"
        style="--ratio-percent: {{ 1 | divided_by: ratio | times: 100 }}%;"
      >
        {%- if card_variant.featured_media -%}
          <div class="card__media{% if image_shape and image_shape != 'default' %} shape--{{ image_shape }} color-{{ settings.card_color_scheme }} gradient{% endif %}">
            <div class="media media--transparent media--hover-effect">
              {% comment %}theme-check-disable ImgLazyLoading{% endcomment %}
              <img
                srcset="
                  {%- if card_variant.featured_media.width >= 165 -%}{{ card_variant.featured_media | image_url: width: 165 }} 165w,{%- endif -%}
                  {%- if card_variant.featured_media.width >= 360 -%}{{ card_variant.featured_media | image_url: width: 360 }} 360w,{%- endif -%}
                  {%- if card_variant.featured_media.width >= 533 -%}{{ card_variant.featured_media | image_url: width: 533 }} 533w,{%- endif -%}
                  {%- if card_variant.featured_media.width >= 720 -%}{{ card_variant.featured_media | image_url: width: 720 }} 720w,{%- endif -%}
                  {%- if card_variant.featured_media.width >= 940 -%}{{ card_variant.featured_media | image_url: width: 940 }} 940w,{%- endif -%}
                  {%- if card_variant.featured_media.width >= 1066 -%}{{ card_variant.featured_media | image_url: width: 1066 }} 1066w,{%- endif -%}
                  {{ card_variant.featured_media | image_url }} {{ card_variant.featured_media.width }}w
                "
                src="{{ card_variant.featured_media | image_url: width: 533 }}"
                sizes="(min-width: {{ settings.page_width }}px) {{ settings.page_width | minus: 130 | divided_by: 4 }}px, (min-width: 990px) calc((100vw - 130px) / 4), (min-width: 750px) calc((100vw - 120px) / 3), calc((100vw - 35px) / 2)"
                alt="{{ card_variant.featured_media.alt | escape }}"
                class="motion-reduce"
                {% unless lazy_load == false %}
                  loading="lazy"
                {% endunless %}
                width="{{ card_variant.featured_media.width }}"
                height="{{ card_variant.featured_media.height }}"
              >
              {% comment %}theme-check-enable ImgLazyLoading{% endcomment %}
 
              {%- if card_variant.metafields.my_fields.secondary_image != null and show_secondary_image -%}
                <img
                  srcset="
                    {%- if card_variant.metafields.my_fields.secondary_image.width >= 165 -%}{{ card_variant.metafields.my_fields.secondary_image | image_url: width: 165 }} 165w,{%- endif -%}
                    {%- if card_variant.metafields.my_fields.secondary_image.width >= 360 -%}{{ card_variant.metafields.my_fields.secondary_image | image_url: width: 360 }} 360w,{%- endif -%}
                    {%- if card_variant.metafields.my_fields.secondary_image.width >= 533 -%}{{ card_variant.metafields.my_fields.secondary_image | image_url: width: 533 }} 533w,{%- endif -%}
                    {%- if card_variant.metafields.my_fields.secondary_image.width >= 720 -%}{{ card_variant.metafields.my_fields.secondary_image | image_url: width: 720 }} 720w,{%- endif -%}
                    {%- if card_variant.metafields.my_fields.secondary_image.width >= 940 -%}{{ card_variant.metafields.my_fields.secondary_image | image_url: width: 940 }} 940w,{%- endif -%}
                    {%- if card_variant.metafields.my_fields.secondary_image.width >= 1066 -%}{{ card_variant.metafields.my_fields.secondary_image | image_url: width: 1066 }} 1066w,{%- endif -%}
                    {{ card_variant.metafields.my_fields.secondary_image | image_url }} {{ card_variant.metafields.my_fields.secondary_image.width }}w
                  "
                  src="{{ card_variant.metafields.my_fields.secondary_image | image_url: width: 533 }}"
                  sizes="(min-width: {{ settings.page_width }}px) {{ settings.page_width | minus: 130 | divided_by: 4 }}px, (min-width: 990px) calc((100vw - 130px) / 4), (min-width: 750px) calc((100vw - 120px) / 3), calc((100vw - 35px) / 2)"
                  alt=""
                  class="motion-reduce"
                  loading="lazy"
                  width="{{ card_variant.metafields.my_fields.secondary_image.width }}"
                  height="{{ card_variant.metafields.my_fields.secondary_image.height }}"
                >
              {%- endif -%}
            </div>
          </div>
        {%- endif -%}
        <div class="card__content">
          <div class="card__information">
            <h3
              class="card__heading"
              {% if card_variant.featured_media == null and settings.card_style == 'standard' %}
                id="title-{{ section_id }}-{{ card_variant.id }}"
              {% endif %}
            >
              <a
                href="{{ card_variant.url }}"
                id="StandardCardNoMediaLink-{{ section_id }}-{{ card_variant.id }}"
                class="full-unstyled-link"
                aria-labelledby="StandardCardNoMediaLink-{{ section_id }}-{{ card_variant.id }} NoMediaStandardBadge-{{ section_id }}-{{ card_variant.id }}"
              >
                {{ card_product.title | escape }}
                {% if hide_variant_info == false %}
                  <br>
                  {{ card_variant.title | capitalize }}
                {% endif %}
              </a>
            </h3>
          </div>
          <div class="card__badge {{ settings.badge_position }}">
            {%- if card_variant.available == false -%}
              <span
                id="NoMediaStandardBadge-{{ section_id }}-{{ card_variant.id }}"
                class="badge badge--bottom-left color-{{ settings.sold_out_badge_color_scheme }}"
              >
                {{- 'products.product.sold_out' | t -}}
              </span>
            {%- elsif card_variant.compare_at_price > card_variant.price and card_variant.available -%}
              <span
                id="NoMediaStandardBadge-{{ section_id }}-{{ card_variant.id }}"
                class="badge badge--bottom-left color-{{ settings.sale_badge_color_scheme }}"
              >
                {{- 'products.product.on_sale' | t -}}
              </span>
            {%- endif -%}
          </div>
        </div>
      </div>
      <div class="card__content">
        <div class="card__information">
          <h3
            class="card__heading{% if card_variant.featured_media or settings.card_style == 'standard' %} h5{% endif %}"
            {% if card_variant.featured_media or settings.card_style == 'card' %}
              id="title-{{ section_id }}-{{ card_variant.id }}"
            {% endif %}
          >
            <a
              href="{{ card_variant.url }}"
              id="CardLink-{{ section_id }}-{{ card_variant.id }}"
              class="full-unstyled-link"
              aria-labelledby="CardLink-{{ section_id }}-{{ card_variant.id }} Badge-{{ section_id }}-{{ card_variant.id }}"
            >
              {{ card_product.title | escape }}
              {% if hide_variant_info == false %}
                <br>
                {{ card_variant.title | capitalize }}
              {% endif %}
            </a>
          </h3>
          <div class="card-information">
            {%- if show_vendor -%}
              <span class="visually-hidden">{{ 'accessibility.vendor' | t }}</span>
              <div class="caption-with-letter-spacing light">{{ card_variant.vendor }}</div>
            {%- endif -%}
            <span class="caption-large light">{{ block.settings.description | escape }}</span>
            {%- if show_rating and card_variant.metafields.reviews.rating.value != blank -%}
              {% liquid
                assign rating_decimal = 0
                assign decimal = card_variant.metafields.reviews.rating.value.rating | modulo: 1
                if decimal >= 0.3 and decimal <= 0.7
                  assign rating_decimal = 0.5
                elsif decimal > 0.7
                  assign rating_decimal = 1
                endif
              %}
              <div
                class="rating"
                role="img"
                aria-label="{{ 'accessibility.star_reviews_info' | t: rating_value: card_variant.metafields.reviews.rating.value, rating_max: card_variant.metafields.reviews.rating.value.scale_max }}"
              >
                <span
                  aria-hidden="true"
                  class="rating-star"
                  style="--rating: {{ card_variant.metafields.reviews.rating.value.rating | floor }}; --rating-max: {{ card_variant.metafields.reviews.rating.value.scale_max }}; --rating-decimal: {{ rating_decimal }};"
                ></span>
              </div>
              <p class="rating-text caption">
                <span aria-hidden="true">
                  {{- card_variant.metafields.reviews.rating.value }} /
                  {{ card_variant.metafields.reviews.rating.value.scale_max -}}
                </span>
              </p>
              <p class="rating-count caption">
                <span aria-hidden="true">({{ card_variant.metafields.reviews.rating_count }})</span>
                <span class="visually-hidden">
                  {{- card_variant.metafields.reviews.rating_count }}
                  {{ 'accessibility.total_reviews' | t -}}
                </span>
              </p>
            {%- endif -%}
              {% render 'price', product: card_product, price_class: '' %}
          </div>
        </div>
        {%- if show_quick_add -%}
          <div class="quick-add no-js-hidden">
            {%- liquid
              assign product_form_id = 'quick-add-' | append: section_id | append: card_variant.id
              assign qty_rules = false
              if card_variant.quantity_rule.min > 1 or card_variant.quantity_rule.max != null or card_variant.quantity_rule.increment > 1
                assign qty_rules = true
              endif
            -%}
            {%- if card_variant.variants.size > 1 or qty_rules -%}
              <modal-opener data-modal="#QuickAdd-{{ card_variant.id }}">
                <button
                  id="{{ product_form_id }}-submit"
                  type="submit"
                  name="add"
                  class="quick-add__submit button button--full-width button--secondary{% if horizontal_quick_add %} card--horizontal__quick-add animate-arrow{% endif %}"
                  aria-haspopup="dialog"
                  aria-labelledby="{{ product_form_id }}-submit title-{{ section_id }}-{{ card_variant.id }}"
                  data-product-url="{{ card_variant.url }}"
                >
                  {{ 'products.product.choose_options' | t }}
                  {%- if horizontal_quick_add -%}
                    <span class="icon-wrap">{% render 'icon-arrow' %}</span>
                  {%- endif -%}
                  <div class="loading-overlay__spinner hidden">
                    <svg
                      aria-hidden="true"
                      focusable="false"
                      class="spinner"
                      viewBox="0 0 66 66"
                      xmlns="http://www.w3.org/2000/svg"
                    >
                      <circle class="path" fill="none" stroke-width="6" cx="33" cy="33" r="30"></circle>
                    </svg>
                  </div>
                </button>
              </modal-opener>
              <quick-add-modal id="QuickAdd-{{ card_variant.id }}" class="quick-add-modal">
                <div
                  role="dialog"
                  aria-label="{{ 'products.product.choose_product_options' | t: product_name: card_variant.title | escape }}"
                  aria-modal="true"
                  class="quick-add-modal__content global-settings-popup"
                  tabindex="-1"
                >
                  <button
                    id="ModalClose-{{ card_variant.id }}"
                    type="button"
                    class="quick-add-modal__toggle"
                    aria-label="{{ 'accessibility.close' | t }}"
                  >
                    {% render 'icon-close' %}
                  </button>
                  <div id="QuickAddInfo-{{ card_variant.id }}" class="quick-add-modal__content-info"></div>
                </div>
              </quick-add-modal>
            {%- else -%}
              <product-form>
                {%- form 'product',
                  card_product,
                  id: product_form_id,
                  class: 'form',
                  novalidate: 'novalidate',
                  data-type: 'add-to-cart-form'
                -%}
                  <input
                    type="hidden"
                    name="id"
                    value="{{ card_variant.id }}"
                    disabled
                  >
                  <button
                    id="{{ product_form_id }}-submit"
                    type="submit"
                    name="add"
                    class="quick-add__submit button button--full-width button--secondary{% if horizontal_quick_add %} card--horizontal__quick-add{% endif %}"
                    aria-haspopup="dialog"
                    aria-labelledby="{{ product_form_id }}-submit title-{{ section_id }}-{{ card_variant.id }}"
                    aria-live="polite"
                    data-sold-out-message="true"
                    {% if card_variant.available == false %}
                      disabled
                    {% endif %}
                  >
                    <span>
                      {%- if card_variant.available -%}
                        {{ 'products.product.add_to_cart' | t }}
                      {%- else -%}
                        {{ 'products.product.sold_out' | t }}
                      {%- endif -%}
                    </span>
                    <span class="sold-out-message hidden">
                      {{ 'products.product.sold_out' | t }}
                    </span>
                    {%- if horizontal_quick_add -%}
                      <span class="icon-wrap">{% render 'icon-plus' %}</span>
                    {%- endif -%}
                    <div class="loading-overlay__spinner hidden">
                      <svg
                        aria-hidden="true"
                        focusable="false"
                        class="spinner"
                        viewBox="0 0 66 66"
                        xmlns="http://www.w3.org/2000/svg"
                      >
                        <circle class="path" fill="none" stroke-width="6" cx="33" cy="33" r="30"></circle>
                      </svg>
                    </div>
                  </button>
                {%- endform -%}
              </product-form>
            {%- endif -%}
          </div>
        {%- endif -%}
        <div class="card__badge {{ settings.badge_position }}">
          {%- if card_variant.available == false -%}
            <span
              id="Badge-{{ section_id }}-{{ card_variant.id }}"
              class="badge badge--bottom-left color-{{ settings.sold_out_badge_color_scheme }}"
            >
              {{- 'products.product.sold_out' | t -}}
            </span>
          {%- elsif card_variant.compare_at_price > card_variant.price and card_variant.available -%}
            <span
              id="Badge-{{ section_id }}-{{ card_variant.id }}"
              class="badge badge--bottom-left color-{{ settings.sale_badge_color_scheme }}"
            >
              {{- 'products.product.on_sale' | t -}}
            </span>
          {%- endif -%}
        </div>
      </div>
    </div>
  </div>
{%- else -%}
  <div class="card-wrapper product-card-wrapper underline-links-hover">
    <div
      class="
        card
        card--{{ settings.card_style }}
        card--text
        {% if extend_height %} card--extend-height{% endif %}
        {% if settings.card_style == 'card' %} color-{{ settings.card_color_scheme }} gradient{% endif %}
        {% if card_variant.featured_media == nil and settings.card_style == 'card' %} ratio{% endif %}
        {{ horizontal_class }}
      "
      style="--ratio-percent: 100%;"
    >
      <div
        class="card__inner {% if settings.card_style == 'standard' %}color-{{ settings.card_color_scheme }} gradient{% endif %}{% if settings.card_style == 'standard' %} ratio{% endif %}"
        style="--ratio-percent: 100%;"
      >
        <div class="card__media">
          {%- if placeholder_image -%}
            {{ placeholder_image | placeholder_svg_tag: 'placeholder-svg' }}
          {%- else -%}
            {{ 'product-apparel-2' | placeholder_svg_tag: 'placeholder-svg' }}
          {%- endif -%}
        </div>
      </div>
      <div class="card__content">
        <div class="card__information">
          <h3 class="card__heading card__heading--placeholder{% if settings.card_style == 'standard' %} h5{% endif %}">
            <a role="link" aria-disabled="true" class="full-unstyled-link">
              {{ 'onboarding.product_title' | t }}
            </a>
          </h3>
          <div class="card-information">
            {%- if show_vendor -%}
              <span class="visually-hidden">{{ 'accessibility.vendor' | t }}</span>
              <div class="caption-with-letter-spacing light">{{ 'products.product.vendor' | t }}</div>
            {%- endif -%}
            {% render 'price' %}
          </div>
        </div>
      </div>
    </div>
  </div>
{%- endif -%}

 

5. Make sure to SAVE

That is it (",)

Copied!
Back to blog

4 comments

@DHEL DOMINCIL,

At this moment, the filter does not work with this. I have not get a chance to write a specific filter for this but stay tuned.

Made4Uo

Cool tutorial! I do have a question:

With the variants showing as individual products on the collection, will the filter(s) for a collection page filter out the specific variants as well?

As an example: If there are several different products that all have a green variant, and customer wants to see only green products, will the filter on the collection page show only those green variants fafter filter?

Dhel Domincil

Hi @Binaebi,
This should work in any Shopify 2.0 FREE themes, since they share the same code, the only difference is the CSS which is not much. Can you message me in “Chat with us” to discuss what gone wrong? Thank you

Made4Uo

This did not work with the Studio theme. It broke the collection and won’t show the filters or even the default products. Everything after the collection banner is gone.

Binaebi Calkins

Leave a comment