These are Categories List in admin:
If I click Shop then I want to display categories and sub-categories in layered navigation filter.
How can I achieve this functionality?
Magento Stack Exchange is a question and answer site for users of the Magento e-Commerce platform. It only takes a minute to sign up.
Sign up to join this communityYou 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.