Shopify How to output a product that doesn't have a collection - shopify

I am trying to output all the products in a menu up to a certain number than output the collection types when that number is reached. So far that works fine, however I don't know how to output a product if the user does not put the product in a collection, I would like the products not entered into a collection to be in a template that I can link to in the menu that outputs the products not in a collection.
Here is my code so far.
{% for collection in collections %}
{% if shop.products_count <= 5 %}
{% for product in collections.[collection.title].products %}
{% capture productLink %}{{ product.url }}{% endcapture %}
{{product.title}}
{% endfor %}
{% elsif shop.products_count > 5 %}
{% capture collectionLink %}{{ collection.url }}{% endcapture %}
{{collection.title}}
{% else %}
You have no Products
{% endif %}
{% endfor %}

I would probably start by making a collection that contains all products in your shop (a smart collection where Product price > 0).
Then on the page where you want to display the products that are not in any collection (except the one we just created), try something like this:
{% for product in collections.all.products %}
{% if product.collections.size <= 1 %}
This product is not in any collections other than collections.all
{% endif %}
{% endfor %}

Related

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 Liquid - Related products as specific handles from a metafield

I am trying to use a Shopify metafield with a comma separated list of handles (ie: handle1,handle2) to call specific related products. These related products are displayed on individual product pages. My problem is: I cannot figure out how to get the products from the array to iterate and display.
I am using the Boundless theme, so I am trying to call/display the products in the same manner as a collection page. This may be part of my problem.
My current code calls the actual product on the page instead of the related products for some reason.
Here is my current code:
{% if product.metafields.c_f['Shown With'] %}
{% assign shownwith = product.metafields.c_f['Shown With'] | split: ',' %}
{% capture shownwith_items %}
{% for product in shownwith %}
{% include 'product-grid-width' with product_image_type: section.settings.product_image_type, product_image_size: section.settings.product_image_size %}
{% include 'product-grid-item' with product_image_spacing: section.settings.product_image_spacing, vendor_enable: section.settings.vendor_enable %}
{% endfor %}
{% endcapture %}
{% endif %}
{% if product.metafields.c_f['Shown With'] %}
{% assign shownwith = product.metafields.c_f['Shown With'] | split: ',' %}
{% capture shownwith_items %}
{% for relPro in shownwith %}
{% assign product = all_products[srelPro] %}
{% include 'product-grid-width' with product_image_type: section.settings.product_image_type, product_image_size: section.settings.product_image_size %}
{% include 'product-grid-item' with product_image_spacing: section.settings.product_image_spacing, vendor_enable: section.settings.vendor_enable %}
{% endfor %}
{% endcapture %}
{{ shownwith_items}}
{% endif %}

Get number of available products in a Shopify collection

I realise I can use collection.products_count to get products count for a collection, but is it possible to get the count of available products, e.g. not sold?
You'll need to iterate over the products and check their availability:
{% assign available_products = 0 %}
{% for product in collection.products %}
{% if product.available %}
{% assign available_products = available_products | plus: 1 %}
{% endif %}
{% endfor %}
{{ available_products }}

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 If in collection then display this

I am trying to write a simple if statement, but always struggle with shopify's system.
Essentially I want it to do this:
{% if collection.product == 'discontinued' %}
This Product is Discontinued.
{% endif %}
If it's in this collection, then display this text/html. Otherwise it wouldn't display anything. This would be in the product.liquid template.
Any ideas?
This is what ended up working:
{% for c in product.collections %}
{% if c.handle == "discontinued" %}
This product is Discontinued
{% endif %}
{% endfor %}
You can create an array of the collections for a product using map on product.collections. This which will create a new array with your specified property, i.e. the handles of each collection.
You can then check if this new array contains the handle you want to work with.
{% assign productCollections = product.collections | map: "handle" %}
{% if productCollections contains 'your-collection-handle' %}
{% comment %} DoSomething {% endcomment %}
{% endif %}
So for your example:
{% assign productCollections = product.collections | map: "handle" %}
{% if productCollections contains 'discontinued' %}
This product is Discontinued
{% endif %}
You can map other fields if your case is different, such as the title.
I guess this will help any one, I have used in the sidebar of shopify website.
The current collection page will get checked by this below code.
<div class="row-fluid not-animated" data-animate="fadeInUp">
<div class="title">By Collections</div>
<form class="coll">
{% assign col_tags = collection.title %}
{% for collection in collections %}
<input type="radio" value="{{ collection.url }}" name="collections" {% if col_tags contains collection.title %} checked {% endif %} >{{ collection.title | escape }} <br/>
{% endfor %}
</form>
If I understand how liquid collections work in Shopify, you will need to iterate over all of your products.
You'd need to do something similar to this if you are working with collections directly:
{% for product in collection.product %}
{% if product.tags contains 'discontinued' %}
This product has been discontinued :(
{% endif %}
{% endfor %}
If you are just working with a single product you can probably just use the inner if liquid tag part.
References:
Collection.liquid
Product.liquid
You can indeed add discontinued products to a collection called discontinued.
When rendering a product, you could do as csaunders suggests, simply loop through all the products in the discontinued collection, and check if the id of the current product matches any of the products in that collection. If so, do what you must do. No need to use tags.