How To Sort Out Of Stock Products To The Bottom Of A Collection without using any apps?

Topic summary

A Shopify store owner seeks a custom code solution to automatically push out-of-stock products to the bottom of collection pages without using apps.

Initial Attempts:

  • Early suggestions involved using Liquid’s sort: 'available' filter in collection template files, but this approach failed to work for the original poster.
  • One respondent recommended the Merchbees app instead of custom code, though this contradicts the no-app requirement.

Working Solutions Identified:

Two-loop method: Split the product display into two separate loops—first displaying available products using {%- unless product.available -%} {%- continue -%} {%- endunless -%}, then unavailable products. This approach works but requires modifying the main-collection-product-grid.liquid file.

Filter and concatenate method: Use where filters to separate available and unavailable products, then combine them with concat. Example code:

{% assign in_stock = collection.products | where: 'available' %}
{% assign out_of_stock = collection.products | where: 'available', false %}
{% assign all_sorted = in_stock | concat: out_of_stock %}

Key Limitation:
Shopify’s pagination only provides 50 products at a time, meaning sorting only applies to the current page. To sort the entire collection, users must set pagination to a very large number (e.g., 1000) to display all products on one page, or implement infinite scrolling as an alternative.

Summarized with AI on October 31. AI used: claude-sonnet-4-5-20250929.

I want to put all out of stock products in the bottom of each collection without using any apps. It is better to have the custom code to fix this problem.

My website :https://healthexpress-mart.com/

Hello, @hem1

Reordering products in collections in Shopify without using apps does require some custom code. Here’s a step-by-step guide on how to achieve this:

  1. Backup Your Theme: Before making any changes, it’s crucial to backup your theme to ensure you can easily revert if something goes wrong.

  2. Access Your Theme Code: Go to your Shopify admin, navigate to “Online Store” > “Themes,” and click on “Actions” > “Edit code” for the theme you want to modify.

  3. Locate the collection.liquid File: In the “Sections” or “Templates” folder (depending on your theme), look for the collection.liquid or collection-template.liquid file. This is the file responsible for displaying products within collections.

  4. Mo

    {% assign sorted_products = collection.products | sort: 'available' %}
    
    <ul>
      {% for product in sorted_products %}
        <li>
          {{ product.title }}
          <!-- Add more product details here -->
        </li>
      {% endfor %}
    </ul>
    

    dify the Liquid Code: In this file, you’ll need to modify the code to reorder products so that out-of-stock products appear at the bottom of the collection. Here’s a basic example of how you can do this:

In this example, we use the sort filter to sort the products by availability, with out-of-stock products appearing at the bottom. You may need to adjust the code to fit your specific needs and the structure of your collection template.

  1. Save Changes: After making the necessary modifications, save your changes.

  2. Test Your Store: It’s important to thoroughly test your store to ensure that the products are now ordered correctly within collections. Check both in-stock and out-of-stock products to verify that they appear in the desired order.

  3. Publish Your Changes: Once you’re satisfied with the changes and have confirmed that they work as expected, click “Save” and then “Publish” to make the changes live on your store.

Please note that this is a basic example of how you can reorder products in a collection. Depending on your theme and specific requirements, the code may need to be adjusted. Additionally, custom code modifications can be sensitive, so it’s a good practice to document your changes and keep your theme backups up to date in case you need to revert any changes.

1 Like

Hi, Thank you for your reply. After I copied the code to the “collection-list.liquid”, there is nothing happened, the out of stock products are still in the top…

Hi @hem1 ,

I understand you are looking for a solution to push out-of-stock products to the bottom of collections in Shopify, without needing an app. Since the previous code sample provided using theme templates and filters did not provide an immediate solution for your needs. I would like to suggest another solution.

Instead of a custom code approach, I recommend using the Merchbees Push Down & Hide Out of Stock app. Here is how it works:

  • When a product goes out of stock, the app automatically moves it to the bottom of the collection.
  • When an out-of-stock product gets replenished with inventory, the app will reposition it back to its original location based on the collection’s chosen sorting type (manual, best-selling, title, etc).
  • This all happens seamlessly in the background without needing to modify any theme files.
  • The app also provides configuration options to fully hide out-of-stock products, push sold-out variants to the bottom, and control where unavailable products appear.

In summary, the Merchbees Push Down & Hide Out of Stock app provides an automated solution to reorder products based on availability, without requiring custom code changes. I recommend this app to deliver the dynamic reordering functionality you need. Please let me know if you have any other questions!

