Integrations / Platforms / Shopify / Collection Search Page Migration
Aug. 09, 2019

Collection Search Page Migration

Introduction

Algolia Search - Instant Search (1.57.0) brings improvements to the Collection page feature:

  • Improved indexing stability
  • Preparation for upcoming collection customisations and merchandising

The migration doesn’t apply to you if you installed Algolia Search - Instant Search after July 30th, 2019 or if you do not use the Collection page feature.

Depending on your implementation of the plugin, you should either do this migration:

  • Automatically via the plugin admin panel. This applies if you have enabled autocomplete, InstantSearch and other front-end features through the plugin.
  • Manually, if you have a custom implementation.

Automatic migration from the admin

To automatically upgrade your shop to Algolia Search - Instant Search (1.57.0), please follow the steps from the upgrade wizard.

Clicking on Upgrade shop triggers the following actions:

  1. Full reindex of your products and collections: this update changes the way we index products to bring more reliability and better indexing performances.
  2. Update of your front-end Algolia widgets: changing the way we index products requires an update of the installed Algolia widgets.

Follow the steps of the migration wizard

If you have changed or customized your theme by manually editing the scripts of the plugin, you must perform the migration manually. Otherwise, you will lose your changes.

If the upgrade wizard doesn’t show up, please contact us.

Manual migration

If your shop has a custom front-end implementation, you have to manually update your theme.

Algolia Search - Instant Search (1.17.0) changes the way collection page products are indexed to Algolia, and brings customization of Collections page (Facets, Sort Orders).

This requires changing the following part in your front-end implementation:

  • Products filtering
  • Query Rules
  • CSS selector logic
  • Facets and Sort Orders logic

This section provides you all the steps to migrate depending on your implementation:

  • You are using the InstantSearch widget, which you customized.
  • You have a custom implementation, using an InstantSearch library on your own.

Before updating the code, open the Algolia Search - Instant Search application and click on the Update shop button. This will reindex your products and collections with the proper attributes needed for the code update.

Follow the steps of the migration wizard

If the upgrade wizard doesn’t show up, please contact us.

Migrate InstantSearch Widget customizations

You’ve installed Algolia through the widgets provided by the plug-in, but you brought some changes to these files that are now custom.

1. Create the algolia_current_collection_id.liquid file

The InstantSearch widget needs the current collection’s ID from the current collection page to query the proper products. To do so, we need to communicate the value of the current collection’s ID to the algolia_instant_search.js file.

Current collection information is only accessible from Liquid files, which are evaluated by the Shopify back end before rendering the page. For this reason, we need to create the algolia_current_collection_id.liquid snippet file.

1. Open the theme code editor.

Dropdown to open the theme code editor

2. Create a new snippet file named algolia_current_collection_id.liquid.

Create the Snippet file

3. Add the following content and save the file:

1
2
3
{
    "currentCollectionID": {{collection.id}}
}

4. Open the layout/theme.liquid file.

5. Add the following line before the template_algolia_money_format script tag:

1
<script type="text/template" id="template_algolia_current_collection_id">{% include 'algolia_current_collection_id' %}</script>

6. Save changes to the layout/theme.liquid file.

2. Update the algolia_init.js file

You now have the current collection’s ID in the <template id="template_algolia_current_collection_id">, you need to store this current collection’s ID in a JavaScript variable in order to be able to use it with InstantSearch.

Right before this line (around line 81):

1
return '$' + val;

Add the following snippet:

1
2
3
4
5
6
7
8
9
10
// Current collection page ID
const current_collection_id_string = algolia
  .getTemplate("current_collection_id")
  .replace(/^\s+|\s+$/g, "");

if (!!current_collection_id_string) {
  const current_collection_id_object = JSON.parse(current_collection_id_string);
  algolia.current_collection_id =
    current_collection_id_object.currentCollectionID;
}

3. Update the algolia_facets.js file

The plugin now lets you configure Facets for collections page.

To enable it, you need to update the algolia_facets.js file.

Right before this line (around line 119):

1
}(algoliaShopify));

Add the following snippet:

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
// Try to fetch facets for current collection or fallback to collections default
const collection_facets =
  algolia.current_collection_id &&
  algolia.config.collection_facets[algolia.current_collection_id]
    ? algolia.config.collection_facets[algolia.current_collection_id]
    : algolia.config.collection_facets &&
      algolia.config.collection_facets.default;

if (collection_facets) {
  var enabledCollectionFacets = _.filter(collection_facets, function(facet) {
    return facet.enabled || parseInt(facet.enabled);
  });

  algolia.collectionFacets = _.map(enabledCollectionFacets, function(facet) {
    return Object.assign({}, facet, {
      escapedName: encodeURIComponent(facet.name)
    });
  });
  algolia.collectionShownFacets = _.filter(algolia.collectionFacets, function(
    facet
  ) {
    return facet.type !== "hidden";
  });
  algolia.collectionHiddenFacets = _.filter(collection_facets, function(facet) {
    return facet.type === "hidden";
  });

  algolia.collectionFacetsWidgets = _.map(
    algolia.collectionShownFacets,
    facetToWidget
  );
}

