SHOPIFY: How can I check if ANY variant is out of stock - shopify

I sell t-shirts with multiple variants.
I would like to check if ANY of those variants is "Out of Stock". Then if ANY of the variants is "Out of Stock" display a message. (the same message, not matter what variant is out of stock)
I know this works to check stock of the FIRST variant:
{% if product.variants.first.inventory_quantity <= 0 %}
<p style="color:#ff0000">This item is currently out of stock.
Order today, and your item will be shipped in 4-6 weeks.</p>
{% case product.variants.first.inventory_quantity %}
{% when '0' %}
{% else %}
{% endcase %}
{% endif %}
But this only checks the first variant. Any help here would be greatly appreciated. I am open to handling this in javascript or liquid, but am fairly new to both.

Here is one surefire way... and you can twist this into whatever pretzels you desire.
{% for variant in product.variants %}
{% if variant.inventory_quantity == 0 %}
<h1>Damn Dawg, this variant be out of stock</h1>
{% else %}
... whatever....
{% endif %}
{% endfor %}
It sounds like if you only want this message printed once, then it applies to the product and not the variants themselves. In this case, just set a variable to true if anything is out of stock and you can thus print your message just once. The limit:2 suggestion is nonsensical.
eg:
{% assign out_of_stock = false %}
{% for variant in product.variants %}
{% if variant.inventory_quantity == 0 %}
{% assign out_of_stock = true %}
{% endif %}
{% endfor %}
{% if out_of_stock == true %}
<h1>Damn Dog, we're out of beers</h1>
{% endif %}

In 2021 there is an HasOutOfStockVariants attribute for GraphQL.

Related

How can I show Shopify variants depending on option value

How could you display only certain variants on the product and collection pages in Shopify depending on the value of an option?
Assuming the option name is 'Box Options' and the values would either be 'Trade' or 'Retail' I would expect something similar to this code to return the price for the Trade variant:
{%- assign get_variant = product.options_with_values -%}
{% assign trade_variant = get_variant | where: "Trade" %}
<p>{{ trade_variant.price }}</p>
For context I'm trying to get trade prices to be used where the customer tag is "Trade" using this if statement in the liquid file:
{% if customer.tags contains 'Trade' %}
Feel like this should be really easy but for the life of me I cannot get this to work.
If your variants contain only one option, then something like that should work (not tested):
{% if customer.tags contains 'Trade' %}
{% assign p_variants = product.variants | where:'title','Trade' %}
{% for variant in p_variants %}
{{ variant.title }}
{% endfor %}
{% endif %}
Then, second case, your variants go with multiple options, then it is a little bit more complex (not tested either):
{% if customer.tags contains 'Trade' %}
{% for variant in product.variants %}
{% if variant.options contains 'Box Options' and variant.title contains 'Trade' %}
{{ variant.title }}
{% endif %}
{% endfor %}
{% endif %}

Checking if no compare_price exists in Shopify Liquid

I want to check if there's no compare price, and I cannot get any of the following to work in Shopify:
{% if price > compare_at_price %}
{% if compare_at_price == 0 %}
{% if compare_at_price == "" %}
I want to output some HTML when the compare_price doesn't exist.
You are missing the object here to get its attributes:
{% if product.price > product.compare_at_price %}
Do something
{% endif %}
To check if there is one:
{% if product.compare_at_price %}
Do sthg
{% endif %}
To check if there isn't one:
{% unless product.compare_at_price %}
Do sthg
{% endunless %}
Documentation:
https://shopify.dev/docs/themes/liquid/reference/objects/product

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 %}

How to hide products in Shopify search results based on a vendor name

I'm in a situation where hiding a certain vendors products in the control panel isn't an options due to an outside POS. For a test in search.liquid, I used search.terms like below. This code works but not everyone will type thevendor exactly the same way and will see the products if they don't type thevendor.
{% for item in search.results %}
{% if search.terms == 'thevendor' %}
{% else %}
{% include 'search-result' %}
{% endif %}
{% endfor %}
I tried to figure out how to write the code to hide these products in a better way. I tried product.vendor like below but when I search for those products individually they are not hidden. The code:
{% for item in search.results %}
{% if product.vendor == 'thevendor' %}
{% else %}
{% include 'search-result' %}
{% endif %}
{% endfor %}
Can someone tell me what I'm missing here? It seems it doesn't know what product.vendor is but when I print out who the vendor is, it displays the vendor. I don't understand why it's not hiding the products that are associated with this vendor.
{% for item in search.results %}
{% if item.product.vendor == 'thevendor' %}
{% else %}
{% include 'search-result' %}
{% endif %}
{% endfor %}
This should work.

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 %}