Solved

Converting options to variant in Liquid

Thisissoul
Visitor
2 1 0

Hello Shopify Community,

 

Context:

For our webshop we are attempting to beter visualize the availability of products, based on whether the variant linked to a certain option is in or out of stock. I've attempted to generalise the question to make any responses useful for other users as well.

We are using the Debut theme - but converting from product options to product variants within Liquid could be useful for use in other themes as well.

 

Problem:

The selection list for users on the product page is generated based on the available product options by iterating through:

 

product.options_with_values

 

We then displaying a radio-button for each of the values within the present options (code sample abbreviated):

 

{%- for value in option.values -%}
   <input type="radio">
{%- endfor -%}

 

When a user selects one of the buttons, JavaScript is used to convert the current option to the relevant variant through theme.js :

 

**
     * Find variant based on selected values.
     *
     *   {array} selectedValues - Values of variant inputs
     *  {object || undefined} found - Variant object from product.variants
     */
    _getVariantFromOptions: function() {
      var selectedValues = this._getCurrentOptions();
      var variants = this.product.variants;

      var found = _.find(variants, function(variant) {
        return selectedValues.every(function(values) {
          return _.isEqual(variant[values.index], values.value);
        });
      });

      return found;
    },

 

 

Question:

We are wondering if there is a possibility to convert from option to variant in Liquid, so you would be able to use something like:

 

{%- for value in option.values -%}
   {%- if option.variant.available == false %}
      <input type="radio" id="out_of_stock">
   {% elseif option.variant.available == true %}
      <input type="radio" id="in_stock">
   {% endif %}
{%- endfor -%}

 

As both

product.variants

 and

product.options_with_values

 are available to Liquid, it seems like this should be possible. If not, does anyone have any other suggestions to achieve the same result?

 

Kind regards,

Thisissoul

Accepted Solution (1)

Thisissoul
Visitor
2 1 0

This is an accepted solution.

After playing around we've made a solution which works but isn't the cleanest code:

 

 

         {% unless product.has_only_default_variant %}
              {% for option in product.options_with_values %}
                <label
                  {% if option.name == 'default' %}
                    class="label--hidden"
                  {% endif -%}
                  for="{{ section.id }}-{{ option.position }}-{{ forloop.index0 }}"
                >
                  {{ option.name }}
                </label>
                {% assign option_position = forloop.index %}
                <fieldset>
                  {%- for value in option.values -%}
                    {%- for variant in product.variants -%}
                      {%- if variant.option1 == value %}
                        {%- if variant.available == true %}
                          <input
                            type="radio"
                            class="single-option-selector-{{ section.id }} "
                            {% if option.selected_value == value %}
                              checked="checked"
                            {% endif %}
                            value="{{ value | escape }}"
                            data-index="option{{option_position}}"
                            name="{{ option.name | handleize }}"
                            id="{{ section.id }}-{{ option.position }}-{{ forloop.index0 }}"
                          >
                          <label for="{{ section.id }}-{{ option.position }}-{{ forloop.index0 }}">
                            {{ value }}
                          </label>
                        {% else %}
                          <input
                            type="radio"
                            class="single-option-selector-{{ section.id }}"
                            value="{{ value | escape }}"
                            sold-out="sold-out"
                            data-index="option{{option_position}}"
                            name="{{ option.name | handleize }}"
                            id="{{ section.id }}-{{ option.position }}-{{ forloop.index0 }}"
                          >
                          <label for="{{ section.id }}-{{ option.position }}-{{ forloop.index0 }}"  style="background-color: lightgrey; color: white;">
                            {{ value }}
                          </label>
                        {%- endif -%}
                      {%- endif -%}
                    {%- endfor -%}
                  {%- endfor -%}
                </fieldset>
              {% endfor %}
            {% else %}
              {% for option in product.options_with_values %}
                <label
                  {% if option.name == 'default' %}
                    class="label--hidden"
                  {% endif -%}
                  for="{{ section.id }}-{{ option.position }}-{{ forloop.index0 }}"
                >
                  {{ option.name }}
                </label>
                {% assign option_position = forloop.index %}
                <fieldset>
                  {%- for value in option.values -%}
                    <input
                      type="radio"
                      class="single-option-selector-{{ section.id }} "
                      {% if option.selected_value == value %}
                        checked="checked"
                      {% endif %}
                      value="{{ value | escape }}"
                      data-index="option{{option_position}}"
                      name="{{ option.name | handleize }}"
                      id="{{ section.id }}-{{ option.position }}-{{ forloop.index0 }}"
                    >
                    <label for="{{ section.id }}-{{ option.position }}-{{ forloop.index0 }}">
                      {{ value }}
                    </label>
                  {%- endfor -%}
                </fieldset>
              {% endfor %}
          {% endunless %}

 

 

