Development Tips: Multiselect Layered Navigation in Magento 2

Development Tips: Multiselect Layered Navigation in Magento 2

Development Tips: Multiselect Layered Navigation in Magento 2

Default Magento Layered Navigation limits customers to choose only one option in each attribute at a time. They are not able to choose , for example, white and black dresses simultaneously and see them both in catalog regarding the search results. So, it’s not user-friendly for shoppers to apply a filter attribute and scroll through products separately.

How to solve this restriction to customers’ search?

The answer is Multiselect. Here/ in this article you will find a sample of a module implementation with such a function. We’ve detected the entry points where you need to change default Magento features. As a result, on the frontend should work the selecting of various options in each attribute, allowing customers to see more personalized search results.

Step 1: Copy Filter Rendering Pattern

The filters are rendered through the /vendor/magento/module-layered-navigation/view/frontend/templates/layer/filter.phtml pattern. We should extend it by adding functionality such as checkboxes and their rendering.

We copy the pattern to the layout/default.xml file and adapt it later according to our needs.

<referenceBlock name="catalog.navigation.renderer">
     <action method="setTemplate">
            <argument name="template" xsi:type="string"Extait_AjaxNavigation::layer/filter.phtml>/argument>
     </action>
</referenceBlock>

Step 2.1: Extend Pattern for Category

Next, we extend the functionality, which enables filter rendering and catalog filtering. Let’s take a look at the change of default Magento behavior for a filter category.

We create Extait\AjaxNavigation\Model\Layer\Filter\Category class inherited from Magento\Catalog\Model\Layer\Filter\Category and extend the following two default methods for the application of several filter options.

This one is to be modified:

/**
* Apply category filter to layer
*
* @param \Magento\Framework\App\RequestInterface $request
* @return $this
*/
public function apply(\Magento\Framework\App\RequestInterface $request)

And the following method, which is responsible for the results with multiple filters applying:

/**
* Get data array for building category filter items
*
* @return array
*/
protected function _getItemsData(

Step 2.2: Extend Pattern for Category

To use our class for filters rendering and not the default one, we add to di.xml class the following:

<virtualType name="categoryFilterList"
type="Magento\Catalog\Model\Layer\FilterList">
     <arguments>
          <argument name="filters" xsi:type="array">
               <item name="category" xsi:type="string">Extait\AjaxNavigation\Model\Layer\Filter\Category</item>
          </argument>
     </arguments>
</virtualType>

Step 3: Extend Pattern for Items in Category

As well, we need to expand the functionality for rendering of each item within one filter.

For this we create Extait\AjaxNavigation\Model\Layer\Filter\Item class derived from Magento\Catalog\Model\Layer\Filter\Item and write the code in di.xml the next way:

<type name="Magento\Catalog\Model\Layer\Filter\ItemFactory">
     <arguments>
     <argument name="instanceName" xsi:type="string">Extait\AjaxNavigation\Model\Layer\Filter\Item      </arguments>
</type>

Step 4: Extend Method for Item URLs

Don’t forget to extend the following methods in order to get URL for a certain item considering the applied filters:

/**
* Get filter item url
*
* @return string
*/
public function getUrl()

/**
* Get url for remove item from filter
*
* @return string
*/
public function getRemoveUrl()

Step 5: Add Plugin for Query Method

Then we should make a proper request to the database for multiple select to work as needed. So we add a plugin to modify the query method:

<type name="Magento\CatalogSearch\Model\Adapter\Mysql\Filter\Preprocessor"> 
     <plugin name="multiple_category_ids" type="Extait\AjaxNavigation\Plugin\Model\Adapter\Mysql\Filter\Preprocessor" />
<type>

There we declare the aroundProcess function in the following way:

public function aroundProcess(...) {
     if ($filter->getField() === 'category_ids') {
           return 'category_ids_index.category_id IN (cat_id1, cat_id2, ...)';
     }
     return $proceed(...);
}

That’s all needed to be adjusted for multiple select. All in all, we’ve extended the code parts responsible for filter rendering and their applying to products from both sides: front and back. 

In case you find any unclear point, please, ask a question in the comments below.

Also, see Magento 2 Layered navigation Custom Filters to learn how to create index tables and implement filter by discount.

Comments

© Extait, 2019