Filtering products in categories
Product filtering is a Category's most powerful feature allowing users to find products within a large product catalogue. Hence it's probably the most complicated aspect of a Category template.
Product filtering is optional per Category. A website administrator may decide to enable filtering in one category and not
another. Within your template you should determine whether to show filter options with the category.filterable
property.
<?ev if (category.filterable) { ?>
...
<?ev } ?>
You should then determine if any filters are available within the category.filters()
method
which returns a CategoryFilterCollection.
<?ev if (category.filterable && category.filters().length) { ?>
<div class="category-filters">
...
</div>
<?ev } ?>
Iterating through filter groups
There are various types of filter groups represented as a CategoryFilter. These allow you to filter by:
- Product Specification
CategoryFilter.isSpecification
- Price
CategoryFilter.isPrice
- Manufacturer
CategoryFilter.isManufacturer
Accessing each group type is done in the same way:
<?ev if (category.filterable && category.filters().length) { ?>
<div class="category-filters">
<?ev for (filter of category.filters()) { ?>
<!-- Filter Group -->
<div class="filter-group">
<!-- Filter Heading -->
<div class="filter-heading">
<strong>{{ filter.title }}</strong>
<br>
{{ filter.description }}
</div>
</div>
<?ev } ?>
</div>
<?ev } ?>
Identifying selected filter groups
An active/selected filter group implies that a user has interacted with one or more of its options and the products listed
on the page are filtered accordingly. You can identify whether a filter group has one or more selected filters using
the CategoryFilter.isActive
property. This allows you to expand filter groups if your
theme collapses filters by default, for example.
<?ev if (category.filterable && category.filters().length) { ?>
<div class="category-filters">
<?ev for (filter of category.filters()) { ?>
<!-- Filter Group -->
<div class="filter-group {{ filter.isActive ? 'active' : 'inactive' }}">
<!-- Filter Heading -->
<div class="filter-heading">
<strong>{{ filter.title }}</strong>
<br>
{{ filter.description }}
</div>
</div>
<?ev } ?>
</div>
<?ev } ?>
Filter display preferences & options
There are three display preferences for category filters:
-
Single-select
CategoryFilter.isSingleSelect
Users may select one option from the available options.
Note, you do not have to use radio input fields (as illustrated below) -
Multi-select
CategoryFilter.isMultiSelect
Users may select multiple options from the available options.
Note, you do not have to use checkbox input fields (as illustrated below) -
Ranges
CategoryFilter.isRangeSelect
Users must be allowed to set a minimum and maximum value. This is usually achieved with either input fields, a range slider or both. A range display preference typically requires some JavaScript.
<?ev if (category.filterable && category.filters().length) { ?>
<div class="category-filters">
<?ev for (filter of category.filters()) { ?>
<!-- Filter Group -->
<div class="filter-group {{ filter.isActive ? 'active' : 'inactive' }}">
<!-- Filter Heading -->
<div class="filter-heading">...</div>
<?ev
if (filter.isRangeSelect) {
var option = filter.options[0];
var name = filter.type;
if (filter.isSpecification) {
name += '[' + filter.id + ']';
}
?>
<!-- Filter Range -->
<div class="filter-range">
<!-- Range minimum -->
<ev:textfield
type="number"
name="{{ name }}[min]"
value="{{ option.minValue.decimal(0) }}"
prefix="{{ option.min.prefix() }}" />
<!-- Range maximum -->
<ev:textfield
type="number"
name="{{ name }}[max]"
value="{{ option.maxValue.decimal(0) }}"
prefix="{{ option.max.prefix() }}" />
</div>
<?ev } else { ?>
<!-- Filter Options -->
<div class="filter-options">
<ul>
<?ev for (var option of filter.options) { ?>
<li class="filter-option">
<a href="{{ option.url }}" rel="nofollow">
{{ option.value }}
</a>
</li>
<?ev } ?>
</ul>
</div>
<?ev } ?>
</div>
<?ev } ?>
</div>
<?ev } ?>
A note about SEO crawl quota
You should add a rel="nofollow"
attribute to filter option links to avoid category filters consuming
valuable search engine crawl quota. We have illustrated this in the example code above.
Adding image & colour swatches
Some category filter options may have a colour or an image if the option represents a swatch based Product Specification.
You can recognise swatch preferences with CategoryFilter.isSwatch
.
<?ev if (category.filterable && category.filters().length) { ?>
<div class="category-filters">
<?ev for (filter of category.filters()) { ?>
<!-- Filter Group -->
<div class="filter-group {{ filter.isActive ? 'active' : 'inactive' }}">
...
<!-- Filter Options -->
<div class="filter-options">
<ul>
<?ev for (var option of filter.options) { ?>
<li class="filter-option">
<a href="{{ option.url }}" rel="nofollow">
<?ev if (filter.isSpecification && filter.isSwatch) { ?>
<!-- Option Swatch -->
<div
class="filter-option-swatch"
style='background-color: {{ option.value.color }};' >
<ev:img src="{{ option.value.image }}" width="50" height="50" />
</div>
<ev } ?>
<!-- Option Text -->
{{ option.value }}
</a>
</li>
<?ev } ?>
</ul>
</div>
...
</div>
<?ev } ?>
</div>
<?ev } ?>
Available on Github
Please note, the code above is incomplete for easy reading.
A more complete code sample category/filter.partial.evml
is available on Github.
Further reading
To find out more about the full capabilities of filters please take a look at the following built-in EVML objects.