The wrong variant gets added to the cart.

Solved

The wrong variant gets added to the cart.

entranced
Explorer
79 3 16

Hi,

I want to be able to set a threshold on products that have multiple variants so that any variant with a stock level of three or less is treated as sold out. I’ve gotten some help along the way and the function now works: variants with low stock levels are greyed out and unselectable.

 

However, another bug has cropped up: the wrong variant ends up in the cart. For example, if you choose to buy the “30 ml” variant on this example , the first available variant is added to the cart instead (in this case, 100 ml). We can’t find any solution at all. Does anyone have any ideas?

 

The theme is Be Yours, and the modified files are product-variant-options.liquid and product-variant-picker.liquid. Thanks!

Accepted Solution (1)

entranced
Explorer
79 3 16

This is an accepted solution.

I approached it differently. Instead of disabling the variant buttons for items with low stock, I chose to hide them. That way, the add-to-cart functionality etc. wasn’t affected. So case closed.

View solution in original post

Replies 4 (4)
entranced
Explorer
79 3 16

Hi Markit-Themes,

 

Thanks a lot for stopping by. 

 

Here is the modified product-variant-options.liquid

{% comment %}
  Renders product variant options

  Accepts:
  - product: {Object} product object.
  - option:  {Object} current product_option object.
  - block:   {Object} block object.
  - picker_type: {String} type of picker to display

  Usage:
  {% render 'product-variant-options',
    product: product,
    option: option,
    block: block,
    picker_type: picker_type
  %}
{% endcomment %}

{%- liquid
  assign product_form_id = 'product-form-' | append: section.id
  assign has_set_default = false
-%}

{%- for value in option.values -%}
  {%- liquid
    # --- SWATCH / DROPDOWN-LOGIK (oförändrad) ---
    assign swatch_focal_point = null
    assign swatch_value       = value | split: ' ' | last | handle

    if block.settings.swatch_source == 'native'
      if value.swatch.image
        assign image_url         = value.swatch.image | image_url: width: 50
        assign swatch_value      = 'url(' | append: image_url | append: ')'
        assign swatch_focal_point = value.swatch.image.presentation.focal_point
      elsif value.swatch.color
        assign swatch_value = 'rgb(' | append: value.swatch.color.rgb | append: ')'
      else
        assign swatch_value = null
      endif
    else
      if block.settings.swatch_source == 'variant'
        if value.variant.image
          assign color_variant_image = value.variant.image | image_url: width: 50
          assign swatch_value        = 'url(' | append: color_variant_image | append: ')'
        endif
      else
        # (din befintliga “custom swatch”-logik här…)
      endif
    endif

    # --- NY STOCK-LOGIK ---
    assign this_variant    = value.variant
    assign stock           = this_variant.inventory_quantity
    assign option_disabled = true
    if stock > 3
      assign option_disabled = false
    endif
  -%}

  {%- comment -%} Sätt “checked” på första tillgängliga variant {%- endcomment -%}
  {% assign is_checked = false %}
  {% if option_disabled == false %}
    {% if value.selected or has_set_default == false %}
      {% assign is_checked      = true %}
      {% assign has_set_default = true %}
    {% endif %}
  {% endif %}

  {%- capture input_id      -%}{{ section.id }}-{{ option.position }}-{{ forloop.index0 }}{%- endcapture -%}
  {%- capture input_name    -%}{{ option.name }}-{{ option.position }}{%- endcapture -%}
  {%- capture input_dataset -%}
    data-product-url="{{ value.product_url }}"
    data-option-value-id="{{ value.id }}"
  {%- endcapture -%}
  {%- capture label_unavailable -%}
    <span class="visually-hidden label-unavailable">
      {{ 'products.product.variant_sold_out_or_unavailable' | t }}
    </span>
  {%- endcapture -%}

  {%- if picker_type == 'swatch' -%}
    {%- capture help_text -%}
      <span class="visually-hidden">{{ value | escape }}</span>
      {{ label_unavailable }}
    {%- endcapture -%}
    {% render 'swatch-input',
      id:               input_id,
      name:             input_name,
      value:            value | escape,
      swatch:           value.swatch,
      product_form_id:  product_form_id,
      checked:          is_checked,
      visually_disabled: option_disabled,
      shape:            block.settings.swatch_type,
      source:           block.settings.swatch_source,
      option:           option,
      product:          product,
      help_text:        help_text,
      additional_props: input_dataset
    %}

  {%- elsif picker_type == 'button' -%}
    <input
      type="radio"
      id="{{ input_id }}"
      name="{{ input_name | escape }}"
      value="{{ value | escape }}"
      form="{{ product_form_id }}"
      class="button-input__input{% if option_disabled %} disabled{% endif %}"
      {% if option_disabled %}disabled aria-disabled="true"{% endif %}
      {% if is_checked %}checked{% endif %}
      {{ input_dataset }}
    >
    <label for="{{ input_id }}" class="{% if option_disabled %}is-sold-out{% endif %}">
      {{ value }}
    </label>

  {%- elsif picker_type == 'dropdown' or picker_type == 'swatch_dropdown' -%}
    <option
      id="{{ input_id }}"
      value="{{ value | escape }}"
      {% if is_checked %}selected{% endif %}
      {% if swatch_value and picker_type == 'swatch_dropdown' %}
        data-option-swatch-value="{{ swatch_value }}"
        {% if swatch_focal_point %}
          data-option-swatch-focal-point="{{ swatch_focal_point }}"
        {% endif %}
      {% endif %}
      {{ input_dataset }}
    >
      {% if option_disabled %}
        {{ 'products.product.value_unavailable' | t: option_value: value }}
      {% else %}
        {{ value }}
      {% endif %}
    </option>
  {%- endif -%}

