How To Show Variants As Separate Products On Shopify?

How To Show Variants As Separate Products On Shopify?

Introduction

Welcome back to the channel! In today’s video, we have an exciting Shopify tutorial for you, focusing on enhancing your collection page by displaying product variants as separate products.. The best part? No need to install any apps or purchase subscriptions – just follow this step-by-step guide.

Installing the Dawn 12.0.0 Theme
For this demonstration, we’ll install a fresh Dawn 12.0.0 theme. As of December 3rd, 2023, this tutorial is compatible with the latest version. Click the “Add” button to install the theme, then publish it.

Setting Up Variant Images
Before diving into code changes, ensure that each variant has an associated image. This is crucial for a seamless implementation. Edit your product, select the appropriate image for each variant, and save the changes.

Code Implementation
To achieve the desired display, we’ll follow a two-step code implementation process.

Adding a New Snippet
Access the backend, add a new snippet named ‘card-variant.liquid,’ and paste the provided code. Save the changes.

Updating the Collection Product Grid
Navigate to the ‘main-collection-product-grid.liquid’ file, locate the existing code for product display, and replace it with the provided code
from the tutorial. Save the changes.

Create a new snippet called card-variant.liquid with the following code:

{{ 'component-rating.css' | asset_url | stylesheet_tag }}
{{ 'component-volume-pricing.css' | asset_url | stylesheet_tag }}

{% comment %}
Code is tested by WebSensePro team with Dawn 12.0.0 Theme 

Code is subject to be updated with every theme updates, for more info contact via https://websensepro.com/contact-us

{% endcomment %}

{%- 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="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">
    
              <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 }}"
              >
           
 
           {%- if card_product.media[1] != null and show_secondary_image -%}
                <img
                  srcset="
                    {%- if card_product.media[1].width >= 165 -%}{{ card_product.media[1] | image_url: width: 165 }} 165w,{%- endif -%}
                    {%- if card_product.media[1].width >= 360 -%}{{ card_product.media[1] | image_url: width: 360 }} 360w,{%- endif -%}
                    {%- if card_product.media[1].width >= 533 -%}{{ card_product.media[1] | image_url: width: 533 }} 533w,{%- endif -%}
                    {%- if card_product.media[1].width >= 720 -%}{{ card_product.media[1] | image_url: width: 720 }} 720w,{%- endif -%}
                    {%- if card_product.media[1].width >= 940 -%}{{ card_product.media[1] | image_url: width: 940 }} 940w,{%- endif -%}
                    {%- if card_product.media[1].width >= 1066 -%}{{ card_product.media[1] | image_url: width: 1066 }} 1066w,{%- endif -%}
                    {{ card_product.media[1] | image_url }} {{ card_product.media[1].width }}w
                  "
                  src="{{ card_product.media[1] | 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_product.media[1].width }}"
                  height="{{ card_product.media[1].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_variant.product.title | escape }}  - {{ variant_option }}
              </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_variant.product.title | escape }} - {{ variant_option }}
            </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
              %}
{% comment %}
Code is tested by WebSensePro team with Dawn 12.0.0 Theme 

Code is subject to be updated with every theme updates, for more info contact via https://websensepro.com/contact-us