However: This will only work for products with one option field - not with multiple options!

View solution in original post

Reply 1 (1)

Thisissoul
Visitor
2 1 0

This is an accepted solution.

After playing around we've made a solution which works but isn't the cleanest code:

 

 

         {% unless product.has_only_default_variant %}
              {% for option in product.options_with_values %}
                <label
                  {% if option.name == 'default' %}
                    class="label--hidden"
                  {% endif -%}
                  for="{{ section.id }}-{{ option.position }}-{{ forloop.index0 }}"
                >
                  {{ option.name }}
                </label>
                {% assign option_position = forloop.index %}
                <fieldset>
                  {%- for value in option.values -%}
                    {%- for variant in product.variants -%}
                      {%- if variant.option1 == value %}
                        {%- if variant.available == true %}
                          <input
                            type="radio"
                            class="single-option-selector-{{ section.id }} "
                            {% if option.selected_value == value %}
                              checked="checked"
                            {% endif %}
                            value="{{ value | escape }}"
                            data-index="option{{option_position}}"
                            name="{{ option.name | handleize }}"
                            id="{{ section.id }}-{{ option.position }}-{{ forloop.index0 }}"
                          >
                          <label for="{{ section.id }}-{{ option.position }}-{{ forloop.index0 }}">
                            {{ value }}
                          </label>
                        {% else %}
                          <input
                            type="radio"
                            class="single-option-selector-{{ section.id }}"
                            value="{{ value | escape }}"
                            sold-out="sold-out"
                            data-index="option{{option_position}}"
                            name="{{ option.name | handleize }}"
                            id="{{ section.id }}-{{ option.position }}-{{ forloop.index0 }}"
                          >
                          <label for="{{ section.id }}-{{ option.position }}-{{ forloop.index0 }}"  style="background-color: lightgrey; color: white;">
                            {{ value }}
                          </label>
                        {%- endif -%}
                      {%- endif -%}
                    {%- endfor -%}
                  {%- endfor -%}
                </fieldset>
              {% endfor %}
            {% else %}
              {% for option in product.options_with_values %}
                <label
                  {% if option.name == 'default' %}
                    class="label--hidden"
                  {% endif -%}
                  for="{{ section.id }}-{{ option.position }}-{{ forloop.index0 }}"
                >
                  {{ option.name }}
                </label>
                {% assign option_position = forloop.index %}
                <fieldset>
                  {%- for value in option.values -%}
                    <input
                      type="radio"
                      class="single-option-selector-{{ section.id }} "
                      {% if option.selected_value == value %}
                        checked="checked"
                      {% endif %}
                      value="{{ value | escape }}"
                      data-index="option{{option_position}}"
                      name="{{ option.name | handleize }}"
                      id="{{ section.id }}-{{ option.position }}-{{ forloop.index0 }}"
                    >
                    <label for="{{ section.id }}-{{ option.position }}-{{ forloop.index0 }}">
                      {{ value }}
                    </label>
                  {%- endfor -%}
                </fieldset>
              {% endfor %}
          {% endunless %}

 

 

However: This will only work for products with one option field - not with multiple options!