{%- endfor -%}

 

Here is the modified product-variant-picker.liquid

{% comment %}
  Renders product variant-picker

  Accepts:
  - product: {Object} product object.
  - block: {Object} passing the block information.
  - product_form_id: {String} Id of the product form to which the variant picker is associated.

  Usage:
  {% render 'product-variant-picker', product: product, block: block, product_form_id: product_form_id %}
{% endcomment %}

{%- unless product.has_only_default_variant -%}
  <variant-selects
    data-primary
    id="variant-selects-{{ section.id }}"
    data-section="{{ section.id }}"
    {{ block.shopify_attributes }}
  >
    {%- for option in product.options_with_values -%}
      {%- liquid
        assign picker_type = block.settings.picker_type

        if block.settings.swatch_type != 'none'
          assign native_swatch_eligible = false
          assign custom_swatch_eligible = false

          if block.settings.swatch_source == 'native'
            assign native_swatch_count = option.values | map: 'swatch' | compact | size
            if native_swatch_count > 0
              assign native_swatch_eligible = true
            endif
          else
            assign custom_swatch_trigger = 'products.product.color_swatch_trigger' | t | downcase
            assign downcased_option      = option.name | downcase
            if custom_swatch_trigger contains downcased_option
              assign custom_swatch_eligible = true
            endif
          endif

          if native_swatch_eligible or custom_swatch_eligible
            if block.settings.picker_type == 'dropdown'
              assign picker_type = 'swatch_dropdown'
            else
              assign picker_type = 'swatch'
            endif
          endif
        endif

        assign is_size = false
        if block.settings.size_chart != blank
          assign size_trigger     = 'products.product.size_chart_trigger' | t | downcase
          assign downcased_option = option.name | downcase
          if size_trigger contains downcased_option
            assign is_size = true
          endif
        endif
      -%}

      {%- capture sizechart_cta -%}
        {%- if is_size -%}
          <div class="form__popup" id="size-{{ section.id }}">
            <modal-opener
              class="no-js-hidden"
              data-modal="#PopupModal-{{ block.id }}"
              {{ block.shopify_attributes }}
            >
              <button
                id="ProductPopup-{{ block.id }}"
                class="link link-with-icon"
                type="button"
                aria-haspopup="dialog"
              >
                {% render 'icon', icon: 'ruler' %}
                <span class="label">
                  {{ 'products.product.size_chart' | t | default: block.settings.size_chart.title }}
                </span>
              </button>
            </modal-opener>
            <a href="{{ block.settings.size_chart.url }}" class="link link-with-icon no-js">
              {% render 'icon', icon: 'ruler' %}
              <span class="label">
                {{ 'products.product.size_chart' | t | default: block.settings.size_chart.title }}
              </span>
            </a>
          </div>
        {%- endif -%}
      {%- endcapture -%}

      {%- if picker_type == 'swatch' -%}
        <fieldset class="js product-form__input product-form__input--swatch">
          {%- if block.settings.show_variant_labels -%}
            <legend class="form__label">
              {{ option.name }}:
              <span data-selected-value>{{ option.selected_value }}</span>
            </legend>
          {%- endif -%}
          {% render 'product-variant-options',
            product:      product,
            option:       option,
            block:        block,
            picker_type:  picker_type
          %}
          {{- sizechart_cta -}}
        </fieldset>

      {%- elsif picker_type == 'button' -%}
        <fieldset class="js product-form__input product-form__input--pill">
          {%- if block.settings.show_variant_labels -%}
            <legend class="form__label">{{ option.name }}</legend>
          {%- endif -%}
          {% render 'product-variant-options',
            product:      product,
            option:       option,
            block:        block,
            picker_type:  picker_type
          %}
          {{- sizechart_cta -}}
        </fieldset>

      {%- else -%}
        <div class="product-form__input product-form__input--dropdown">
          {%- if block.settings.show_variant_labels -%}
            <label
              class="form__label"
              for="Option-{{ section.id }}-{{ forloop.index0 }}"
            >
              {{ option.name }}
            </label>
          {%- endif -%}
          <div class="select">
            {%- if picker_type == 'swatch_dropdown' -%}
              <span data-selected-value class="dropdown-swatch">
                {% if block.settings.swatch_source == 'native' %}
                  {% render 'swatch',
                    swatch: option.selected_value.swatch,
                    shape:  block.settings.swatch_type
                  %}
                {% else %}
                  {% render 'swatch-custom',
                    product: product,
                    option:  option,
                    source:  block.settings.swatch_source,
                    shape:   block.settings.swatch_type
                  %}
                {% endif %}
              </span>
            {%- endif -%}
            <select
              id="Option-{{ section.id }}-{{ forloop.index0 }}"
              class="select__select"
              name="options[{{ option.name | escape }}]"
              form="{{ product_form_id }}"
            >
              {% render 'product-variant-options',
                product:      product,
                option:       option,
                block:        block,
                picker_type:  picker_type
              %}
            </select>
            <span class="svg-wrapper">
              {{- 'icon-caret.svg' | inline_asset_content -}}
            </span>
          </div>
          {{- sizechart_cta -}}
        </div>
      {%- endif -%}

    {%- endfor -%}

    {%- comment -%}
      Välj först en variant som har mer än 3 i lager.
      Om ingen sådan finns, fallback till Shopify’s selected_or_first_available_variant.
    {%- endcomment -%}
    {%- assign fallback_variant = product.selected_or_first_available_variant -%}
    {%- assign chosen_variant  = nil -%}

    {%- for variant in product.variants -%}
      {% if variant.inventory_quantity > 3 %}
        {%- assign chosen_variant = variant -%}
        {%- break -%}
      {% endif %}
    {%- endfor -%}

    {%- if chosen_variant == nil -%}
      {%- assign chosen_variant = fallback_variant -%}
    {%- endif -%}

    <script type="application/json" data-selected-variant>
      {{ chosen_variant | json }}
    </script>

    <script>
      document.addEventListener('DOMContentLoaded', function() {
        var vs = document.querySelector('#variant-selects-{{ section.id }}');
        if (!vs) return;
        var checkedInput = vs.querySelector('input[type="radio"]:checked');
        if (checkedInput) {
          checkedInput.dispatchEvent(new Event('change', { bubbles: true }));
        }
      });
    </script>
  </variant-selects>
{%- endunless -%}

 

