Integrations / Shopify

Customizing InstantSearch

Basic customization options are described in the InstantSearch configuration section.

If you want to customize your search beyond what can be done in the configuration section, you’ll need to modify the files in the theme. It’s best if you work together with a front-end developer to customize the InstantSearch results page.

If you modify any of Algolia’s files in your theme, you won’t be able to update to the latest version of the plugin without losing your changes because an upgrade overrides your Algolia files.

Resources

The Algolia integration for Shopify adds a few additional resources to your theme.

External libraries

External libraries are hosted in your shop theme using the Shopify Assets Management. The Algolia integration for Shopify uses several libraries to build the search experience for your front end:

Generic assets

The following assets are loaded on every page:

File Description
snippets/algolia_money_format.liquid Used to retrieve the currency of your shop
assets/algolia_config.js.liquid Holds your configuration. This file is overwritten on every configuration update in your store, and shouldn’t be edited manually
assets/algolia_init.js.liquid Bootstraps InstantSearch for your shop
assets/algolia_helpers.js.liquid Templating logic helpers. For more information, see Available helpers section
assets/algolia_translations.js.liquid Contains the string constants used to translate back-end results into easily readable strings

Plugin specific assets

The CSS styles are split into two files:

Pre-bundled InstantSearch widgets

The Algolia integration for Shopify includes these InstantSearch widgets:

Update the number of facet values

To change the number of facet values shown on the search results page, you need to make two changes:

  1. Request the correct number of facet values from Algolia. Update the file algolia_instantsearch.js.liquid. For example, to retrieve five facet values from the search engine:

    1
    2
    3
    4
    5
    6
    7
    
      instant.search.addWidgets([
        configure({
          hitsPerPage: instant.hitsPerPage,
          facetingAfterDistinct: Boolean(algolia.config.show_products),
    +     maxValuesPerFacet: 5,
        }),
      ]);
    
  2. Update the algolia_facets.js.liquid file so that the refinementList widget shows all the required values:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    
      var TYPES_TO_WIDGET = {
        slider: { name: 'rangeSlider', useDefault: true, widget: rangeSlider },
        menu: { name: 'menu', params: { limit: 10 }, widget: menu },
        conjunctive: {
          name: 'refinementList',
    -     params: { operator: 'and', limit: 10 },
    +     params: { operator: 'and', limit: 5 },
          widget: refinementList,
        },
        disjunctive: {
          name: 'refinementList',
    -     params: { operator: 'or', limit: 10 },
    +     params: { operator: 'or', limit: 5 },
          widget: refinementList,
        },
      };
    

To let users see more facet values than you initially show in your interface, add a Show more button to the refinementList widget. Set showMore to true and set showMoreLimit to an applicable limit:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
  var TYPES_TO_WIDGET = {
    slider: { name: 'rangeSlider', useDefault: true, widget: rangeSlider },
    menu: { name: 'menu', params: { limit: 10 }, widget: menu },
    conjunctive: {
      name: 'refinementList',
-     params: { operator: 'and', limit: 10 },
+     params: { operator: 'and', limit: 5, showMore: true, showMoreLimit: 20 },
      widget: refinementList,
    },
    disjunctive: {
      name: 'refinementList',
-     params: { operator: 'or', limit: 10 },
+     params: { operator: 'or', limit: 5, showMore: true, showMoreLimit: 20 },
      widget: refinementList,
    },
  };

Sorting facet values

To sort the facet values, set the sortBy attribute of the refinementList widget.

Sort all conjunctive/disjunctive facets

Update the algolia_facets.js.liquid file to sort all conjunctive or disjunctive facets:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
  var TYPES_TO_WIDGET = {
    slider: { name: 'rangeSlider', useDefault: true, widget: rangeSlider },
    menu: { name: 'menu', params: { limit: 10 }, widget: menu },
    conjunctive: {
      name: 'refinementList',
-     params: { operator: 'and', limit: 10 },
+     params: { operator: 'and', limit: 10, sortBy: ["isRefined", "name:asc"] },
      widget: refinementList,
    },
    disjunctive: {
      name: 'refinementList',
-     params: { operator: 'or', limit: 10 },
+     params: { operator: 'or', limit: 10, sortBy: ["isRefined", "name:asc"] },
      widget: refinementList,
    },
  };

