Shopify: Add a new "In/Out of Stock" facet using inventory_quantity

I wan’t to add new Facet like “Product availability” as header and with two checkbox option “In Stock” and “Out of stock” and the type should be conjuctive in order to mix with other Facets.

I tried to figure out how to achieve this, I already have the logic for “Out of stock” by using product attribute (inventory_quantity == 0) and (inventory_quantity > 0) for “In stock”

As I learned the default Facet in the Shopify app dashboard are generated from Algolia Dashboard using API. I checked all the templates uploaded in the Shopify theme but I can’t see where to inject code for this Facet and I can’t see any documentation related to adding custom Facet.

Thanks

Hi @sandrojordanmonte70 . We didn’t expect to receive this request, and this definitely makes sense.
Doing this wouldn’t be straightforward.

Theorical solution

Basically, the goal here is to have a link which would have add those filters to the filters sent to Algolia to find in stock products (and products not tracked by Shopify):

inventory_management_shopify=0 OR inventory_quantity > 0

See also : AND groups inside OR

Finding out of stock products (and products not tracked by Shopify) would require you to add those:

inventory_management_shopify=0 OR inventory_quantity <= 0

Code

A diff will be better than words here.

--- a/assets/algolia_instant_search.js.liquid
+++ b/assets/algolia_instant_search.js.liquid
@@ -190,6 +190,41 @@
       }
     });

+    // Inventory
+    instant.search.addWidget({
+      init: function (opts) {
+        var helper = opts.helper;
+
+        // In stock
+        $('.algolia-in-stock').on('click', function () {
+          var page = helper.getPage();
+          if ($(this).hasClass('ais-facet--active')) { // Already selected, removing the filter
+            $(this).removeClass('ais-facet--active');
+            helper.setQueryParameter('filters', '');
+          } else {
+            $(this).addClass('ais-facet--active');
+            helper.setQueryParameter('filters', 'inventory_management_shopify=0 OR inventory_quantity > 0');
+          }
+          helper.setPage(page);
+          helper.search();
+        });
+
+        // Out of stock
+        $('.algolia-out-of-stock').on('click', function () {
+          var page = helper.getPage();
+          if ($(this).hasClass('ais-facet--active')) { // Already selected, removing the filter
+            $(this).removeClass('ais-facet--active');
+            helper.setQueryParameter('filters', '');
+          } else {
+            $(this).addClass('ais-facet--active');
+            helper.setQueryParameter('filters', 'inventory_management_shopify=0 OR inventory_quantity <= 0');
+          }
+          helper.setPage(page);
+          helper.search();
+        });
+      }
+    });
+
     // Hidden facets
     var list = _.map(instant.facets.hidden, function (facet) { return facet.name; });
     instant.search.addWidget({
--- a/snippets/algolia_instant_search.hogan.liquid
+++ b/snippets/algolia_instant_search.hogan.liquid
@@ -4,6 +4,21 @@
   </div>
   <div class="ais-facets">
       <div class="ais-current-refined-values-container"></div>
+      <div class="ais-facet-disjunctive ais-facet-inventory">
+        <div class="ais-root ais-refinement-list ais-facet">
+          <div class="ais-refinement-list--header ais-facet--header ais-header">Inventory</div>
+          <div class="ais-body ais-refinement-list--body ais-facet--body">
+            <div class="ais-refinement-list--list">
+              <div class="ais-refinement-list--item ais-facet--item algolia-in-stock">
+                <div><label class="ais-refinement-list--label ais-facet--label">In stock</label></div>
+              </div>
+              <div class="ais-refinement-list--item ais-facet--item algolia-out-of-stock">
+                <div><label class="ais-refinement-list--label ais-facet--label">Out of stock</label></div>
+              </div>
+            </div>
+          </div>
+        </div>
+      </div>
     [[# facets ]]
       <div class="ais-facet-[[ type ]] ais-facet-[[ name ]]"></div>
     [[/ facets ]]

Note: we’re relying on the fact that the JS helper doesn’t use filters to send parameters to Algolia.
Just in case, fixing the version of instantsearch.js in layout/theme.liquid should prevent you from future issues:

  <!-- Replace -->
  {{ '//cdn.jsdelivr.net/instantsearch.js/1/instantsearch.min.css' | stylesheet_tag }}
  <!-- and -->
  {{ '//cdn.jsdelivr.net/instantsearch.js/1/instantsearch.min.js' | script_tag }}

  <!-- With -->
  {{ '//cdn.jsdelivr.net/instantsearch.js/1.11.15/instantsearch.min.css' | stylesheet_tag }}
  <!-- and -->
  {{ '//cdn.jsdelivr.net/instantsearch.js/1.11.15/instantsearch.min.js' | script_tag }}

Thanks very much… it is working.
The missing data I found is the count number of product per facet just like some other facet.

This is unfortunately not possible. Indeed, other facets are using a single value equality, for which we can retrieve facet counts.
In this case, we’re using a comparison, which doesn’t allow us to retrieve facet counts.

Thanks a ton for this. Seems to be working great!

1 Like

Hello @Jerska
We already used this product availability filter and also we are extending using the same customization but using tags to categorize our tags with heading and now we noticed that we are looking for Facet not Filter. Can you provide me the query on how to replace Filter to make Facet.

Thanks

@sandrojordanmonte70 facets are implicitely filters. The two concepts are deeply linked together.

To set brand as a facet, we use:

attributesForFaceting: ['brand']

To set brand as a filter, we use:

attributesForFaceting: ['onlyFilter(brand)']

The difference between the two concepts is thin. Indeed, facets are used to filter a result set. But what distinguishes them from their onlyFilter alternatives is that facets can list their available values on the search page.

e.g.

The vendor attribute here is a facet, with a filter on “Algolia demo”.
Setting “Algolia demo” as an onlyFilter would make it impossible to display this list, but still possible to programatically filter on “Algolia demo”.

So to answer your question, if your tags are set as a facet, you can already filter on them.