Best Regards,
Kenny

You’ll have to use the where filter twice and then concat the two arrays together. I also wrote a small blog post about it:

https://andreasvirkus.me/thoughts/sort-shopify-products-by-availability/

3 Likes

I have tried that in my theme and not working already tried in multiple places

{%- liquid
assign per_page = section.settings.rows | times: section.settings.columns
assign paginated = false
if section.settings.display_type == ‘all’
assign paginated = true
endif
-%}

{%- capture image_sizes -%}
(min-width: 720px) calc(calc(100vw - calc(2 * clamp(18px, 3.3vw, 3.3vw))) / {{ section.settings.columns }}),
calc(calc(100vw - calc(2 * clamp(18px, 3.3vw, 3.3vw))) / {{ section.settings.mobile_columns }})
{%- endcapture -%}

{% paginate collections by per_page %}

{{ page_title }}

{%- if section.settings.display_type == 'all' -%} {%- for collection in collections -%} {%- assign available_products = collection.products | where: 'available', true -%} {%- assign out_of_stock_products = collection.products | where: 'available', false -%} {%- assign sorted_products = available_products | concat: out_of_stock_products -%}

{%- for product in sorted_products -%}
{%
render ‘collection-item’ with
collection: product,
aspect_ratio: section.settings.collection_listing_aspect_ratio,
label_style: section.settings.label_style,
overlay_text_color: section.settings.overlay_text_color,
overlay_title_background: section.settings.overlay_title_background,
overlay_title_background_style: section.settings.overlay_title_background_style,
image_sizes: image_sizes
%}
{%- endfor -%}
{%- endfor -%}
{%- else -%}
{%- for collection_item in section.settings.collection_list -%}
{%
render ‘collection-item’ with
collection: collection_item,
aspect_ratio: section.settings.collection_listing_aspect_ratio,
label_style: section.settings.label_style,
overlay_text_color: section.settings.overlay_text_color,
overlay_title_background: section.settings.overlay_title_background,
overlay_title_background_style: section.settings.overlay_title_background_style,
image_sizes: image_sizes
%}
{%- endfor -%}
{%- endif -%}

{% if paginated %}

{% if paginate.pages > 1 %} {% render 'pagination' with paginate: paginate, type: 'general.pagination.collections', show_item_count: true %} {% else %} {% render 'pagination' with paginate: paginate, type: 'general.pagination.collections', display_paginate_item_count_only: true %} {% endif %}
{% endif %}
{% endpaginate %}

Can someone clarify for me exactly where to insert this bit of code on collection-liquid section?

Thanks.

You can split up the products loop in two. First run all avaliable products then all that are not.

Open main-collection-product-grid.liquid and find the <ul id="product-grid>… Then copy the for loop and paste the new one after the first one. The first forloop should only run through available products. Like so:

{%- unless product.available -%} {%- continue -%} {%- endunless -%}

The next one only the NOT available products. Like so:

{%- if product.available -%} {%- continue -%} {%- endif -%}

All put together it could look something like this:


              {%- for product in collection.products -%}
                {%- unless product.available -%} {%- continue -%} {%- endunless -%}
                {% assign lazy_load = false %}
                {%- if forloop.index > 2 -%}
                  {%- assign lazy_load = true -%}
                {%- endif -%}

                - {% render 'card-product',
                      card_product: product,
                      media_aspect_ratio: section.settings.image_ratio,
                      image_shape: section.settings.image_shape,
                      show_secondary_image: section.settings.show_secondary_image,
                      show_vendor: section.settings.show_vendor,
                      show_rating: section.settings.show_rating,
                      lazy_load: lazy_load,
                      show_quick_add: section.settings.enable_quick_add,
                      section_id: section.id
                    %}
                

              {%- endfor -%}

              {%- for product in collection.products -%}
                {%- if product.available -%} {%- continue -%} {%- endif -%}
                {% assign lazy_load = false %}
                {%- if forloop.index > 2 -%}
                  {%- assign lazy_load = true -%}
                {%- endif -%}
                - {% render 'card-product',
                            card_product: product,
                            media_aspect_ratio: section.settings.image_ratio,
                            image_shape: section.settings.image_shape,
                            show_secondary_image: section.settings.show_secondary_image,
                            show_vendor: section.settings.show_vendor,
                            show_rating: section.settings.show_rating,
                            lazy_load: lazy_load,
                            show_quick_add: section.settings.enable_quick_add,
                            section_id: section.id
                    %}
                
              {%- endfor -%}
            