Here is the original product-variant-options.liquid

{% comment %}
  Renders product variant options

  Accepts:
  - product: {Object} product object.
  - option: {Object} current product_option object.
  - block: {Object} block object.
  - picker_type: {String} type of picker to dispay


  Usage:
  {% render 'product-variant-options',
    product: product,
    option: option,
    block: block
    picker_type: picker_type
  %}
{% endcomment %}
{%- liquid
  assign product_form_id = 'product-form-' | append: section.id
-%}

{%- for value in option.values -%}
  {%- liquid
    assign swatch_focal_point = null

    assign swatch_value = value | split: ' ' | last | handle 
    comment
      fall-back value ↑ or null?
    endcomment
    
    if block.settings.swatch_source == 'native'
      if value.swatch.image
        assign image_url = value.swatch.image | image_url: width: 50
        assign swatch_value = 'url(' | append: image_url | append: ')'
        assign swatch_focal_point = value.swatch.image.presentation.focal_point
      elsif value.swatch.color
        assign swatch_value = 'rgb(' | append: value.swatch.color.rgb | append: ')'
      else
        assign swatch_value = null
      endif
    else
      if block.settings.swatch_source == 'variant'
        if value.variant.image
          assign color_variant_image = value.variant.image | image_url: width: 50
          assign swatch_value = 'url(' | append: color_variant_image | append: ')'
        endif
      else
        assign swatch_file_extension = 'png'
        assign file_name_uniq = product.id | append: '_' | append: value | handle | append: '.' | append: swatch_file_extension
        assign file_name_custom = blank
        assign file_name_alt = value | handle | append: '.' | append: swatch_file_extension
        assign value_downcase = value | downcase
        assign swatch_config = settings.swatch_config | newline_to_br | split: '<br />'
        for swatch in swatch_config
          assign swatch_parts = swatch | strip | split: ':'
          assign swatch_name = swatch_parts.first | downcase | strip
          if swatch_name == value_downcase
            assign swatch_entry = swatch_parts.last | strip
            if swatch_entry contains '#'
              assign swatch_value = swatch_entry
              assign file_name_alt = blank
            else
              assign file_name_custom = swatch_entry
            endif
            break
          endif
        endfor
        assign file_name_final = blank
        if images[file_name_uniq] != blank
          assign file_name_final = file_name_uniq
        elsif file_name_custom != blank and images[file_name_custom] != blank 
          assign file_name_final = file_name_custom
        elsif images[file_name_alt] != blank
          assign file_name_final = file_name_alt
        endif
        assign swatch_image = blank
        if images[file_name_final] != blank
          assign swatch_image = images[file_name_final] | image_url: width: 50
        elsif file_name_final contains '//cdn.shopify.com/'
          assign swatch_image = file_name_final
        endif 
        if swatch_image != blank
          assign swatch_value = 'url(' | append: swatch_image | append: ')'
        endif
      endif
    endif

    assign option_disabled = true
    if value.available
      assign option_disabled = false
    endif
  -%}

  {%- capture input_id -%}
      {{ section.id }}-{{ option.position }}-{{ forloop.index0 -}}
    {%- endcapture -%}

  {%- capture input_name -%}
      {{ option.name }}-{{ option.position }}
    {%- endcapture -%}

  {%- capture input_dataset -%}
      data-product-url="{{ value.product_url }}"
      data-option-value-id="{{ value.id }}"
      {% if option_disabled %}data-crossout{% unless block.settings.enable_swatch_unavailable_click %} disabled{% endunless %}{% endif %}
    {%- endcapture -%}

  {%- capture label_unavailable -%}
      <span class="visually-hidden label-unavailable">
        {{- 'products.product.variant_sold_out_or_unavailable' | t -}}
      </span>
    {%- endcapture -%}

  {%- if picker_type == 'swatch' -%}
    {%- capture help_text -%}
      <span class="visually-hidden">{{ value | escape }}</span>
      {{ label_unavailable }}
    {%- endcapture -%}
    {%
      render 'swatch-input',
      id: input_id,
      name: input_name,
      value: value | escape,
      swatch: value.swatch,
      product_form_id: product_form_id,
      checked: value.selected,
      visually_disabled: option_disabled,
      shape: block.settings.swatch_type,
      source: block.settings.swatch_source,
      option: option,
      product: product,
      help_text: help_text,
      additional_props: input_dataset
    %}
  {%- elsif picker_type == 'button' -%}
    <input
      type="radio"
      id="{{ input_id }}"
      name="{{ input_name | escape }}"
      value="{{ value | escape }}"
      form="{{ product_form_id }}"
      {% if value.selected %}
        checked
      {% endif %}
      class="button-input__input{% if option_disabled %} disabled{% endif %}"   
      {{ input_dataset }}
    >
    <label for="{{ input_id }}">
      {{ value -}}
      {{ label_unavailable }}
    </label>
  {%- elsif picker_type == 'dropdown' or picker_type == 'swatch_dropdown' -%}
    <option
      id="{{ input_id }}"
      value="{{ value | escape }}"
      {% if value.selected %}
        selected="selected"
      {% endif %}
      {% if swatch_value and picker_type == 'swatch_dropdown' %}
        data-option-swatch-value="{{ swatch_value }}"
        {% if swatch_focal_point %}
          data-option-swatch-focal-point="{{ swatch_focal_point }}"
        {% endif %}
      {% endif %}
      {{ input_dataset }}
    >
      {% if option_disabled -%}
        {{- 'products.product.value_unavailable' | t: option_value: value -}}
      {%- else -%}
        {{- value -}}
      {%- endif %}
    </option>
  {%- endif -%}
{%- endfor -%}

 