4. Update the algolia_sort_orders.js file

The plugin now lets you configure Sort Orders for collections page.

To enable it, you need to update the algolia_sort_orders.js file.

Right before this line (around line 18):

1
}(algoliaShopify));

Add the following snippet:

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
// Try to fetch sort orders for current collection or fallback to collections default
const collection_sort_orders =
  algolia.current_collection_id &&
  algolia.config.collection_sort_orders[algolia.current_collection_id]
    ? algolia.config.collection_sort_orders[algolia.current_collection_id]
    : algolia.config.collection_sort_orders &&
      algolia.config.collection_sort_orders.default;

if (collection_sort_orders) {
  algolia.collectionSortOrders = [
    { name: sort_order_base, label: "" + algolia.translations.relevance }
  ];

  _.forEach(collection_sort_orders, function(sort_order) {
    if (
      !_.isUndefined(sort_order.asc) &&
      !_.isNull(sort_order.asc) &&
      (sort_order.asc.active === true || sort_order.asc.active === "1")
    ) {
      algolia.collectionSortOrders.push({
        name: sort_order_base + "_" + sort_order.key + "_asc",
        label: sort_order.asc.title
      });
    }
    if (
      !_.isUndefined(sort_order.desc) &&
      !_.isNull(sort_order.desc) &&
      (sort_order.desc.active === true || sort_order.desc.active === "1")
    ) {
      algolia.collectionSortOrders.push({
        name: sort_order_base + "_" + sort_order.key + "_desc",
        label: sort_order.desc.title
      });
    }
  });
}

5. Update the algolia_instant_search.js file

Rename the collection page flag variable

Replace the following line:

1
2
3
var collectionFacetConstraint =
  !!algolia.is_collection_results_page &&
  !!algolia.config.instant_search_enabled_on_collection;

With the following snippet:

1
2
3
var collectionPage =
  !!algolia.is_collection_results_page &&
  !!algolia.config.instant_search_enabled_on_collection;
Store the current collection’s ID in a variable

The current collection’s ID is now stored in a algolia.current_collection_id variable. We must expose all necessary variables to properly filter products and activate Query Rules.

After this line:

1
2
3
4
5
6
if (
  (!algolia.full_results && !collectionPage) ||
  !algolia.config.instant_search_enabled
) {
  return;
}

Add the following snippet:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
var collectionFacetFilter = null;
var collectionRulesContextValue = null;
if (collectionPage) {
  var matches = window.location.pathname.match(/\/collections\/([^/]+)/i);
  const handle = !!matches && matches.length === 2 ? matches[1] : null;

  collectionFacetFilter = algolia.config.collection_id_indexing
    ? algolia.current_collection_id
      ? 'collection_ids:"' + algolia.current_collection_id + '"'
      : null
    : 'collections:"' + handle + '"';

  collectionRulesContextValue = algolia.config.collection_id_query_rules
    ? algolia.current_collection_id
    : handle;
}
Update the CSS Selector logic

Replace the following lines (around line 24):

1
2
3
4
5
6
algolia.config.results_selector += ", .algolia-shopify-instantsearch";
var $hiding = $(
  "<style>" +
    algolia.config.results_selector +
    " { visibility: hidden }</style>"
);

With the following snippet:

1
2
3
4
5
6
7
8
9
10
11
var results_selector = collectionPage
  ? algolia.config.collection_css_selector
  : algolia.config.results_selector;
var activeSortOrders =
  collectionPage && algolia.collectionSortOrders
    ? algolia.collectionSortOrders
    : algolia.sortOrders;
results_selector += ", .algolia-shopify-instantsearch";
var $hiding = $(
  "<style>" + results_selector + " { visibility: hidden }</style>"
);
Update the Sort Orders logic

