Problem:
We want all out of stock items to show, but we want them at the bottom of every list for collection, search, tag and front end output. There is no default {{ collection.sort_by == “stock” }} option available within Shopify
Solution:
I wrote the code below.
I was extremely dissatisfied with all of the apps/plugins that “claim” to do this.
CODE SAMPLES:
In order to pull this off several sections of the template needed to be modified. For purposes of simplicity I will demonstrate with only the STATIC COLLECTION LIQUID template as it is most likely to commonly occur in most themes.
TEMPLATE: /sections/static-collection.liquid
Default code expected to be something like this: The standard “render my collection”
{% for product in collection.products %}
{% render 'product-grid-item', product: product %}
{% endfor %}
IDEAL ‘NON EXISTENT’ CUSTOMIZATION THEORY:
Lets say we simply want our “out of stock” items to be at the bottom of the list.
We could try to accomplish this by SORTING the array as follows, but it does not work!
[correct me if I am wrong about this]
{% assign products = collection.products | sort: '*inventory_quantity*' %}
{% for product in products %}
{% render 'product-grid-item', product: product %}
{% endfor %}
This is because inventory is stored here and its not a choice for | sort:
*see: https://shopify.dev/api/liquid/filters#sort
{{ product.selected_or_first_available_variant.inventory_quantity }}
WORKING CUSTOMIZATION EXAMPLE:
Here is then a working example
the idea being to CAPTURE the low stock items and push them to the bottom of a list
<em> {% for product in collection.products %}
{% assign quantity = product.selected_or_first_available_variant.inventory_quantity %}
{% if quantity > 0 %}
{% capture captured_temp %}
{% render 'product-grid-item', product: product %}
{% endcapture %}
{% assign capture_over_one = capture_over_one | append: captured_temp %}
{% endif %}
{% if quantity == 0 %}
{% capture captured_temp %}
{% render 'product-grid-item', product: product %}
{% endcapture %}
{% assign capture_nostock = capture_nostock | append: captured_temp %}
{% endif %}
{% endfor %}
{{ capture_over_one }}
{{ capture_nostock }}</em>
In this case we have simply captured anything with 1+ stock into the natural order, and then captured the out of stock items, and at the end we just dump out the capture.
BUT WAIT THERE IS MORE!
Here is then a working example with more elaborate needs
Consider how we may want to see if the customer has CONTROLLED the sort
And if the customer wants to sort by Price, Title, or some filter, we needs to get creative
Lets also assume we want to push any inventory that’s 1 (just 1 left), or “low stock” to the top to try to sell it out, we can do all this and more with the following methodology and creative thinking
{% assign sort_active = false %}
{% if collection.sort_by != blank %} {% assign sort_active = true %} {% endif %}
{% if collection.sort_by == "manual" %} {% assign sort_active = false %} {% endif %}
{% assign capture_default = "" %}
{% assign capture_over_ten = "" %}
{% assign capture_over_two = "" %}
{% assign capture_only_one = "" %}
{% assign capture_nostock = "" %}
{% assign captured_temp = "" %}
{% for product in collection.products %}
{% capture captured_customer_sort %}
{% render 'product-grid-item', product: product %}
{% endcapture %}
{% assign capture_default = capture_default | append: captured_customer_sort %}
{% assign quantity = product.selected_or_first_available_variant.inventory_quantity %}
{% if quantity > 9 %}
{% capture captured_temp %}
{% render 'product-grid-item', product: product %}
{% endcapture %}
{% assign capture_over_ten = capture_over_ten | append: captured_temp %}
{% endif %}
{% if quantity > 1 and quantity < 10 %}
{% capture captured_temp %}
{% render 'product-grid-item', product: product %}
{% endcapture %}
{% assign capture_over_two = capture_over_two | append: captured_temp %}
{% endif %}
{% if quantity == 1 %}
{% capture captured_temp %}
{% render 'product-grid-item', product: product %}
{% endcapture %}
{% assign capture_only_one = capture_only_one | append: captured_temp %}
{% endif %}
{% if quantity < 1 %}
{% capture captured_temp %}
{% render 'product-grid-item', product: product %}
{% endcapture %}
{% assign capture_nostock = capture_nostock | append: captured_temp %}
{% endif %}
{% endfor %}
{% if sort_active == true %}
{{ capture_default }}
{% else %}
{{ capture_only_one }}
{{ capture_over_two }}
{{ capture_over_ten }}
{{ capture_nostock }}
{% endif %}
Key notes here:
- First, lets detect if collection.sort_by has been set, if so, then do not push down low stock items, the customer may want to know this immediately with their “sort by price” choice
- Then, lets loop over the products and capture them into some brackets, in this case I want products that have only 1 left at the top, followed by 2-9 in stock, followed by 10+
- The idea being I want to SELL OUT the low stock first…
- From here, one can customize and control their brackets as needed
Closing thoughts:
This is but only the static-collection.liquid page, I needed to then customize several other modules and get rather creative with this tactic to achieve very unique and subjective results that would not apply to most peoples stores. I therefore understand why this feature has not really been addressed in the Shopify core…
However;
- the ability to simply use the api/liquid/filters#sort by INVENTORY should indeed be an option for us in code
- and a selection should be available within collections via the drop menu to create collections ordered by inventor as follows in the feature request below
Feature Request 1:
I hope to attract enough attention to this issue that we can get Shopify to add a SORT BY STOCK/INVENTORY feature where as there are 3 sort options:
- NATURAL (inventory does not change order)
- STOCK_ASCENDING (highest stock first with out of stock items are pushed to the bottom of any list)
- PROMOTE_LOW_STOCK (low stock items are pushed to the top of any list, out of stock 0 inventory at end)
- STOCK_DESCENDING (out of stock items are pushed to the top of any list)
- I see no reason to really have an option that pushes out of stock items to the top… but to be thorough may as well do it, its just the reverse of {{ inventory_quantity }}
- This however becomes critically important on the admin panel, hence it should exist.
The idea being: “I want to see a list of all out of stock items”
Feature Request 2:
Upgrade the product collection array to allow something much like this:
{% assign products = collection.products | sort: 'inventory_quantity' %}
{% assign products = collection.products | sort: 'NATURAL' %}
{% assign products = collection.products | sort: 'STOCK_ASCENDING' %}
{% assign products = collection.products | sort: 'PROMOTE_LOW_STOCK' %}
{% assign products = collection.products | sort: 'STOCK_DESCENDING' %}
https://shopify.dev/api/liquid/filters#sort
Feature Request 3:
Add these SORT OPTIONS into the admin panel so we can SORT our products by INVENTORY as well, this is a common task we need to accomplish under ADMIN->PRODUCTS within the FILTERS
#end
QED:
I have thus demonstrated the usefulness of having STOCK SORTING filters and options for both the front end and back end. I have also demonstrated an overly elaborate method to do this, one that may be necessary for all the the extremely subjective usage cases out there that need custom code, but the core SORT BY STOCK option should still exist for us within the Shopify Core and Liquid Filters.

