Integrations / Shopify

Managing out of stock products

Shop owners can easily manage how to deal with out of stock items, and decide whether they should or shouldn’t appear in search results.

This feature is available from the Standard plan.

Available options

The stock policy feature in the Shopify admin

You can access this setting from the Search options tab. There are three options:

  • Show all out of stock items in search results
    All out of stock items remain in search results.
  • Hide all out of stock items in search results
    All out of stock items are removed from search results.
  • Hide out of stock items - but show those which are marked as available
    All out of stock items are removed from search results, except for those with the Continue selling when out of stock setting enabled.

The Continue selling when out of stock is accessible in the product details page of the Shopify Admin interface.

When selecting the Hide out of stock items - but show those which are marked as available option, a reindex might be necessary to ensure we have all the necessary data.

The stock policy feature reindex alert in the Shopify admin

How does it work?

This feature relies on the inventory_quantity and inventory_policy properties on the product variants, as provided by Shopify.

Under the hood, we use filters to show or hide out of stock products:

  • Show all out of stock items in search results
    We don’t apply any filters, as we don’t want to exclude anything.
  • Hide all out of stock items in search results
    We apply the inventory_quantity > 0 filter.
  • Hide out of stock items - but show those which are marked as available
    We apply the inventory_available:true filter.

The inventory_available attribute is true for records when their inventory_quantity is greater than 0, or if they have the Continue selling when out of stock setting enabled.

Widget changes

We have updated our frontend widgets to support this new feature.

The final versions of the changed widgets can be found in algolia_autocomplete.js.liquid and algolia_instant_search.js.liquid.

Autocomplete

The new algolia_autocomplete.js.liquid file contains the following changes:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
@@ -49,6 +49,33 @@
       };
     }

+    // Filters for stock policy
+    var stockPolicyFilter = null;
+
+    /**
+     * Filters for stock policy are valid only if:
+     * - stock policy has been defined, AND
+     * - we are targeting products search index
+     */
+    if (algolia.config.stock_policy && section === 'products') {
+      if (algolia.config.stock_policy === 'allow') {
+        /**
+         * For 'allow', we don't need to add any filter as we want to continue
+         * displaying all out of stock items.
+         */
+      } else if (algolia.config.stock_policy === 'deny') {
+        // For 'deny' we will filter out all items based on inventory quantity
+        stockPolicyFilter = 'inventory_quantity > 0';
+      } else if (algolia.config.stock_policy === 'continue') {
+        /**
+         * For 'continue' we will filter on `inventory_available` attribute whose
+         * value is dependent on:
+         * `inventory_quantity > 0 OR inventory_policy == 'continue'`
+         */
+        stockPolicyFilter = 'inventory_available:true';
+      }
+    }
+
     return {
       name: section,
       source: function(query, callback) {
@@ -61,6 +88,12 @@
         if (params.distinct) {
           searchOpts.distinct = true;
         }
+
+        // Add the stock policy filter if applicable
+        if (stockPolicyFilter) {
+          searchOpts.filters = stockPolicyFilter;
+        }
+
         index(section)
           .search(query, searchOpts)
           .then(function(answer) {

InstantSearch

The new algolia_instant_search.js.liquid file contains the following changes:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
@@ -25,6 +25,12 @@
     return;
   }

+  /**
+   * Array which will contain all filters to be applied while initiating the
+   * search API call.
+   */
+  var searchFilters = [];
+
   var collectionFacetFilter = null;
   var collectionRulesContextValue = null;
   if (collectionPage) {
@@ -39,11 +45,40 @@
       collectionFacetFilter = 'collections:"' + handle + '"';
     }

+    // Add the collection filter to the list of search filters
+    searchFilters.push(collectionFacetFilter);
+
     collectionRulesContextValue = algolia.config.collection_id_query_rules
       ? algolia.current_collection_id
       : handle;
   }

+  // Filters for stock policy
+  var stockPolicyFilter = null;
+  if (algolia.config.stock_policy) {
+    if (algolia.config.stock_policy === 'allow') {
+      /**
+       * For 'allow', we don't need to add any filter as we want to continue
+       * displaying all out of stock items.
+       */
+    } else if (algolia.config.stock_policy === 'deny') {
+      // For 'deny' we will filter out all items based on inventory quantity
+      stockPolicyFilter = 'inventory_quantity > 0';
+    } else if (algolia.config.stock_policy === 'continue') {
+      /**
+       * For 'continue' we will filter on `inventory_available` attribute whose
+       * value is dependent on:
+       * `inventory_quantity > 0 OR inventory_policy == 'continue'`
+       */
+      stockPolicyFilter = 'inventory_available:true';
+    }
+
+    // Add the stock policy filter to the list of search filters
+    if (stockPolicyFilter) {
+      searchFilters.push(stockPolicyFilter);
+    }
+  }
+
   var results_selector = collectionPage
     ? algolia.config.collection_css_selector
     : algolia.config.results_selector;
@@ -130,18 +165,18 @@
           searchFunctionHelper.setQueryParameter('distinct', true);
         }

-        // Collection page features
-        if (collectionPage) {
-          // Collection page filtering
-          if (collectionFacetFilter) {
+        // Assign any required filters
+        if (searchFilters.length) {
           searchFunctionHelper.setQueryParameter(
             'filters',
-              collectionFacetFilter
+            searchFilters.join(' AND ')
           );
         }

+        // Assign any required `ruleContexts` which are required for query rules
+        // targeting collection pages
+        if (collectionPage) {
           // Collection page merchandising:
-
           // send rulesContext for promoted results only if no filters active
           if (
             !hasRefinements(searchFunctionHelper, instant.facets.list) &&
Did you find this page helpful?