Sort a particular facet

To sort only particular facets, add an entry in the facetSortFunctions method defined in algolia_facets.js.liquid. For example, to sort the “vendor” facet by “name”:

1
2
3
4
5
6
7
8
9
  algolia.facetSortFunctions = {
    price_range: sortByRefined(function sortRanges(a, b) {
      if (a.name.length === b.name.length) {
        return a.name.localeCompare(b.name);
      }
      return a.name.length - b.name.length;
    }),
+   vendor: ["isRefined", "name:asc"],
  };

The key in the facetSortFunctions object is the facet name. You can find the facet names in the algoliaShopify.config.facets object.

To see other possible sorting options, see sortBy.

Display search results as a list by default

To display search results as a list, update the template snippets/algolia_instant_search.liquid:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
     <div class="ais-search-header">
       <div class="ais-stats-container"></div>
       <div class="ais-change-display">
-        <span class="ais-change-display-block ais-change-display-selected"><i class="fa fa-th-large"></i></span>
-        <span class="ais-change-display-list"><i class="fa fa-th-list"></i></span>
+        <span class="ais-change-display-block"><i class="fa fa-th-large"></i></span>
+        <span class="ais-change-display-list ais-change-display-selected"><i class="fa fa-th-list"></i></span>
       </div>
       <div class="ais-sort">
         ...
       </div>
     </div>
-    <div class="ais-hits-container ais-results-as-block"></div>
+    <div class="ais-hits-container ais-results-as-list"></div>
   </div>
   <div class="ais-pagination-container"></div>
 </div>

Turn off search-as-you-type

To use Algolia Search without the search-as-you-type experience, follow these steps:

  1. In your Shopify dashboard, make sure that your theme has the Algolia integration installed. Duplicate the theme for testing or staging.

  2. In the Search Options tab, enable InstantSearch:

    Enable the InstantSearch page to replace the default Shopify search results page

  3. In the Themes section of your Shopify store, select your theme and click Edit code.

  4. Under Assets, open the algolia_instant_search.js.liquid file.

  5. Find the code for the searchBox widget and add searchAsYouType: false to its configuration:

    Code snippet with the settings for the InstantSearch search box widget, highlighting the searchAsYouType equals false setting

  6. Add InstantSearch to your theme. Depending on how you customized your theme, you might need to adjust the styles.

Add custom widgets

You can add custom widgets to InstantSearch, either by importing a custom widget or by configuring a widget with custom templates.

Import pre-bundled widgets

Pre-bundled widgets are included by default. You can import pre-bundled widgets from the algolia.externals object within the algolia_instant_search.js.liquid file.

For example, to add a refinementList widget:

1
var refinementList = algolia.externals.widgets.refinementList;

It’s best to keep the imports together at the top of the file.

Import non-bundled widgets

To import a widget that isn’t included in the Algolia integration for Shopify, follow these steps:

  1. Add all required libraries directly on your store. Edit your theme.liquid file and add the following lines between the <!-- Algolia head --> ... <!-- /Algolia head --> block:
