Vendor list page - Only list vendors with items in stock - shopify

I have a page on my site that lists all the vendors in my shop like so:
<div class="vendor-list" id="designers-a-to-z">
<ul>
{% assign current = "" %}
{% capture alphabet %}
-A-B-C-D-E-F-G-H-I-J-K-L-M-N-O-P-Q-R-S-T-U-V-W-X-Y-Z
{% endcapture %}
{% assign letters = alphabet | split: '-' %}
{% assign its_a_letter = false %}
{% for vendor in shop.vendors %}
{% assign vendor_first_letter = vendor | strip | upcase | slice : 0 %}
{% for letter in letters %}
{% if vendor_first_letter == letter %}
{% assign its_a_letter = true %}
{% break %}
{% endif %}
{% endfor %}
{% if its_a_letter %}
{% unless vendor_first_letter == current %}
<h3><span class="anchor" id="designers-{{ vendor_first_letter }}"></span>{{ vendor_first_letter }}</h3>
{% endunless %}
<li class="vendor-list-item">
{{ vendor }}
</li>
{% else %}
{% assign vendor_first_letter = "#" %}
{% unless vendor_first_letter == current %}
<h3><span class="anchor" id="designers-{{ vendor_first_letter }}"></span>{{ vendor_first_letter }}</h3>
{% endunless %}
<li class="vendor-list-item">
{{ vendor }}
</li>
{% endif %}
{% assign current = vendor_first_letter %}
{% endfor %}
</ul>
</div>
Some of these vendors don't currently have any items in stock so it's pointless to have them show up here. Is it possible to display only the vendors that have items in stock within their collection?
I currently have 2 collection tags in my store for 'in-stock' and 'sold-out' to help filter them with our filter menu and that is appended to the url so we only show customers in stock items.

Since a product has a vendor, and a product has inventory, you could just check that way. It would be insanely slow and obnoxious but hey! That is what a hosted platform is for, to turn crazy Liquid into the right tight HTML.
Note the Liquid for product.available
Returns true if a product is available for purchase. Returns false if all of the products variants' inventory_quantity values are zero or less, and their inventory_policy is not set to "Allow users to purchase this item, even if it is no longer in stock."
So while you loop through your vendor list, loop through all the products, checking the product vendor for a match, and the availability. If they don't suit you... skip the vendor.
Would be interesting to see how slow this is... but you never know till you try...
Another approach, perhaps smarter, is to iterate all your in-stock products once. Build your vendor list out of that, instead of shop.vendors.

I was able to get this working by writing it like this:
{% for vendor in shop.vendors %}
{% for collection in collections %}
{% if collection.title == vendor %}
{% if collection.all_tags contains 'in-stock' %}
then the conditions for checking the first letter and displaying the vendor, etc. nothing new
It only worked, however, on my dev site that I was testing it on and when I pushed it to production I got liquid error: memory limits exceeded. My dev site is definitely lacking in collections and products compared to my live site so this may work for people who have smaller sites.

Related

How to display different variant prices to different customers? (Shopify/Liquid)

