Add custom listing filters

Overview

In an online shop, filters are an important feature. So you might use filters in your custom plugin. This guide will get you covered on how to implement your own, custom filters in Shopware's storefront.

Prerequisites

Before you start reading this guide, make sure you got an own plugin installed to work with. If you need a starting point for that, see this guide:

Create new Filter

At first, you need to create a subscriber - in this example we'll call it ExampleListingSubscriber. If you're not sure on working with subscribers, please refer to the guide on working with events in Shopware:
As usual, we'll start by creating this new class in the same path as you're seeing in Shopware's core - /src/Subscriber/ExampleListingSubscriber.php.
New listing filters, e.g. for your product listing, can be registered via the event \Shopware\Core\Content\Product\Events\ProductListingCollectFilterEvent This event was introduced to enable every developer to specify the metadata for a filter. The handling, meaning if and how a filter is added, is done by Shopware's core:
1
public static function getSubscribedEvents(): array
2
{
3
return [
4
ProductListingCollectFilterEvent::class => 'addFilter'
5
];
6
}
Copied!
After that, you can start to actually add your custom filters. Arguably an important step is to define your filter. Therefore, you're able to use the Filter class, including the parameters below:
Parameter
Description
name
Unique name of the filter
filtered
Set this option to true if this filter is active
aggregations
Defines aggregations behind a filter. Sometimes a filter contains multiple aggregations like properties
filter
Sets the DAL filter which should be added to the criteria
values
Defines the values which will be added as currentFilter to the result
exclude
Configure exclusions
As a result, an example filter could look like this:
1
$filter = new Filter(
2
// name
3
'manufacturer',
4
5
// filtered
6
!empty($ids),
7
8
// aggregations
9
[new EntityAggregation('manufacturer', 'product.manufacturerId', 'product_manufacturer')],
10
11
// filter
12
new EqualsAnyFilter('product.manufacturerId', $ids),
13
14
// values
15
$ids
16
);
Copied!
Inside the ProductListingCollectFilterEvent, you get the existing filters, can define your new custom filters and merge them into the existing ones. Here is a complete example implementation, adding a filter on the product information isCloseout. Please note the comments for explanation:
<plugin root>/src/Subscriber/ExampleListingSubscriber.php
1
class ExampleListingSubscriber implements EventSubscriberInterface
2
{
3
// register event
4
public static function getSubscribedEvents(): array
5
{
6
return [
7
ProductListingCollectFilterEvent::class => 'addFilter'
8
];
9
}
10
11
public function addFilter(ProductListingCollectFilterEvent $event): void
12
{
13
// fetch existing filters
14
$filters = $event->getFilters();
15
$request = $event->getRequest();
16
17
$filtered = (bool) $request->get('isCloseout');
18
19
$filter = new Filter(
20
// unique name of the filter
21
'isCloseout',
22
23
// defines if this filter is active
24
$filtered,
25
26
// Defines aggregations behind a filter. A filter can contain multiple aggregations like properties
27
[
28
new FilterAggregation(
29
'active-filter',
30
new MaxAggregation('active', 'product.isCloseout'),
31
[new EqualsFilter('product.isCloseout', true)]
32
),
33
],
34
35
36
// defines the DAL filter which should be added to the criteria
37
new EqualsFilter('product.isCloseout', true),
38
39
// defines the values which will be added as currentFilter to the result
40
$filtered
41
);
42
43
// Add your custom filter
44
$filters->add($filter);
45
}
46
}
Copied!

Add your filter to the Storefront UI

Well, fine - you successfully created a filter via subscriber. However, you want to enable your shop customer to use it, right? Now you need to integrate your filter in the storefront. Let's start by searching the template file you need to extend in Shopware's storefront. It's this one - src/Storefront/Resources/views/storefront/component/listing/filter-panel.html.twig.
In this template, the existing filters are contained in the block component_filter_panel_items. We are going to extend this block with our new filter. If you're not sure on how to customize templates in the storefront, we got you covered with another guide:
The block component_filter_panel_items is available from Shopware Version 6.4.8.0
Including our filter will be done as seen below, please take the comments into account:
<plugin root>/src/Resources/views/storefront/component/listing/filter-panel.html.twig
1
{% sw_extends '@Storefront/storefront/component/listing/filter-panel.html.twig' %}
2
3
{% block component_filter_panel_items %}
4
{{ parent() }}
5
6
{# We'll include our filter element here #}
7
{% sw_include '@Storefront/storefront/component/listing/filter/filter-boolean.html.twig' with {
8
name: 'isCloseout',
9
displayName: 'Closeout'
10
} %}
11
{% endblock %}
Copied!
As we want to filter a boolean value, we choose the filter-boolean component here. Sure, there are some more you can use - dependent on your filter's values:
Name
Description
filter-boolean
A filter to display boolean values
filter-multi-select
Filters with multiple values
filter-property-select
A filter tailored specifically for properties
filter-range
Displays a range which can be used for filtering
filter-rating-select and filter-rating-select-item
Filter component for rating
Extending component_filter_panel_items as shown above puts our filter after the already existing ones. We could put it at the beginning by moving the parent() call to the end of the block.
If we instead want our filter to be placed before or after a specific filter in the middle of the list, we can instead extend the block for that filter. For example, if we want our filter to be displayed after the price filter, we would extend the block component_filter_panel_item_price:
<plugin root>/src/Resources/views/storefront/component/listing/filter-panel.html.twig
1
{% sw_extends '@Storefront/storefront/component/listing/filter-panel.html.twig' %}
2
3
{% block component_filter_panel_item_price %}
4
{{ parent() }}
5
6
{# We'll include our filter element here #}
7
{% sw_include '@Storefront/storefront/component/listing/filter/filter-boolean.html.twig' with {
8
name: 'isCloseout',
9
displayName: 'Closeout'
10
} %}
11
{% endblock %}
Copied!

Next steps

Are you interested in adding custom sorting options to your listing in the storefront as well? Head over to the corresponding guide to learn more about that: