Go through all available variants in Shopify liquid - shopify

I am trying to show all the available sizes from a product in the collection page.
I managed to write this snippet that will show available sizes, but only for one of the color combinations.
{% for option in product.options_with_values %}
{% assign downcased_option = option.name | downcase %}
{% if downcased_option contains 'size' %}
{% assign is_size = true %}
{% for value in option.values %}
{% assign variant_available = true %}
{% if product.options.size >= 1 %}
{% unless product.variants[forloop.index0].available %}
{% assign variant_available = false %}
{% endunless %}
{% endif %}
<span class="{% unless variant_available %}soldout{% endunless %}">{{ value | escape }}</span>
{% endfor %}
{% endif %}
{% endfor %}
But, let's say we have the next variants:
Green/32, Green/34
Blue/34
Black/34, Black/36
With the snippet above, it will not show available size 36 from black color as it's not available in green.
What I want is to go through every single size and show if availability, no matter the color.
Does someone know how to achieve this?
Thanks

Forgive me if I'm missing something but making the assumption that all variants have a size and there are only two options you just need to loop through the available variants and just display the variant name split it and display first or last where ever the size is in the options list. if there are loads of duplicates then put them in an array and run 'uniq'.
{% for variant in product.variants %}
{% if variant.available %}
{% assign sizesList = variant.title | split: '/' | first | append: ', ' }}
{% endif %}
{% endfor %}
{% assign sizes = sizesList | split: ', ' %}
{{ sizes | uniq | join: ", " }}

Related

How to fetch unique value in liquid file

here is my code i tried to fetch only unique value from items variable but I got all value can someone please help to solve this
{% capture items %}
{% for tag in product.tags %}
{%if tag contains 'pair'%}
{% assign tag_split = tag | remove_first: 'pair::' | split: "::" %}
{% assign color = tag_split[0] %}
{{color}}
{% endif %}
{% endfor %}
{% endcapture %}
{% assign my_array = items | split: ", " %}
<p>{{ my_array | uniq }} </p>
This filter should help you to keep only one elem per value:
https://shopify.github.io/liquid/filters/uniq/

Go through array elements in Liquid

I'm writing some liquid code for a shopify website in order to add products to any blog post based on tags that use product's handle. I've tried with one product and it works just fine so I was trying to iterate it through a loop but I couldn't get any information from the array I've created. This is the code I've written so far. Can you help me understand what I'm doing wrong? Thanks!
{% comment %}declare variables{% endcomment %}
{% assign related_prod_index = 0 %}
{% assign related_prod_array = "" | split: ',' %}
{% comment %}check for tags that contains products handles{% endcomment %}
{% for tag in article.tags %}
{% if tag contains "product_"%}
{% assign prod_handle = tag | split:"_" %}
{% assign blog_prod = all_products[prod_handle[1]] %}
{% assign related_prod_array = related_prod_array | push:blog_prod %}
{% assign related_prod_index = related_prod_index | plus:1 %}
{% endif %}
{% endfor%}
{% comment %}check how many product tags I found{% endcomment %}
<h1>{{ related_prod_index }} tags found</h1>
{% comment %}loop that create small preview for each product{% endcomment %}
{% if related_prod_array %}
{% for rel_pr in related_prod_array %}
<img src="{{ rel_pr.featured_image | img_url:'original' }}">
<p>{{rel_pr.title}}</p>
<p>{{rel_pr.price | money}}</p>
{% endfor %}
{% endif %}
This looks like it should be working, but if this post is true, then you can't add Product objects to an array.
The good news is you shouldn't need to. Put the display code in the same loop you use to search through the tags.
{% for tag in article.tags %}
{% if tag contains "product_"%}
{% assign prod_handle = tag | split:"_" %}
{% assign blog_prod = all_products[prod_handle[1]] %}
<img src="{{ blog_prod .featured_image | img_url:'original' }}">
<p>{{blog_prod .title}}</p>
<p>{{blog_prod .price | money}}</p>
{% endif %}
{% endfor %}

How to find out if a size is in stock using liquid on Shopify?

I'm trying to display the sizes of the products on the product card so that the customer won't have to click on the product to find out which sizes are in stock. If the size is in stock, the size will have different styling to the sizes without stock.
What I have at the moment:
{% assign sizes = '' %}
{% for variant in product.variants %}
{% assign sizes = sizes | append: variant.options[0] | append: '_' %}
{% endfor %}
{% assign sizesArr = sizes | split: '_' | uniq %}
{% for size in sizesArr %}
<span>{{ size }}</span>
{% endfor %}
This shows all the sizes of the product. The problem is the code doesn't distinguish between the sizes that have stock and those that don't, so I can't change the styling between the two.
Thanks in advance.
This cheat sheet will help you, shopify Cheat Sheet
There is variant.inventory_quantity will you need to use to determine the stock.
{% for variant in product.variants %}
{% assign sizes = sizes | append: variant.options[0] | append: '_' %}
{% endfor %}
you need to check if a product has variants or not. then proceed when there is a variant.
because there can be multiple product variants option.
{% for variant in product.variants %}
{% for option in variant.options %}
my stock is {{option.inventory_quantity}}
{% endfor %}
{% endfor %}

paginating variant collection in liquid