2 Likes

Not sure if this the most ideal, but 100% works

Hello

Shopify provides only 50 products at a time, which means sorting will be applied only to the products on the current page, not the entire product array.

For example, if there are 250 products, out of which 30 are sold out, Shopify will provide 50 products either in a random order or a specific order. These 50 products may include sold-out items; your code will only sort these 50 products.

I want to implement functionality so that all sold-out products appear on the last pages.

For Miguel’s example yes, but otherwise this is untrue. In my example I sort over the whole collection.

Is there any effective way to implement what I’ve mentioned above? I truly appreciate any guidance or suggestions.

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

<ul>
  {% for product in sorted_products %}
    <li>
      {{ product.title }}
      <!-- Add more product details here -->
    </li>
  {% endfor %}
</ul>

@andreasvirkus

I have tried your way, but pagination does not work for sorted_products as it says the format (type) of the “collection.products” and “sorted_products” are not the same.

Pagination is only available on specific Shopify objects… sorted_products itself cannot be paginated.

However, you can add pagination on the collection mixed with the filter method to get (closer to) what you want. Below, is an example I use. Using pagination normally, out of stock items get pushed to the bottom of the page - not the entire list. To get the whole collection sorted with the OOS items pushed to the bottom of the entire list, I just increase the page size to something large (1000 is big enough for my store) to fit on a single page (if you are ok with a large listing page).

{% paginate collection.products by 1000 %}  
  {% assign in_stock = collection.products | where: 'available' %}
  {% assign out_of_stock = collection.products | where: 'available', false %}
  {% assign all_sorted = in_stock | concat: out_of_stock %}

  {% for product in all_sorted %}
     do something
  {% endfor %}
{% endpaginate %}

{%- paginate collection.products by section.settings.pagination_limit -%}
{%- if collection.products.size == 0 -%}

{%- render 'icon', name: 'empty-collection', fill: '#9a9a9a' -%}

{{ 'collections.general.no_matches' | t }}

{%- else -%}

{% assign sorted_products = collection.products %}

{%- for product in sorted_products -%}
{%- if product.available == true -%}

{% liquid case settings.pcard_layout when '1' render 'product-card-1', product: product, section: section, index: forloop.index, animated: animated, animation_effect: animation_effect when '2' render 'product-card-2', product: product, section: section, index: forloop.index, animated: animated, animation_effect: animation_effect when '3' render 'product-card-3', product: product, section: section, index: forloop.index, animated: animated, animation_effect: animation_effect when '4' render 'product-card-4', product: product, section: section, index: forloop.index, animated: animated, animation_effect: animation_effect when '5' render 'product-card-5', product: product, section: section, index: forloop.index, animated: animated, animation_effect: animation_effect endcase %}
{% endif %}

{%- endfor -%}
{% assign sorted_product = collection.products %}
{%- for product in sorted_product -%}
{%- if product.available == false -%}

{% liquid case settings.pcard_layout when '1' render 'product-card-1', product: product, section: section, index: forloop.index, animated: animated, animation_effect: animation_effect when '2' render 'product-card-2', product: product, section: section, index: forloop.index, animated: animated, animation_effect: animation_effect when '3' render 'product-card-3', product: product, section: section, index: forloop.index, animated: animated, animation_effect: animation_effect when '4' render 'product-card-4', product: product, section: section, index: forloop.index, animated: animated, animation_effect: animation_effect when '5' render 'product-card-5', product: product, section: section, index: forloop.index, animated: animated, animation_effect: animation_effect endcase %}
{% endif %}

{%- endfor -%}

{% if paginate.pages > 1 %}
{%- if section.settings.paginate_type == 'paginate' -%} {%- render 'pagination', paginate: paginate, anchor: '' -%} {%- else -%} {%- render 'new-locale', key: 'collections.paginate.load_more' -%} {%- endif -%}
{% endif %} {%- endif -%} {%- endpaginate -%} I need out-of-stock products to appear at the end of the collection, but right now, they are showing at the bottom of each page. I want all available products to be displayed first, followed by the out-of-stock products. I have tried multiple approaches, but I am facing issues. I need help resolving this issue

If you are willing to not have pagination, then just set your pagination size to something very large that so everything fits on a single page.

You can setup infinite scrolling. Here is one way to do it.

https://community.shopify.com/post/1839519