1
2
3
4
5
<script src="https://cdn.jsdelivr.net/npm/algoliasearch@4.5.1/dist/algoliasearch-lite.umd.js" integrity="sha256-EXPXz4W6pQgfYY3yTpnDa3OH8/EPn16ciVsPQ/ypsjk=" crossorigin="anonymous"></script>
<script src="https://cdn.jsdelivr.net/npm/instantsearch.js@4.8.3/dist/instantsearch.production.min.js" integrity="sha256-LAGhRRdtVoD6RLo2qDQsU2mp+XVSciKRC8XPOBWmofM=" crossorigin="anonymous"></script>
<script src="https://cdn.jsdelivr.net/npm/hogan.js@3.0.2/dist/hogan-3.0.2.min.js" integrity="sha256-jIAAmB65ff5CEFvV6DRfRWjHFwqq+AHeV4le8f8PYp4=" crossorigin="anonymous"></script>
<script src="https://cdn.jsdelivr.net/npm/autocomplete.js@0.37.1/dist/autocomplete.min.js" integrity="sha256-YVWQosorZnr6fALvOW9VALYuInld27RkSPkElGBdCaU=" crossorigin="anonymous"></script>
<script src="https://cdn.jsdelivr.net/npm/search-insights@1.9.0/dist/search-insights.min.js" integrity="sha256-/zXpGP2+kWLFmVvxDBsJtOhx05CPGoY6nuOg9P/5fgc=" crossorigin="anonymous"></script>
  1. Replace the file algolia_externals.js with the following code:
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
(function (algolia) {
 "use strict";

 algolia.externals = {
   // Export the required librarires
   Hogan: window.Hogan,
   instantsearch: window.instantsearch,
   algoliasearch: window.algoliasearch,
   autocomplete: window.autocomplete,
   aa: window.AlgoliaAnalytics.default,

   // Export the required widgets
   widgets: {
     rangeSlider: window.instantsearch.widgets.rangeSlider,
     menu: window.instantsearch.widgets.menu,
     refinementList: window.instantsearch.widgets.refinementList,
     searchBox: window.instantsearch.widgets.searchBox,
     stats: window.instantsearch.widgets.stats,
     sortBy: window.instantsearch.widgets.sortBy,
     clearRefinements: window.instantsearch.widgets.clearRefinements,
     panel: window.instantsearch.widgets.panel,
     hits: window.instantsearch.widgets.hits,
     pagination: window.instantsearch.widgets.pagination,
     configure: window.instantsearch.widgets.configure,
     // Define any new widgets here...
   },

   // Export InstantSearch connectors
   connectors: {
     connectCurrentRefinements:
       instantsearch.connectors.connectCurrentRefinements,
   },
 };
})(window.algoliaShopify);
  1. Export any new widgets in algolia_externals.js. For example, to use the infiniteHits widget, add it to the widgets property of the externals object like so:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    
     // Export the required widgets
     widgets: {
       rangeSlider: window.instantsearch.widgets.rangeSlider,
       menu: window.instantsearch.widgets.menu,
       refinementList: window.instantsearch.widgets.refinementList,
       searchBox: window.instantsearch.widgets.searchBox,
       stats: window.instantsearch.widgets.stats,
       sortBy: window.instantsearch.widgets.sortBy,
       clearRefinements: window.instantsearch.widgets.clearRefinements,
       panel: window.instantsearch.widgets.panel,
       hits: window.instantsearch.widgets.hits,
       pagination: window.instantsearch.widgets.pagination,
       configure: window.instantsearch.widgets.configure,
    +  infiniteHits: instantsearch.widgets.infiniteHits,
    },
    

Now you can refer to this widget in algolia_instant_search.js:

1
algolia.externals.widgets.infiniteHits

Use the widgets

When using the widget, you can modify its default templates. If you aren’t using the latest version of the Algolia for Shopify InstantSearch widget, this is necessary because InstantSearch uses the Hogan templating language to render widgets and results, but on a Shopify store, the delimiters used by Hogan have been changed to square brackets [] instead of the usual curly braces {}.

Here’s an example of how to add the refinementList widget:

1
2
3
4
5
6
7
8
9
10
11
12
instant.search.addWidgets([
  algolia.externals.widgets.refinementList({
    container: document.querySelector('.some-element-class'),
    attribute: 'vendor',
    searchable: true, // Setting searchable to true creates a search input in the refinementList UI
    templates: {
      // Use the Hogan templates utilising `[]` delimiters
      item: algolia.getTemplate('instant_search_facet_item'),
      showMoreText: algolia.getTemplate('instant_search_facet_show_more')
    }
  })
])

You can add this line anywhere after var instant has been declared.

Change the default sort order

If you want to change the sort order, you need to know:

  • The name of the sort order as it shows up in your store front
  • The name of the replica index for this sort order

For example, to target the alphabetical A-Z sort order, its name is Name and the replica index is shopify_products_title_asc.

To update the default sort order, you have to make some minor modifications to the code:

  1. Update the defined sort orders within algolia_sort_orders.js.liquid
  2. Update the InstantSearch implementation within algolia_instant_search.js.liquid

Update the defined sort orders

Update the algolia_sort_orders.js.liquid file to ensure that the required sort order comes first within the list.