In my collection template I'm showing product variants if applicable and products if not. This works very well, safe for the fact that it seems impossible to paginate. I've tried creating a custom array of variants/products, but paginate wants nothing to do with it.
Here's the code I'm currently using which works for outputting variants/products in a grid:
{% for product in collection.products %}
{% if product.variants.size == 0 %}
{% include 'product-card-grid2', max_height: max_height %}
{% else %}
{% for variant in product.variants %}
{% include 'product-card-grid2', max_height: max_height %}
{% endfor %}
{% endif %}
{% endfor %}
How do you paginate something like this? Essentially I'd like something like the excellent pimoroni.com.
Liquid seems exceptionally rigid in terms of array construction/manipulation.
I guess the alternative would be to output the list as json and then manually handling it in JS, but it would be nice if that's avoidable.
One page may show 200 and another may show 50. I'd like to normalize that to 20 per page - also to avoid hitting shopify's hard cap on collections.
You can't achieve this only with liquid.
You can paginate the products but the variants will throw the logic of.
So there is not a lot of you can do.
One hacky ways is to overwrite the paginate limit to something crazy to show all the products and create a JS paginate instead of a liquid one.
Example:
{% paginate collection.products by 9999 %}
{% for product in collection.products %}
{% if product.variants.size == 0 %}
{% include 'product-card-grid2', max_height: max_height %}
{% else %}
{% for variant in product.variants %}
{% include 'product-card-grid2', max_height: max_height %}
{% endfor %}
{% endif %}
{% endfor %}
{% endpaginate %}
But if you have a lot of products the load time will be crazy slow for the back-end to process the request.
Another option is to create a GraphQL query with the Storefront API and populate the page via JS. Bu this may be an overkill for such a thing.
Another option is to use some kind of an App that will pull the variants and create the pagination for you. ( via JS once again )
Last option is to describe this to your client and that you don't have an easy/optimised way to handle variants pagination because of Shopify limitations.
Concat only works on arrays. Luckily there are ways to handle that. Array doesn't have the slice method (only strings) so we need to construct that too. Modulo takes care of under/overflow.
At last, success:
{% comment %}
------------------------------------------------------------------------------
Consolidating the product list for later use.
NOTE: It will probably cap over 50 products!!!!!!!!!!!!!!!!!!!!!!!!!!!
Needs to be rewritten at some point to use page number to load only the needed
products.
{% endcomment %}
{% assign productList = "" | split: "" %}
{% assign counter = 0 %}
{% assign variantLimit = 30 %}
{% for product in collection.products %}
{% assign productList = productList | concat: product.variants %}
{% assign counter = counter | plus: product.variants.size %}
{% endfor %}
{% assign maxSize = productList.size %}
{% assign start = current_page | minus: 1 | times: variantLimit %}
{% assign end = current_page | times: variantLimit | minus: 1 %}
{% if end > maxSize %}
{% assign end = productList.size | modulo: variantLimit %}
{% endif %}
{% assign slice = "" | split: "" %}
{% for i in (start..end) %}
{% assign temp = productList[i] | where: "available", true %}
{% assign slice = slice | concat: temp %}
{% endfor %}
{% assign productList = slice %}
And this as product loop
{% for variant in productList %}
{% include 'product-card-grid2', max_height: max_height %}
{% endfor %}
Also remember the next button
{% unless end > maxSize %}
Next Page
{% endunless %}

Shopify: calling swatch.liquid 'colors' on collection.liquid and product-loop.liquid

I have not been able to find a fix for my issue. I want to show a simple "More Colors" option beneath the product prices.
Screenshot of Product example
I have been testing code such as:
{% if product.variants 'color' > 1 %}
Has more than one variant.
{% else %}Only one variant.
{% endif %}
But haven't had any luck. Everything either calls "Has more..." or "Only one..." regarless of the swatch count.
I am editing product-loop.liquid which is being called from collections.liquid
It has only outputed "Only one variant" or "Has more than one variant" for every product regardless of swatch/color count.
Thanks for any help..
This statement is nonsense:
{% if product.variants 'color' > 1 %}
Instead, you want to check the options set for your variants, and if you detect an option set to color, and you have more than one variant, then clearly, you are in more than one color territory.
{% assign has_more_colors = false %}
{% for option in product.options %}
{% if option contains 'color' and product.variants.length > 1 %}
{% assign has_more_colors = true %}
{% endif %}
{% endfor %}
So now you can do whatever it is you need to do... since you now know you a) have an option called colors, and b) more than one variant, hence more than one color...
The following snippet was posted to the Shopify boards. It solved this issue:
{% assign option_title = "Color" %}
{% assign option_index = "" %}
{% assign option_values = "" %}
{% for option in product.options %}
{% if option == option_title %}
{% assign option_index = forloop.index %}
{% endif %}
{% endfor %}
{% for variant in product.variants %}
{% assign variant_option_value = "" %}
{% if option_index == 1 %}
{% assign variant_option_value = variant.option1 | handleize %}
{% elsif option_index == 2 %}
{% assign variant_option_value = variant.option2 | handleize %}
{% elsif option_index == 3 %}
{% assign variant_option_value = variant.option3 | handleize %}
{% endif %}
{% assign option_values = option_values | append:"," | append:variant_option_value %}
{% endfor %}
{% assign option_values = option_values | remove_first:"," | split:"," | uniq %}
{% if option_values.size > 1 %}
MORE COLORS
{% else %}
{% endif %}