Shopify themes, liquid, logos, and UX
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
Solved! Go to the solution
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!
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!
Learn how to expand your operations internationally with Shopify Academy’s learning path...
By Shopify Feb 4, 2025Hey Community, happy February! Looking back to January, we kicked off the year with 8....
By JasonH Feb 3, 2025Expand into selling wholesale with Shopify Academy’s learning path, B2B on Shopify: Lau...
By Shopify Jan 28, 2025