For the search results page

In the algolia.config.sort_orders section, update the algolia.sortOrders object so that the required sort order comes first:

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
  algolia.config.sort_orders.forEach(function(sort_order) {
    if (
      sort_order.asc &&
      (sort_order.asc.active === true || sort_order.asc.active === '1')
    ) {
      algolia.sortOrders.push({
        value: sort_order_base + '_' + sort_order.key + '_asc',
        label: sort_order.asc.title,
      });
    }

    if (
      sort_order.desc &&
      (sort_order.desc.active === true || sort_order.desc.active === '1')
    ) {
      algolia.sortOrders.push({
        value: sort_order_base + '_' + sort_order.key + '_desc',
        label: sort_order.desc.title,
      });
    }
  });

+ // Updating the default sort order to alphabetical a-z
+ algolia.sortOrders.sort((so1, _) =>
+   so1.label === 'Name' ? -1 : 1
+ );
  ...

For collection pages

In the if (collection_sort_orders) section, update the algolia.collectionSortOrders object so that the required sort order comes up first:

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
  if (collection_sort_orders) {
    algolia.collectionSortOrders = [
      {
        value: sort_order_base,
        label: '' + algolia.translations.relevance,
      },
    ];

    collection_sort_orders.forEach(function(sort_order) {
      if (
        sort_order.asc &&
        (sort_order.asc.active === true || sort_order.asc.active === '1')
      ) {
        algolia.collectionSortOrders.push({
          value: sort_order_base + '_' + sort_order.key + '_asc',
          label: sort_order.asc.title,
        });
      }

      if (
        sort_order.desc &&
        (sort_order.desc.active === true || sort_order.desc.active === '1')
      ) {
        algolia.collectionSortOrders.push({
          value: sort_order_base + '_' + sort_order.key + '_desc',
          label: sort_order.desc.title,
        });
      }
    });

+   // Updating the default sort order to alphabetical a-z
+   algolia.collectionSortOrders.sort((so1, _) =>
+     so1.label === 'Name' ? -1 : 1
+   );
  }
})(window.algoliaShopify);

Update the InstantSearch implementation

To ensure that the desired sort order is selected by default, update the algolia_instant_search.js.liquid file.

For the search results page

Add the following lines to the top of algolia_instant_search.js.liquid:

1
2
3
4
5
6
   var collectionPageEnabled =
     algolia.is_collection_results_page &&
     algolia.config.instant_search_enabled_on_collection;
+  var targetIndexName = collectionPageEnabled
+    ? algolia.config.index_prefix + 'products'
+    : algolia.config.index_prefix + 'products_title_asc';

You need to update the indexName as well:

1
2
3
4
5
6
7
8
9
10
         algolia.config.app_id,
         algolia.config.search_api_key
       ),
-      indexName: algolia.config.index_prefix + 'products',
+      indexName: targetIndexName,
       routing: {
-        stateMapping: singleIndex(algolia.config.index_prefix + 'products'),
+        stateMapping: singleIndex(targetIndexName),
       },
       searchFunction: function(searchFunctionHelper) {

For collection pages

Add the following lines to the top of algolia_instant_search.js.liquid:

1
2
3
4
5
6
   var collectionPageEnabled =
     algolia.is_collection_results_page &&
     algolia.config.instant_search_enabled_on_collection;
+  var targetIndexName = collectionPageEnabled
+    ? algolia.config.index_prefix + 'products_title_asc'
+    : algolia.config.index_prefix + 'products';

Update the indexName as well:

1
2
3
4
5
6
7
8
9
10
         algolia.config.app_id,
         algolia.config.search_api_key
       ),
-      indexName: algolia.config.index_prefix + 'products',
+      indexName: targetIndexName,
       routing: {
-        stateMapping: singleIndex(algolia.config.index_prefix + 'products'),
+        stateMapping: singleIndex(targetIndexName),
       },
       searchFunction: function(searchFunctionHelper) {

To update the default sort order for a specific collection, you can encapsulate the changes in algolia_instant_search.js.liquid within a statement conditional on the collection names (available within the variable collectionHandle) or ID (available within the variable algolia.current_collection_id).

Did you find this page helpful?