{% endcomment %}
              <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_variant, price_class: '', show_compare_at_price: true %}
            {%- if card_variant.quantity_price_breaks_configured? -%}
              <div class="card__information-volume-pricing-note">
                <span class="caption">{{ 'products.product.volume_pricing.note' | t }}</span>
              </div>
            {%- endif -%}
          </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_product.id
              assign qty_rules = false
              if card_product.selected_or_first_available_variant.quantity_rule.min > 1 or card_product.selected_or_first_available_variant.quantity_rule.max != null or card_product.selected_or_first_available_variant.quantity_rule.increment > 1
                assign qty_rules = true
              endif
            -%}
            {%- if card_product.variants.size > 1 or qty_rules -%}
              <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{% if horizontal_quick_add %} card--horizontal__quick-add animate-arrow{% endif %}"
                  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 }}
                  {%- if horizontal_quick_add -%}
                    <span class="icon-wrap">{% render 'icon-arrow' %}</span>
                  {%- endif -%}
                  {%- render 'loading-spinner' -%}
                </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>
            {%- else -%}
              <product-form data-section-id="{{ section.id }}">
                {%- 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_product.selected_or_first_available_variant.id }}"
                    class="product-variant-id"
                    {% if card_product.selected_or_first_available_variant.available == false %}
                      disabled
                    {% endif %}
                  >
                  <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_product.id }}"
                    aria-live="polite"
                    data-sold-out-message="true"
                    {% if card_product.selected_or_first_available_variant.available == false %}
                      disabled
                    {% endif %}
                  >
                    <span>
                      {%- if card_product.selected_or_first_available_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 -%}
                    {%- render 'loading-spinner' -%}
                  </button>
                {%- endform -%}
              </product-form>
            {%- endif -%}
          </div>
        {%- endif -%}
        <div class="card__badge {{ settings.badge_position }}">
          {%- if card_product.available == false -%}
            <span
              id="Badge-{{ section_id }}-{{ card_product.id }}"
              class="badge badge--bottom-left color-{{ settings.sold_out_badge_color_scheme }}"
            >
              {{- 'products.product.sold_out' | t -}}
            </span>
          {%- elsif card_product.compare_at_price > card_product.price and card_product.available -%}
            <span
              id="Badge-{{ section_id }}-{{ card_product.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 }}
        {% if extend_height %} card--extend-height{% endif %}
        {% if settings.card_style == 'card' %} color-{{ settings.card_color_scheme }} gradient{% endif %}
      "
      style="--ratio-percent: 100%;"
    >
      <div
        class="card__inner{% if settings.card_style == 'standard' %} color-{{ settings.card_color_scheme }} gradient{% endif %} ratio"
        style="--ratio-percent: 100%;"
      >
        <div class="card__media">
          <div class="media media--transparent">
            {%- if placeholder_image -%}
              {{ placeholder_image | placeholder_svg_tag: 'placeholder-svg' }}
            {%- else -%}
              {{ 'product-apparel-2' | placeholder_svg_tag: 'placeholder-svg' }}
            {% endif %}
          </div>
        </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', show_compare_at_price: true %}
          </div>
        </div>
      </div>
    </div>
  </div>
{%- endif -%}

Replace the following code in main-collection-product-grid.liquid:

<li
                  class="grid__item{% if settings.animations_reveal_on_scroll %} scroll-trigger animate--slide-in{% endif %}"
                  {% if settings.animations_reveal_on_scroll %}
                    data-cascade
                    style="--animation-order: {{ forloop.index }};"
                  {% endif %}
                >
                  {% render 'card-product',
                    card_product: product,
                    media_aspect_ratio: section.settings.image_ratio,
                    image_shape: section.settings.image_shape,
                    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>

With following code:

{%- liquid
    assign option_chosen = "Color" 
    assign option_index = ''
    for option in product.options
        if option_chosen == option
            assign option_index = forloop.index0 
            break
        endif
    endfor
-%}
{% comment %}
Code is tested by WebSensePro team with Dawn 12.0.0 Theme 

Code is subject to be updated with every theme updates, for more info contact via https://websensepro.com/contact-us

{% endcomment %}

{%- if option_index == '' -%}
  <li
  class="grid__item{% if settings.animations_reveal_on_scroll %} scroll-trigger animate--slide-in{% endif %}"
  {% if settings.animations_reveal_on_scroll %}
      data-cascade
      style="--animation-order: {{ forloop.index }};"
  {% endif %}
  >
  {% render 'card-product',
      card_product: product,
      media_aspect_ratio: section.settings.image_ratio,
      image_shape: section.settings.image_shape,
      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>
{%- else -%}
  {% assign displayed_values = "" %}
  {% for variant in product.variants %}
  {%- liquid
    assign variant_option = variant.options[option_index]
    assign valueIsDisplayed = false
    for value in displayed_values
      if value == variant_option
        assign valueIsDisplayed = true
        break
      endif
    endfor
  -%}
  {% unless valueIsDisplayed %}
      {%- assign variant_option_arr = variant_option | append: ';'  | split: ';' -%}
      {% assign displayed_values = displayed_values | concat: variant_option_arr %}
      <li
      class="grid__item{% if settings.animations_reveal_on_scroll %} scroll-trigger animate--slide-in{% endif %}"
      {% if settings.animations_reveal_on_scroll %}
          data-cascade
          style="--animation-order: {{ forloop.index }};"
      {% endif %}
      >
      {% render 'card-variant',
          card_variant: variant,
          card_product: product,
          variant_option: variant_option,
          media_aspect_ratio: section.settings.image_ratio,
          image_shape: section.settings.image_shape,
          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>
    {% endunless %}
  {% endfor %}
{%- endif -%}

Preview and Customize
After implementing the code changes, preview your theme and head to the collection page. You’ll now notice that each variant is displayed as a separate product, enriching the overall user experience.

Bonus Tip: Displaying Variants by Size
Customization doesn’t stop there! As shown in the tutorial, you can easily modify the code to display variants based on size rather than color. Simply update the specified option to ‘size’ in the code.

4.1/5 - (19 votes)

About

Leave a Comment

Your email address will not be published. Required fields are marked *