Problems sorting out of stock items to the end of a collection

Highlighted
New Member
4 0 0

So I'm trying to get out of stock items to appear at the end of my collections. I found this thread: https://ecommerce.shopify.com/c/shopify-discussion/t/how-do-i-sort-out-of-stock-products-to-the-end-... where I got the following code:

 

  <div class="row products">
    {% for product in collection.products limit: settings.pagination_limit %}
    {% if product.available %}
    {% include 'product-loop' with collection.handle %}
    {% endif %}
    {% endfor %}
    {% for product in collection.products limit: settings.pagination_limit %}
    {% unless product.available %}
    {% include 'product-loop' with collection.handle %}
    {% endunless %}
    {% endfor %}
  </div>

I put this code on my collection-template.liquid page, in place of this line:

{% include 'product-grid-item' %}

The code works, however, I am experiencing a very annoying issue.

When pagination occurs, there are still out of stock products on each page, but at the end of the page. I want the out of stock products to all be on the last page. 

By the way, I'm using the Simple theme. 

I've noticed that more than several people have had this issue, and it seems no one has been able to find a solution. Solving this would definitely be a great help to the Shopify community, as I'm certain this is something that will keep coming up in the future. 

0 Likes
Highlighted
New Member
4 0 0

Having done a bit of research, I can see a general path to a fix. I need to create two arrays, one consisting of all available products in collection.products, and a second array consisting of the unavailable products. Then, these arrays need to be concatenated. The resulting array would then provide the products in the correct order.

The problem is, it seems that creating such an array is absurdly convoluted and counter-intuitive. I (and the greater Shopify community) would seriously appreciate it if someone could help with this issue. 

0 Likes
Highlighted
Shopify Partner
15 0 10

Hi AlexVL,

I was able to get it working with some basic testing for the Supply and Simple themes:

In collection-template.liquid, I added this line:

{% assign sortedProducts = collection.products | sort: 'available' %}

Right above the line doing the pagination (Simple theme example here):

{% paginate collection.products by 12 %}

So it looks like this:

<!-- /templates/collection.liquid -->
{% assign sortedProducts = collection.products | sort: 'available' %}
{% paginate collection.products by 12 %}

<div data-section-id="{{ section.id }}" data-section-type="collection-template" data-sort-enabled="{{ section.settings.collection_sort_enable }}" data-tags-enabled="{{ section.settings.collection_tag_enable }}">
  <header class="grid">

Then we need to locate the line in the for loop for the pagination that include the product grid item (Simple theme example shown, note near the bottom for Supply theme):

{% include 'product-grid-item' %}

And change it to this:

{% include 'product-grid-item', product: sortedProducts[sortedProductsIndex] %}

And insert this line above the include line that we just changed:

{% assign sortedProductsIndex = paginate.current_offset | plus: forloop.index0 %}

So the end result of that looks like this:

  <div class="grid grid--uniform" role="list">

    {% for product in collection.products %}
      {% if collection.products.size == 1 %}
        {% assign grid_item_width = 'medium-up--one-third small--one-whole' %}
      {% else %}
        {% assign grid_item_width = 'medium-up--one-third small--one-half' %}
      {% endif %}
      {% assign sortedProductsIndex = paginate.current_offset | plus: forloop.index0 %}
      {% include 'product-grid-item', product: sortedProducts[sortedProductsIndex] %}
    {% else %}
      {% comment %}
        Add default products to help with onboarding for collections/all only.

---

For me that was sufficient to sort the out of stock items to the end of the entire product list, and it did seem to respect the theme's built in sorting (alphabetical, price, etc), although I only did some very basic testing on that.

Edit: Scratch that, after a little bit more testing, it seems like the out of stock items aren't always sorted amongst themselves at the end of the list (for example, the out of stock items don't appear in alphabetical order)

---

For other themes: 

I did notice that in the Supply theme, there was an extra argument in the product-grid-item include:

{% include 'product-grid-item' with grid_item_width %}

