Logo BrocksiNet

BrocksiNet

Try to clean the web

How to add a "is in stock" filter in Shopware 6?

In a default shopware 6 you will have filters for properties and you will have filters for manufacturer, rating, price and free shipping. But you will not have a filter for is in stock. But shopware has a nice documentation about how to add easily a listing filter. In this post I will tell you about the learnings and the troubles I had during adding this filter to the category listing.

How filters work? And Troubles I had.

You can scroll down to the implementation when you think you will not have any troubles.

First of all there are several things that can affect your category listing page:

  • Config: Admin -> System -> Products -> Disable filter options without results -> Yes/No
  • Config: Admin -> System -> Products -> Hide products after clearance -> Yes/No
  • Using ElasticSearch -> Yes/No
  • The Index is up-to-date -> Yes/No

For me it was working the best after I refreshed the Index with:

bin/console dal:refresh:index

I am not using ElasticSearch, so it is deactivated via .env-File and also I reseted the index to make sure it is not used:

bin/console es:reset

And the admin config for Disable filter options without results is set to YES for me. Also the admin config for Hide products after clearance should be set to NO, without this the filter makes not that much sense (not that much to filter).

Now when you check your listing page and click on some filters the filters should work and also some filter options get disabled. Not the whole property, only the options that can not add more products to the listing. The whole property gets disabled when all options of the property are empty. Keep this in mind.

So where you can check this? Look into your Browser at the Network-Tab and search for a request like this (including /filter?):

http://localhost:8000/widgets/cms/navigation/dde822dcd18f4e4f8b1da49d230f9aa1/filter?only-aggregations=1&reduce-aggregations=1&slots=178c38be9b22496ab87d73bb3089eba6

This request will return some json and in this json you will find all filters and properties. Some JavaScript Plugins will then disabled or enable the filters in the frontend depending on the json that is returend.

How to implement the "is-in-stock" filter in Shopware 6?

Create a FilterSubscriber Class in (for example) custom/static-plugins/YourPlugin/src/Subscriber/FilterSubscriber.php (sure you need to update the namespace, you can also place this file in custom/plugins or in vendor):

<?php

namespace Vendor\PluginName\Subscriber;

use Shopware\Core\Content\Product\Events\ProductListingCollectFilterEvent;
use Shopware\Core\Content\Product\SalesChannel\Listing\Filter;
use Shopware\Core\Framework\DataAbstractionLayer\Search\Aggregation\Bucket\FilterAggregation;
use Shopware\Core\Framework\DataAbstractionLayer\Search\Aggregation\Metric\MaxAggregation;
use Shopware\Core\Framework\DataAbstractionLayer\Search\Filter\RangeFilter;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;

class FilterSubscriber implements EventSubscriberInterface
{
    public static function getSubscribedEvents(): array
    {
        return [
            ProductListingCollectFilterEvent::class => 'addInStockFilter'
        ];
    }

    public function addInStockFilter(ProductListingCollectFilterEvent $event): void
    {
        $filters = $event->getFilters();
        $request = $event->getRequest();
        $isInStockFiltered = (bool) $request->get('is-in-stock');

        $isInStockFilter = new Filter(
            'is-in-stock',
            $isInStockFiltered,
            [
                new FilterAggregation(
                    'is-in-stock-filter',
                    new MaxAggregation('is-in-stock', 'product.stock'),
                    [
                        new RangeFilter('product.stock', [RangeFilter::GT => 0])
                    ]
                ),
            ],
            new RangeFilter('product.stock', [RangeFilter::GT => 0]),
            $isInStockFiltered
        );

        $filters->add($isInStockFilter);
    }
}

Then you need to add your FilterSubscriber to the service.xml of your plugin (update the namespace).

<?xml version="1.0" ?>

<container xmlns="http://symfony.com/schema/dic/services"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd">

    <services>
        <service id="Vendor\PluginName\Subscriber\FilterSubscriber">
            <tag name="kernel.event_subscriber"/>
        </service>
    </services>
</container>

And now you should add the new filter to the frontend via twig template. You can create this file in that place: custom/static-plugins/PluginName/src/Resources/views/storefront/component/listing/filter-panel.html.twig (for example).

{% sw_extends '@Storefront/storefront/component/listing/filter-panel.html.twig' %}

{% block component_filter_panel_item_manufacturer %}
    {# isInStockFilter #}
    <div class="filter-wrapper">
        {% sw_include '@Storefront/storefront/component/listing/filter/filter-boolean.html.twig' with {
            name: 'is-in-stock',
            displayName: "listing.isInStockFilter"|trans|striptags
        } %}
    </div>

    {{ parent() }}
{% endblock %}

This will add the is in stock filter at the top of the filters, before manufacturer filter. After this you also need to add the translations for "listing.isInStockFilter", how to do this you can find out in the translations documentation.

After this you should clear the cache and then reload your frontpage to check if the filter is working.

Which JavaScript Files enable or disable the filters on the category listing page?

You can find them here: vendor/shopware/storefront/Resources/app/storefront/src/plugin/listing look at the filter-multi-select.plugin.js or the filter-boolean.plugin.js there you will find functions named disableFilter or enableFilter.

Released - 25.01.2022

Comments


About the author

Bild Bjoern
Björn MeyerSoftware Engineer
Björn is interested in the details of web technologies. He started with Joomla, Drupal, Typo3, vBulletin, Fireworks and Photoshop. Today his focus is on PHP for example with Magento 2, Shopware 6 and Symfony. He also likes JavaScript with Angular, React, VueJs and TypeScript. In his free time, he seeks constant balance with swimming, running and yoga.