Here comes the original product-variant-picker.liquid

{% comment %}
  Renders product variant-picker

  Accepts:
  - product: {Object} product object.
  - block: {Object} passing the block information.
  - product_form_id: {String} Id of the product form to which the variant picker is associated.
  Usage:
  {% render 'product-variant-picker', product: product, block: block, product_form_id: product_form_id %}
{% endcomment %}
{%- unless product.has_only_default_variant -%}
  <variant-selects data-primary
    id="variant-selects-{{ section.id }}"
    data-section="{{ section.id }}"
    {{ block.shopify_attributes }}
  >
    {%- for option in product.options_with_values -%}
      {%- liquid
        assign picker_type = block.settings.picker_type
        
        if block.settings.swatch_type != 'none'
          assign native_swatch_eligible = false
          assign custom_swatch_eligible = false
          if block.settings.swatch_source == 'native'
            assign native_swatch_count = option.values | map: 'swatch' | compact | size
            if native_swatch_count > 0
              assign native_swatch_eligible = true
            endif
          else
            assign custom_swatch_trigger = 'products.product.color_swatch_trigger' | t | downcase
            assign downcased_option = option.name | downcase
            if custom_swatch_trigger contains downcased_option
              assign custom_swatch_eligible = true
            endif
          endif

          if native_swatch_eligible == true or custom_swatch_eligible == true
            if block.settings.picker_type == 'dropdown'
              assign picker_type = 'swatch_dropdown'
            else
              assign picker_type = 'swatch'
            endif
          endif
        endif

        assign is_size = false
        if block.settings.size_chart != blank
          assign size_trigger = 'products.product.size_chart_trigger' | t | downcase
          assign downcased_option = option.name | downcase
          if size_trigger contains downcased_option
            assign is_size = true
          endif
        endif
      -%}

      {%- capture sizechart_cta -%}
        {%- if is_size -%}
          <div class="form__popup" id="size-{{ section.id }}">
            <modal-opener class="no-js-hidden" data-modal="#PopupModal-{{ block.id }}" {{ block.shopify_attributes }}>
              <button id="ProductPopup-{{ block.id }}" class="link link-with-icon" type="button" aria-haspopup="dialog">
                {% render 'icon', icon: 'ruler' %}
                <span class="label">{{ 'products.product.size_chart' | t | default: block.settings.size_chart.title }}</span>
              </button>
            </modal-opener>
            <a href="{{ block.settings.size_chart.url }}" class="link link-with-icon no-js">
              {% render 'icon', icon: 'ruler' %}
              <span class="label">{{ 'products.product.size_chart' | t | default: block.settings.size_chart.title }}</span>
            </a>
          </div>
        {%- endif -%}
      {%- endcapture -%}

      {%- if picker_type == 'swatch' -%}
        <fieldset class="js product-form__input product-form__input--swatch">
          {%- if block.settings.show_variant_labels -%}
            <legend class="form__label">
              {{ option.name }}:
              <span data-selected-value>
                {{- option.selected_value -}}
              </span>
            </legend>
          {%- endif -%}
          {% render 'product-variant-options',
            product: product,
            option: option,
            block: block,
            picker_type: picker_type
          %}
          {{- sizechart_cta -}}
        </fieldset>
      {%- elsif picker_type == 'button' -%}
        <fieldset class="js product-form__input product-form__input--pill">
          {%- if block.settings.show_variant_labels -%}
          <legend class="form__label">{{ option.name }}</legend>
          {%- endif -%}
          {% render 'product-variant-options',
            product: product,
            option: option,
            block: block,
            picker_type: picker_type
          %}
          {{- sizechart_cta -}}
        </fieldset>
      {%- else -%}
        <div class="product-form__input product-form__input--dropdown">
          {%- if block.settings.show_variant_labels -%}
            <label class="form__label" for="Option-{{ section.id }}-{{ forloop.index0 }}">
              {{ option.name }}
            </label>
          {%- endif -%}
          <div class="select">
            {%- if picker_type == 'swatch_dropdown' -%}
              <span
                data-selected-value
                class="dropdown-swatch"
              >
                {% if block.settings.swatch_source == 'native' %}
                  {% render 'swatch', swatch: option.selected_value.swatch, shape: block.settings.swatch_type %}
                {% else %}
                  {% render 'swatch-custom', product: product, option: option, source: block.settings.swatch_source, shape: block.settings.swatch_type %}
                {% endif %}
              </span>
            {%- endif -%}
            <select
              id="Option-{{ section.id }}-{{ forloop.index0 }}"
              class="select__select"
              name="options[{{ option.name | escape }}]"
              form="{{ product_form_id }}"
            >
              {% render 'product-variant-options',
                product: product,
                option: option,
                block: block,
                picker_type: picker_type
              %}
            </select>
            <span class="svg-wrapper">
              {{- 'icon-caret.svg' | inline_asset_content -}}
            </span>
          </div>
          {{- sizechart_cta -}}
        </div>
      {%- endif -%}
    {%- endfor -%}

    <script type="application/json" data-selected-variant>
      {{ product.selected_or_first_available_variant | json }}
    </script>
  </variant-selects>
{%- endunless -%}

 

The_ScriptFlow
Explorer
109 5 11

Could you please share your Store URL and password so that I take a look and provide you solution code.

Thanks

- Need a Shopify Specialist? Chat on WhatsApp Or email at: Info@thescriptflow.com

- Boost Your Sales with Affiliate Marketing - UpPromote: Affiliate & Referral


- If my solution was helpful, mark it as a solution and hit the like button! And wait don't forget to Buy me a Coffee

entranced
Explorer
79 3 16

Hi ScriptFlow! The store is open for now and here is URLto example product with variants https://doftnoter.se/products/parfym-damer-jil-sander-jil-sander-edp-n%C2%BA-4?variant=5063743805883... 

entranced
Explorer
79 3 16

This is an accepted solution.

I approached it differently. Instead of disabling the variant buttons for items with low stock, I chose to hide them. That way, the add-to-cart functionality etc. wasn’t affected. So case closed.