Replace the occurrences of algolia.sortOrders with activeSortOrders at the following lines:

  • around line 66: sortOrders: algolia.sortOrders,
  • around line 121: multipleSortOrders: algolia.sortOrders.length > 1
  • around line 201: if (algolia.sortOrders.length > 1) {
Update the Facets logic

Replace the following lines (around line 33):

1
2
3
4
5
6
7
facets: {
  hidden: algolia.hiddenFacets,
  shown: algolia.shownFacets,
  list: algolia.facets,
  widgets: algolia.facetsWidgets
},
hitsPerPage: algolia.config.products_full_results_hits_per_page,

With the following:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
facets: {
  hidden:
    collectionPage && algolia.collectionHiddenFacets
      ? algolia.collectionHiddenFacets
      : algolia.hiddenFacets,
  shown:
    collectionPage && algolia.collectionShownFacets
      ? algolia.collectionShownFacets
      : algolia.shownFacets,
  list:
    collectionPage && algolia.collectionFacets
      ? algolia.collectionFacets
      : algolia.facets,
  widgets:
    collectionPage && algolia.collectionFacetsWidgets
      ? algolia.collectionFacetsWidgets
      : algolia.facetsWidgets
},
hitsPerPage:
  collectionPage && algolia.config.collections_full_results_hits_per_page
    ? algolia.config.collections_full_results_hits_per_page
    : algolia.config.products_full_results_hits_per_page,
Update products filtering logic

Look for the for the following line:

1
2
3
4
5
6
if (!!collectionFacetConstraint && !!collectionFacetValue) {
  helper.setQueryParameter(
    'filters',
    'collections:"' + collectionFacetValue + '"'
  );
}

And replace it by the following snippet:

1
2
3
if (!!collectionFacetFilter) {
  helper.setQueryParameter('filters', collectionFacetFilter);
}
Update Query Rules activation logic

Look for for the following lines:

1
2
3
4
// if we are on a collection page, `collectionFacetValue` is defined
if (!!collectionFacetValue) {
  helper.setQueryParameter('ruleContexts', [ collectionFacetValue ]);
}

And replace them with the following snippet:

1
2
3
4
// if we are on a collection page, `collectionRulesContextValue` is defined
if (!!collectionRulesContextValue) {
  helper.setQueryParameter('ruleContexts', [collectionRulesContextValue.toString()]);
}

Your customizations are now migrated.

Migrate a custom front-end search UI implementation

Your shop front-end search UI is built without using the provided widgets.

When browsing a collection page, the front-end search implementation needs the current collection ID to filter products and activate Query Rules. To do so, we need to communicate the value of this current collection’s ID to the JavaScript files that’s responsible of the search implementation.

1. Create the algolia_current_collection_id.liquid file

Current collection information is only accessible from Liquid files, which are evaluated by the Shopify back end before rendering the page. For this reason we need to create the algolia_current_collection_id.liquid snippet file.

1. Open the theme code editor.

Dropdown to open the theme code editor

2. Create a new snippet file named algolia_current_collection_id.liquid

Create the Snippet file

3. Add the following content and save the file:

1
2
3
{
    "currentCollectionID": {{collection.id}}
}

4. Open the layout/theme.liquid file.

5. Add the following line before the template_algolia_money_format script tag:

1
<script type="text/template" id="template_algolia_current_collection_id">{% include 'algolia_current_collection_id' %}</script>

6. Save changes to the layout/theme.liquid file.

2. Update your custom front-end implementation code

First, we need to store the current collection’s ID in a JavaScript variable.

Make sure to add the following snippet to the JavaScript file that contains the InstantSearch logic:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
var collectionFacetFilter = null;
var collectionRulesContextValue = null;

if (collectionPage) {
  const current_collection_id_string = algolia
    .getTemplate('current_collection_id')
    .replace(/^\s+|\s+$/g, '');
  let current_collection_id = null;

  if (!!current_collection_id_string) {
    const current_collection_id_object = JSON.parse(
      current_collection_id_string
    );
    current_collection_id = current_collection_id_object.currentCollectionID;
  }

  collectionFacetFilter = current_collection_id
    ? 'collection_ids:"' + current_collection_id + '"'
    : null;

  collectionRulesContextValue = current_collection_id;
}

The above snippet exposes all necessary variables to do proper products filtering and Query Rules activation.

Update products filtering logic

On Collection pages, InstantSearch should automatically filter on products that belongs to the given collection.

Your implementation should contain some logic to filter on a collections attribute. You should update this logic to filter on the collection_ids property.

You can now use the collectionFacetFilter variable which contains the proper filter value (e.g., collection_ids:132342342).

The collectionFacetFilter variable can be null if the script is loaded on a collection page that does not exist, or a different type of page (e.g., a search results page).

Update Query Rules activation logic

If your front-end search implementation contains merchandising logic using Algolia Query Rules, you must change the ruleContexts sent by InstantSearch to Algolia.

1. Look for for the line which manipulates ruleContexts.

You should update the logic to use the collectionRulesContextValue variable, which contains the proper value to use, as follows:

1
2
3
4
// if we are on a collection page, `collectionRulesContextValue` is defined
if (!!collectionRulesContextValue) {
  helper.setQueryParameter('ruleContexts', [collectionRulesContextValue.toString()]);
}

To enable merchandising on your front-end search implementation, add the following snippet into the part that handles search parameters (searchFunction):

1
2
3
4
// if we are on a collection page, `collectionRulesContextValue` is defined
if (!!collectionRulesContextValue) {
  helper.setQueryParameter('ruleContexts', [collectionRulesContextValue.toString()]);
}

The collectionRulesContextValue variable can be null if the script is loaded on a collection page that does not exist, or a different type of page (e.g., a search results page).

Your front-end search implementation is now migrated.

Did you find this page helpful?