I'm currently working on the shopify site for the B2B company where i work.
(Yeah, we know that Shopify Plus is the best option for B2Bs, but we can't afford the price)
We work on two different customer lists and really need two different prices to show to customers on the main-product page.
I managed the lists with customer tags, and also the two different prices with Variants.
Now i was trying to figure out how to show the Price of the Variant 1 to customers with the "list1" tag and the Price of the Variant 2 to customers with the "list2" tag.
(Yeah, we know that there are Wholesale Pricing app to do this, but we can't afford the monthly cost either).
I tried something like this, but i'm stuck...
Could you please help me out?
This is my last try:
{% if customer.tags contains "list1" %}
{% assign current = product.selected_or_first_available_variant %}
{%- assign target_variant = product.variants[0] -%}
<div class="no-js-hidden" id="variantPrice-{{ section.id }}" role="status" {{ block.shopify_attributes }}>
{%- render 'price', product: product, use_variant: true, show_badges: true, price_class: 'price--large' -%} </div>
{% else %}
{% assign current = product.selected_or_first_available_variant %}
{%- assign target_variant = product.variants[1] -%}
<div class="no-js-hidden" id="variantPrice-{{ section.id }}" role="status" {{ block.shopify_attributes }}>
{%- render 'price', product: product, use_variant: true, show_badges: true, price_class: 'price--large' -%} </div>
{% endif %}
I somehow managed to solve this. After being stuck on it for two days :P
It works with something like this:
{%- when 'price' -%}
{% if customer %}//Hide the price if not registered - endif is at the end//
{% if customer.tags contains "list1" %}
{%- assign target_variant = product.variants[0] -%}
<div class="no-js-hidden" id="price-{{ section.id }}" role="status"
{{block.shopify_attributes }}>
{%- render 'price', product: product, use_variant: true, show_badges: true,
price_class: 'price--large' -%} </div> //It shows the price of the First Variant//
{% else %}
{%- assign target_variant = product.variants[1] -%}//I can't figure out if this is relevant for the code, but it works like this, so...//
<div id="variantPrice" role="status" {{ block.shopify_attributes }}>{%- render 'price' -%} </div> //It shows the price of the Second Variant //
{% endif %}
I don't know if this is the correct way, but it works, so it's fine :P
Hope it will help someone with the same issue.
The interesting thing about your approach here is that a customer from List type 1 would be seeing the price for the variant as List type 1 price, but there is zero stopping them from simply placing the variant with the different price from List type 2 in the cart if they wanted.
In other words, you are decorating the price displayed, which is your goal I guess, but there is no actual logic in place to ensure customers pay the correct amount. For that, you would need a different logic, one that tries hard to ensure a customer from List type 1 only gets to checkout with product variants that are assigned to List type 1. Without that logic, you're wide open to a bit of price abuse.
The approach may be very straight to the point:
{% if customer %}
{% for variant in product.variants %}
{% assign current = forloop.index | plus: 1 | prepend:'list' %}
{% if customer.tags contains current %}
{{ variant.price}}
{% assign found = true %}
{% endif %}
{% endfor %}
{% unless found %}
Display what you want to if no price has been found for logged in user
{% endunless %}
{% else %}
What you want to display when customer is not connected to an account.
{% endif %}
You may use the same logic for your add to cart form.

Display product loop based on tag only in Shopify

I'm trying to display a product loop in a Collection template on Shopify. I want to pull all products with a specific tag 'Hydrate' to display within the Collection.
The template file is collection.custom.liquid and so far I have the below:
{% for product in collection.products %}
{% if product.tags contains "Hydrate" %}
Do Something
{% endif %}
{% endfor %}
But it doesn't display anything. I have confirmed I do have the tags setup correctly and I'm even using the exact same case sensitivity in case thats a thing.
If someone could point me in the right direction to display products from the tag 'Hydrate' in a custom collection template that would be great! Thanks so much
EDIT
I've now altered the code and moved it outside any pagination, and added for each product to the below. It now displays however it keeps displaying the same tags 5 times over on the page. Is there an issue with my syntax? Any ideas?
{% for product in collection.products %}
{% for product in products %}
{% if product.tags contains "Hydrate" %}
<p>{{ product.title }}</p>
{% endif %}
{% endfor %}
{% endfor %}
EDIT 2
In case anyone else has this same issue in future, the below code is what has ended up working and displays the correct tags, the correct amount of times:
{% assign products = collection.products %}
{% for product in products %}
{% if product.tags contains "Hydrate" %}
<p>{{ product.title }}</p>
{% endif %}
{% endfor %}
Your code is correct, so it might be a pagination issue. For example, there are no product with this tag in the first page but there are in the second one.

Show all products except items in the cart - Shopify

My aim is to show all products except the items in my cart essentially related items. I've tried several things but I just keep hitting a dead end.
So far:
This lists the product ids of each item in my cart:
{% assign all_product_ids = cart.items | map: 'product_id'| uniq %}
<pre>Product ids: {{ all_product_ids }}</pre>
This was my ureka moment however it's hardcoded, there must be a way to make it dynamic
{% for item in cart.items %}
{% if item.product.id == 1323872092227 %}
<div><h1>Nice sunglasses</h1></div><br>
{% endif %}
{% endfor %}
Still trying to get this to work
{% assign cart_item_ids = cart.items | map: 'product_id' %} // get array of cart item ids
{% for product in collections['all'].products%}
{% if cart_item_ids contains product.product_id %} // check if current product in loop's id is not in the array of cart_item_ids
<pre>Hi I'm in your cart</pre>
{% else %}
<pre>Hi I'm not in your cart</pre>
{% endif%}
{% endfor %}
Could someone point me in the right direction?
Thank you kindly

how to limit the numbers of product to show

I'm new to shopify. I'm trying to limit the output of the product for example 4 product for each tag. but seems like there is variables for me to loop..
anyone can help? thx.
{% for tag in collection.all_tags %}
{% if current_tags contains tag %}
<li class="active">{{ tag | link_to_remove_tag: tag }}</li>
{% else %}
<li>{{ tag | link_to_add_tag: tag }}</li>
{{ tag }}
{% if collection.products.size > 0 %}
<ul class="product-grid just">
{% for product in collection.products %}
{% if product.tags contains tag %}
<li>{% include 'product-grid-item' %}</li>
{% endif %}
{% endfor %}
</ul>
{% else %}
<p><strong><br/>No products found in this collection.</strong></p>
{% endif %}
{% endif %}
{% endfor %}
The limit parameter can be used to display the first 4 products in a collection:
{% for product in collection.products limit:4 %}
However if you need to display a limited number of products with a given tag, you will need to implement your own counter. See this discussion on the Shopify forums for an example of how to do this.
E.g.
{% for tag in collection.all_tags %}
{{ tag }}
{% assign counter = 0 %}
{% for product in collection.products %}
{% if product.tags contains tag and counter < 4 %}
<li>{% include 'product-grid-item' %}</li>
{% assign counter = counter | plus: 1 %}
{% endif %}
{% endfor %}
{% endfor %}
For a good separation the logic how many items are to be displayed is better put somewhere the "List" is made ready for output.
This way you don't have to do content related maths in the view, which is never a good idea since it doesn't put code where it belong and other people wanting to change something may have difficulties to find it. That being said you can either put the limitations on the collection.products object based on a configured backend parameter just before handing the object to the rendering or you go further back and intervene at the "grab products from database" point and limit/alter the result. ;)
There sure is a possibility to use an incrementing counter and stop at 4 in the template but I can hardly recommend to use that since it's not where the logic should be. The template should show, not think what to show, otherwise it's hardly reusable.

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.