Supporting Storefront Filtering

Storefront filtering lets merchants quickly make filters for collection and search results pages. Filters use current product data like availability, price, variant options, and more.

In this guide, you will see how to add storefront filtering to your theme.


Resources

To implement storefront filtering, you will use the following resources:


Implementing Storefront Filtering

To support storefront filtering, you need to implement a filter for customers to interact with.

Filters applied are reflected through URL parameters, so you should also familiarize yourself with the structure of filter URL parameters.

Note

Filters must be created in the SHOPLINE backend before they can be applied.


The Filter Display

Note

Collections with more than 5,000 products do not display filters.

The following sections outline the basic implementation of filters for collections and search results. Each implementation uses a form to host the filter inputs, with a submit button to apply the associated filters. However, you can use JavaScript to automatically submit the form based on input changes. Once the form is submitted, the page will refresh and apply the filters.

Upon form submission, the page will refresh and apply the filters.

For more advanced solutions, refer to Seed's implementation.

Collection Filters

Collection filters should be included in the collection template or referenced by content included by the collection template.

The example implementation below includes two main components:

  • A list of filter groups and their values.
  • A list of active filters, if any.

Each of these components is output through the collection object's filters attribute and the associated filter object.

<form class="filter-form">
{{#for collection.filters as |filter|}}
<details class="filter-group">
<summary class="filter-group-summary">
<div>
<span>{{ filter.label }}</span>
{{#if filter.active_values.length > 0 }}
<span>({{ filter.active_values.length }})</span>
{{/if}}
</div>
</summary>
<div class="filter-group-box">
<div class="filter-group-box__header">
<span class="filter-group-box__header-selected">{{ filter.active_values.length }} selected</span>
{{#if filter.active_values.length > 0 }}
<a href="{{ filter.url_to_remove }}" class="filter-group-box__header-reset">Reset</a>
{{/if}}
</div>
{{#case filter.type}}
{{#when "boolean" "list"}}
<ul class="facets__list">
{{#for filter.values as |value|}}
<li class="facets__item">
<label for="Filter-{{filter.param_name}}-{{forloop.index0}}" class="facet-checkbox">
<input
id="Filter-{{filter.param_name}}-{{forloop.index0}}"
type="checkbox"
name="{{value.param_name}}"
value="{{value.value}}"
{{#if value.active}}checked{{/if}}
/>
<span>
{{ value.label }}
</span>
</label>
</li>
{{/for}}
</ul>
<div class="filter-group-box__submit">
<input type="submit" value="Apply">
</div>
{{/when}}
{{#when "price_range"}}
<div class="filter-group-box__price-range">
<div class="filter-group-box__price-range-from">
<span>{{ cart.currency.symbol }}</span>
<input
name="{{ filter.min_value.param_name }}"
id="Filter-{{ filter.min_value.param_name }}"
{{#if filter.min_value.value }}
value="{{ replace (money_without_currency filter.min_value.value) ',' '' }}"
{{/if}}
type="number"
placeholder="0"
min="0"
max="{{ replace (money_without_currency filter.range_max) ',' '' }}"
>
<label for="Filter-{{ filter.min_value.param_name }}">From</label>
</div>
<div class="filter-group-box__price-range-to">
<span>{{ cart.currency.symbol }}</span>
<input name="{{ filter.max_value.param_name }}"
id="Filter-{{ filter.max_value.param_name }}"
{{#if filter.max_value.value }}
value="{{ replace (money_without_currency filter.max_value.value) ',' '' }}"
{{/if}}
type="number"
placeholder="{{ replace (money_without_currency filter.range_max) ',' '' }}"
min="0"
max="{{ replace (money_without_currency filter.range_max) ',' '' }}"
>
<label for="Filter-{{ filter.max_value.param_name }}">To</label>
</div>
</div>
<div class="filter-group-box__submit">
<input type="submit" value="Apply">
</div>
{{/when}}
{{/case}}
</div>
</details>
{{/for}}
<div class="active-filters">
<a href="{{ collection.url }}?sort_by={{ collection.sort_by }}" class="active-filters__clear">Clear all</a>
{{#for collection.filters as |filter|}}
{{#if filter.type == "price_range"}}
{{#if filter.min_value.value or filter.max_value.value }}
<a class="active-filters__remove-filter" href="{{ filter.url_to_remove }}">
{{ assign "min_value" (default filter.min_value.value 0) }}
{{ assign "max_value" (default filter.max_value.value filter.range_max) }}
{{ money_without_currency min_value }} - {{ money_without_currency max_value }} X
</a>
{{/if}}
{{else}}
{{#for filter.active_values as |filter_value| }}
<a class="active-filters__remove-filter" href="{{ filter_value.url_to_remove }}">
{{ filter.label }}: {{ filter_value.label }} X
</a>
{{/for}}
{{/if}}
{{/for}}
</div>
</form>

Search Results Filters

Note

Search results with more than 1,000 products do not display filters.

Search result filters should be included in the search template or referenced by content included by the search template.

The example implementation below includes two main components:

  • A list of filter groups and their values.
  • A list of active filters, if any.

Each of these components is output through the search object's filters attribute and the associated filter object.

If filters are applied on the search results page, all non-product results are filtered out.

<form class="filter-form">
{{#for search.filters as |filter|}}
<details class="filter-group">
<summary class="filter-group-summary">
<div>
<span>{{ filter.label }}</span>
{{#if filter.active_values.length > 0 }}
<span>({{ filter.active_values.length }})</span>
{{/if}}
</div>
</summary>
<div class="filter-group-box">
<div class="filter-group-box__header">
<span class="filter-group-box__header-selected">{{ filter.active_values.length }} selected</span>
{{#if filter.active_values.length > 0 }}
<a href="{{ filter.url_to_remove }}" class="filter-group-box__header-reset">Reset</a>
{{/if}}
</div>
{{#case filter.type}}
{{#when "boolean" "list"}}
<ul class="facets__list">
{{#for filter.values as |value|}}
<li class="facets__item">
<label for="Filter-{{filter.param_name}}-{{forloop.index0}}" class="facet-checkbox">
<input
id="Filter-{{filter.param_name}}-{{forloop.index0}}"
type="checkbox"
name="{{value.param_name}}"
value="{{value.value}}"
{{#if value.active}}checked{{/if}}
/>
<span>
{{ value.label }}
</span>
</label>
</li>
{{/for}}
</ul>
<div class="filter-group-box__submit">
<input type="submit" value="Apply">
</div>
{{/when}}
{{#when "price_range"}}
<div class="filter-group-box__price-range">
<div class="filter-group-box__price-range-from">
<span>{{ cart.currency.symbol }}</span>
<input
name="{{ filter.min_value.param_name }}"
id="Filter-{{ filter.min_value.param_name }}"
{{#if filter.min_value.value }}
value="{{ replace (money_without_currency filter.min_value.value) ',' '' }}"
{{/if}}
type="number"
placeholder="0"
min="0"
max="{{ replace (money_without_currency filter.range_max) ',' '' }}"
>
<label for="Filter-{{ filter.min_value.param_name }}">From</label>
</div>
<div class="filter-group-box__price-range-to">
<span>{{ cart.currency.symbol }}</span>
<input name="{{ filter.max_value.param_name }}"
id="Filter-{{ filter.max_value.param_name }}"
{{#if filter.max_value.value }}
value="{{ replace (money_without_currency filter.max_value.value) ',' '' }}"
{{/if}}
type="number"
placeholder="{{ replace (money_without_currency filter.range_max) ',' '' }}"
min="0"
max="{{ replace (money_without_currency filter.range_max) ',' '' }}"
>
<label for="Filter-{{ filter.max_value.param_name }}">To</label>
</div>
</div>
<div class="filter-group-box__submit">
<input type="submit" value="Apply">
</div>
{{/when}}
{{/case}}
</div>
</details>
{{/for}}
<div class="active-filters">
<a href="{{ collection.url }}?sort_by={{ collection.sort_by }}&keyword={{ search.terms }}" class="active-filters__clear">Clear all</a>
{{#for collection.filters as |filter|}}
{{#if filter.type == "price_range"}}
{{#if filter.min_value.value or filter.max_value.value }}
<a class="active-filters__remove-filter" href="{{ filter.url_to_remove }}">
{{ assign "min_value" (default filter.min_value.value 0) }}
{{ assign "max_value" (default filter.max_value.value filter.range_max) }}
{{ money_without_currency min_value }} - {{ money_without_currency max_value }} X
</a>
{{/if}}
{{else}}
{{#for filter.active_values as |filter_value| }}
<a class="active-filters__remove-filter" href="{{ filter_value.url_to_remove }}">
{{ filter.label }}: {{ filter_value.label }} X
</a>
{{/for}}
{{/if}}
{{/for}}
</div>
</form>
Was this article helpful to you?

Error loading component.

Error loading component.