The syntax for injecting a new product from the sorted array then looked like this:

{% include 'product-grid-item' with grid_item_width, product: sortedProducts[sortedProductsIndex] %}

---

Let me know if that works for you

Joe

https://lcfermi.com | joe@lcfermi.com
0 Likes
Highlighted
Shopify Partner
15 0 10

After some more digging, I was able to come up with a method of generating a sorted array from 2 arrays so that the same sort filter works on both the available and unavailable products. It does use a slice filter on arrays though, this doesn't appear in Shopify's liquid documentation but does appear in the liquid source code on github: https://github.com/Shopify/liquid/blob/master/lib/liquid/standardfilters.rb so there is some additional risk of support for this changing

In order to maintain the correct sort parameter for the unavailable products, replace this line:

{% assign sortedProducts = collection.products | sort: 'available' %}

With this snippet of code:

{% assign unsortedProducts = collection.products | reverse | reverse %}
{% comment %}
Yes I know, reverse | reverse looks redundant, but there does seem to be some value in getting an array out of the reverse filter instead of trying to use collection.products directly (avoids an error where concat complains that is needs an array argument), and since we don't want to actually change the order here, we have to reverse it back.
{% endcomment %}

{% for product in unsortedProducts %}
	{% assign sliceIndex = forloop.index0 %}
	{% assign aProduct = unsortedProducts | slice: sliceIndex, 1 %}

	{% if product.available == true %}
		{% if availableProducts.size == 0 %}
			{% assign availableProducts = aProduct %}
		{% else %}
			{% assign availableProducts = availableProducts | concat:aProduct %}
		{% endif %}
	{% else %}
		{% if unavailableProducts.size == 0 %}
			{% assign unavailableProducts = aProduct %}
		{% else %}
			{% assign unavailableProducts = unavailableProducts | concat: aProduct %}
		{% endif %}
	{% endif %}
{% endfor %}

{% assign sortedProducts = availableProducts | concat:unavailableProducts %}

 

https://lcfermi.com | joe@lcfermi.com
Highlighted
New Member
4 0 0

Joe, I implemented this and it works great. Thank you so much for your help!

0 Likes
Highlighted
New Member
4 0 0

Actually, there is one issue. If there is a collection with no out of stock items, the product page shows this error: 

Liquid error (line 28): concat filter requires an array argument

All products on such a page show as out of stock, with broken images. 

I think the problem is with this line: {% assign sortedProducts = availableProducts | concat:unavailableProducts %} 

 

0 Likes
Highlighted
Shopify Partner
15 0 10

Aha! Good catch,

You are correct on the culprit line, try replacing that line:

{% assign sortedProducts = availableProducts | concat:unavailableProducts %}

With this snippet:

{% assign sortedProducts = collection.products %}
{% if unavailableProducts.size > 0 and availableProducts.size > 0 %}
	{% assign sortedProducts = availableProducts | concat:unavailableProducts %}
{% endif %}

 

https://lcfermi.com | joe@lcfermi.com
0 Likes
Highlighted
New Member
3 0 0

Hi Joe,

Your code really works but unfortunately it is not being applied if the products are more than 50. Is their any way in order to make it work fine? 

Thank you

0 Likes
Highlighted
Shopify Partner
15 0 10

Hi Sagar,

Unfortunately no, I haven't been able to find a way to make that work with a liquid solution. There is another discussion here where an app is proposed for the solution:

https://ecommerce.shopify.com/c/shopify-discussion/t/how-do-i-sort-out-of-stock-products-to-the-end-...

Joe

https://lcfermi.com | joe@lcfermi.com
0 Likes
Highlighted
Shopify Expert
10007 116 1818

If you have more than 50 products you'd need to use a combination of Liquid and JavaScript.

The page would load the first 50, then JavaScript would load the rest (via collection pagination). Once everything is loaded, the JavaScript can adjust the order of the products. 

★ Winning Partner of the Build a Business competition. ★ http://freakdesign.com.au
0 Likes