Support storefront filtering

Storefront filtering allows merchants to easily create filters for filtering collection pages. Filters are based on existing product data, like availability, vendor, price, variant options, and more.

In this tutorial, you'll learn how to support storefront filtering in your theme.

Resources

To implement storefront filtering, you'll use the following:

Implementing storefront filtering

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

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

📘

Note

Before filters can be applied, they need to be created in the Shoplazza admin.

Filter display

The collection filter display should be included in the collection template.

The following example implementation contains several main components:

  • A spz-filter component to implement filters display and filter functions.
  • A spz-list component to implement product display and refresh the product list when the filter option is changed.
  • A spz-pagination component to implement paging functionality.
<spz-filter id="collection-filter" list-id="collection-list" result-id="filter-result" collection-id="{{ collection.id }}" layout="container">
  <div>
    <!-- Filter content -->
    <div role="content">
      <spz-render layout="container" manual as="default" class="filter-content-inner-render">
        <template>
          <div>
            <spz-dropdown id="filter-${data.title}-dropdown" placement="bottomLeft"
              overlay-style="top: 20px; left: -12px;" layout='nodisplay' hidden>
              <div>
                <div>
                  <div><span role="selectedCount"></span> selected</div>
                  <div role="reset">Reset</div>
                </div>
                <spz-selector layout='container' multiple @select="collection-filter.apply(values=event.selectedOptions);" role="items">
                  <div spz-for="item in data.values" option='${item.value}' value="${item.value}">
                    <span>${item.label}</span>
                  </div>
                </spz-selector>
              </div>
            </spz-dropdown>
            <div @tap="filter-${data.title}-dropdown.open;">${data.title}</div>
          </div>
        </template>
      </spz-render>
      <spz-render layout='container' manual as='price'>
        <template>
          <div>
            <spz-dropdown id='filter-${data.title}-dropdown' placement="bottomLeft"
              overlay-style="top: 20px; left: -12px;" layout='nodisplay' hidden>
              <div>
                <div role="reset">Reset</div>
                <div>
                  <div>
                    <span>{{ shop.finance_symbol }}</span>
                    <input type="number" placeholder='From' role="price-min" @input-debounced="collection-filter.apply;">
                  </div>
                  <div>
                    <span>{{ shop.finance_symbol }}</span>
                    <input type="number" placeholder="To" role="price-max" @input-debounced="collection-filter.apply;">
                  </div>
                </div>
              </div>
            </spz-dropdown>
            <div @tap="filter-${data.title}-dropdown.open;">${data.title}</div>
          </div>
        </template>
      </spz-render>
    </div>

    <!-- Sort -->
    <select name="sort_by" role="sortBy" @change="collection-list.refresh(sort_by=event.value, redo=true);">
      <option value="manual" selected>Recommend</option>
      <option value="price-ascending">Price, low to high</option>
      <option value="price-descending">Price, high to low</option>
      <option value="published-descending">Newest in</option>
      <option value="best-selling">Total sales, high to low</option>
      <option value="add_to_cart_count">Purchases, high to low</option>
      <option value="views">Pageviews, high to low</option>
    </select>
  </div>

  <!-- Filter result -->
  <div id="filter-result" hidden>
    <spz-render as="default" manual layout="container">
      <template>
        <div role="delete">${data.label}</div>
      </template>
    </spz-render>

    <spz-render as="price" manual layout="container">
      <template>
        <div spz-if="${!(data.gte == 0 && data.lte == -1)}" role="delete">
          <div>
            <span spz-if="${data.gte !== 0 && data.lte === -1}">more than</span>
            <spz-currency value="${data.gte || 0}" layout="container"></spz-currency>
            <span spz-if="${!!data.lte && data.lte !== -1}">-</span>
            <spz-currency value="${data.lte}" spz-if="${!!data.lte && data.lte !== -1}"
              layout="container"></spz-currency>
          </div>
        </div>
      </template>
    </spz-render>

    <div role="clearAll">Clear all</div>
  </div>
</spz-filter>

<!-- A list of products with active filters -->
<spz-list
  id="collection-list"
  layout="container"
  manual
  initial-page="0"
  page-size="20"
  total="data.count"
  list="data.products"
  src="{{ collection.id | prepend: '/api/collections/' | append: '/cps' | add_root_url }}?page=0&limit=20"
  inherit-url-search="filter,sort_by,page"
  record-params-page-plus-one
>
  {% paginate collection.products by limit %}
    {% for product in collection.products %}
      <a href="{{ product.url }}">
        <spz-img
          layout="responsive"
          width="{{ product.image.width }}"
          height="{{ product.image.height }}"
          src="{{ product.image.src }}"
          alt="{{ product.image.alt }}"
        ></spz-img>
        <span>{{ product.title | escape }}</span>
        <div>{{ product.price | money }}</div>
      </a>
    {% endfor %}
  {% endpaginate %}

  <template>
    <a href="${data.url}">
      <spz-img
        layout="responsive"
        width="${data.image.width}"
        height="${data.image.height}"
        src="${data.image.src}"
        alt="${data.image.alt}"
      ></spz-img>
      <span>${data.title}</span>
      <spz-currency value="${data.price}" layout="container"></spz-currency>
    </a>
  </template>
</spz-list>

<spz-pagination list-id="collection-list" layout="container"></spz-pagination>