0

These are Categories List in admin: enter image description here

If I click Shop then I want to display categories and sub-categories in layered navigation filter.

How can I achieve this functionality?

0

You need to overwrite some core models. This cannot be achieved using Magento UI.

The model you need to overwrite is here: Magento\CatalogSearch\Model\Layer\Filter\Category

Create a new module and add this to your di.xml file:

<preference for="Magento\CatalogSearch\Model\Layer\Filter\Category" type="Vendor\Module\Model\Layer\Filter\Category" />

Try this code in your model:

<?php
/**
 * Copyright © Magento, Inc. All rights reserved.
 * See COPYING.txt for license details.
 */
 namespace Vendor\Module\Model\Layer\Filter;

  use Magento\Catalog\Model\Layer\Filter\AbstractFilter;
  use Magento\Catalog\Model\Layer\Filter\DataProvider\Category as     CategoryDataProvider;

 class Category extends AbstractFilter
 {
/**
 * @var \Magento\Framework\Escaper
 */
private $escaper;

/**
 * @var CategoryDataProvider
 */
private $dataProvider;
protected $_logger;
/**
 * @param \Magento\Catalog\Model\Layer\Filter\ItemFactory $filterItemFactory
 * @param \Magento\Store\Model\StoreManagerInterface $storeManager
 * @param \Magento\Catalog\Model\Layer $layer
 * @param \Magento\Catalog\Model\Layer\Filter\Item\DataBuilder $itemDataBuilder
 * @param \Magento\Catalog\Model\CategoryFactory $categoryFactory
 * @param \Magento\Framework\Escaper $escaper
 * @param CategoryManagerFactory $categoryManager
 * @param array $data
 */
public function __construct(   
    \Magento\Catalog\Model\Layer\Filter\ItemFactory $filterItemFactory,
    \Magento\Store\Model\StoreManagerInterface $storeManager,
    \Magento\Catalog\Model\Layer $layer,
    \Magento\Catalog\Model\Layer\Filter\Item\DataBuilder $itemDataBuilder,
    \Magento\Framework\Escaper $escaper,
    \Magento\Catalog\Model\Layer\Filter\DataProvider\CategoryFactory $categoryDataProviderFactory,
    \Psr\Log\LoggerInterface $logger, //log injection

    array $data = []
) {
    parent::__construct(
        $filterItemFactory,
        $storeManager,
        $layer,
        $itemDataBuilder,
        $data
    );
    $this->escaper = $escaper;
    $this->_requestVar = 'cat';
    $this->dataProvider = $categoryDataProviderFactory->create(['layer' => $this->getLayer()]);
    $this->_logger = $logger;
}

/**
 * Apply category filter to product collection
 *
 * @param   \Magento\Framework\App\RequestInterface $request
 * @return  $this
 */
public function apply(\Magento\Framework\App\RequestInterface $request)
{
    $categoryId = $request->getParam($this->_requestVar) ?: $request->getParam('id');
    if (empty($categoryId)) {
        return $this;
    }

    $this->dataProvider->setCategoryId($categoryId);

    $category = $this->dataProvider->getCategory();

    $this->getLayer()->getProductCollection()->addCategoryFilter($category);

    if ($request->getParam('id') != $category->getId() && $this->dataProvider->isValid()) {
        $this->getLayer()->getState()->addFilter($this->_createItem($category->getName(), $categoryId));
    }
    return $this;
}

/**
 * Get filter value for reset current filter state
 *
 * @return mixed|null
 */
public function getResetValue()
{
    return $this->dataProvider->getResetValue();
}

/**
 * Get filter name
 *
 * @return \Magento\Framework\Phrase
 */
public function getName()
{
    return __('Category');
}

/**
 * Get data array for building category filter items
 *
 * @return array
 */
protected function _getItemsData()
{
    $_objectManager = \Magento\Framework\App\ObjectManager::getInstance();
    $productCollection = $this->getLayer()->getProductCollection();

    $category = $this->dataProvider->getCategory();

    $optionsFacetedData = $productCollection->getFacetedData('category');
    $categories = $category->getChildrenCategories();
    $collectionSize = $productCollection->getSize();

    if ($category->getIsActive()) {
        foreach ($categories as $category) {
            if ($category->getIsActive()
                && isset($optionsFacetedData[$category->getId()])
                && $this->isOptionReducesResults($optionsFacetedData[$category->getId()]['count'], $collectionSize)
            ) {
                $this->itemDataBuilder->addItemData(
                    $this->escaper->escapeHtml($category->getName().'first-tier'.$category->getParentId()),
                    $category->getId(),
                    $optionsFacetedData[$category->getId()]['count']
                );
            }
                $cat = $_objectManager->create('Magento\Catalog\Model\Category')->load($category->getId());
                $sub_category = $cat->getChildrenCategories();

                foreach ($sub_category as $category) {
                    if ($category->getIsActive()
                            && isset($optionsFacetedData[$category->getId()])
                            && $this->isOptionReducesResults($optionsFacetedData[$category->getId()]['count'], $collectionSize)
                        ) 
                    {
                        $this->itemDataBuilder->addItemData(
                            $this->escaper->escapeHtml($category->getName().'second-tier'.$category->getParentId()),
                            $category->getId(),
                            $optionsFacetedData[$category->getId()]['count']
                        );
                    }
                }
        }
    }
    return $this->itemDataBuilder->build();
}
}

Basically adding a foreach loop to _getItemsData() function to display the second tier of category.

3
  • Hi! Thank you for the response, Can we select multiple categories?
    – kiran
    Nov 8 '18 at 15:55
  • That will create only one new tier under the layered navigation. If you want to add a third one, just add another foreach loop at the end.
    – Greg
    Nov 8 '18 at 15:59
  • I am using same function this->itemDataBuilder function for getting child and sub child categories. But using this->itemDataBuilder it generated all unique div for all categories. Now I need to achieve one all shu child category list into his parent category div. For example: - Main category div - Child category div - Sub child category div Is it possible?
    – Arjun
    Jan 2 '20 at 13:26

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.