13

I want to add a layered navigation block for a custom product collection. Is there a way to do that in Magento2 ?

2
  • Try with this module link
    – rafal-kos
    Sep 1, 2016 at 16:21
  • Manadev is for advanced layered navigation on a standard product collection May 22, 2019 at 21:28

3 Answers 3

0

I know you can add one manually by adding a static block (with links to all the items you want to link) and calling it in the category layout and update xml using the code below. P.S. "Block_Code" is your static block code.

<referenceContainer name="sidebar.additional">
   <block class="Magento\Cms\Block\Block" name="male_model">
       <arguments>
            <argument name="block_id" xsi:type="string">Block_Code</argument>
       </arguments>
   </block>
</referenceContainer>
0

in admin go to : Stores > Attributes > Product

Find the attribute you want to use and set "Use in Layered Navigation" to one of the filterable options

In catalog_category_view.xml

<referenceContainer name="content">
    <block class="Magento\Catalog\Block\Category\View" name="category.products" template="Magento_Catalog::category/products.phtml">
        <block class="Magento\LayeredNavigation\Block\Navigation\Category" name="catalog.leftnav" before="-" template="Magento_LayeredNavigation::layer/view.phtml"/>
    </block>
</referenceContainer>

In category/products.phtml

<?php echo $block->getChildHtml('catalog.leftnav'); ?>
0

I was able to get product collection by using layerResolver like this:

Vendor/Module/Controller/Index/Index.php

public function __construct(
    \Magento\Framework\App\Action\Context $context,
    \Magento\Framework\View\Result\PageFactory $pageFactory,
    \Magento\Catalog\Model\Layer\Resolver $layerResolver
) {
    $this->layerResolver = $layerResolver;
    $this->pageFactory = $pageFactory;
    $this->context = $context;
    parent::__construct($context);
}

public function execute()
{        
    $date = new \Zend_Date();
    $result = $this->pageFactory->create();
    $this->layerResolver->create('search');

    $collection = $this->layerResolver->get()->getProductCollection();
    $collection->('special_price', ['gt'=>0],'left');
    $collection
         ->addAttributeToFilter(
            'special_from_date',
            [
                'or' => [
                    0 => [
                        'date' => true,
                        'to' => $date->get('YYYY-MM-dd').' 23:59:59'],
                    1 => [
                        'is' => new \Zend_Db_Expr('null')
                    ],
                ]
            ],
            'left'
        )->addAttributeToFilter(
            'special_to_date',
            [
                'or' => [
                    0 => [
                        'date' => true,
                        'from' =>  $date->get('YYYY-MM-dd').' 00:00:00'],
                    1 => [
                        'is' => new \Zend_Db_Expr('null')
                    ],
                ]
            ],
            'left'
        );
    $list = $result->getLayout()->getBlock('custom.products.list');
    $list->setProductCollection($collection);
    return $result;
}

To avoid problems with aggregations and buckets I use this:

Vendor/Module/etc/di.xml

<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd">

    <!-- To prepare the filterlist for our custom collection which would be passed to the left navigation we need below virtual types for our custom page navigation -->
    <virtualType name="customFilterList" type="Vendor\Module\Model\Layer\FilterList">
        <arguments>
            <argument name="filterableAttributes" xsi:type="object">Vendor\Module\Model\Layer\FilterableAttributeList</argument>
            <argument name="filters" xsi:type="array">
                <item name="attribute" xsi:type="string">Vendor\Module\Model\Layer\Filter\Attribute</item>
                <item name="category" xsi:type="string">Vendor\Module\Model\Layer\Filter\Category</item>
            </argument>
        </arguments>
    </virtualType>

    <!-- once the filter list virtual type is ready we can pass the same to our navigation , I have prepared the virtual type of the core navigation for my custom module and have passed the custom filter list to it -->
    <virtualType name="Vendor\Module\Block\Navigation\Custnavigation" type="Magento\LayeredNavigation\Block\Navigation">
        <arguments>
            <argument name="filterList" xsi:type="object">customFilterList</argument>
        </arguments>
    </virtualType>
</config>

Vendor/Module/Model/Layer/FilterableAttributeList.php

namespace Vendor\Module\Model\Layer;
class FilterableAttributeList extends \Magento\Catalog\Model\Layer\Category\FilterableAttributeList
{
}

Vendor/Module/Model/Layer/FilterList.php

namespace Vendor\Module\Model\Layer;
class FilterList extends \Magento\Catalog\Model\Layer\FilterList
{
}

Vendor/Module/Model/Layer/Filter/Attribute.php

namespace Vendor\Module\Model\Layer\Filter;

class Attribute extends \Magento\Catalog\Model\Layer\Filter\Attribute
{
}

Vendor/Module/Model/Layer/Filter/Category.php

namespace Vendor\Module\Model\Layer\Filter;

class Category extends \Magento\CatalogSearch\Model\Layer\Filter\Category
{
}

Vendor/Module/view/frontend/layout/custompage_index_index.xml

<?xml version="1.0"?>
<page xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" layout="2columns-left">
    <body>
        <attribute name="class" value="page-with-filter"/>
        <referenceContainer name="sidebar.main">
            <block class="Vendor\Module\Block\Navigation\Custnavigation" name="catalog.leftnav" before="-" template="Magento_LayeredNavigation::layer/view.phtml">
                <block class="Magento\LayeredNavigation\Block\Navigation\State" name="catalog.navigation.state" as="state" />
                <block class="Magento\LayeredNavigation\Block\Navigation\FilterRenderer" name="catalog.navigation.renderer" as="renderer" template="Magento_LayeredNavigation::layer/filter.phtml"/>
            </block>
        </referenceContainer>
        <referenceContainer name="content">
            <block class="Vendor\Module\Block\Product\CustomList" name="custom.products.list" as="product_list" template="Magento_Catalog::product/list.phtml">
                <container name="category.product.list.additional" as="additional" />
                <block class="Magento\Framework\View\Element\RendererList" name="category.product.type.details.renderers" as="details.renderers">
                    <block class="Magento\Framework\View\Element\Template" as="default"/>
                </block>
                <block class="Magento\Catalog\Block\Product\ProductList\Toolbar" name="product_list_toolbar" template="Magento_Catalog::product/list/toolbar.phtml">
                    <block class="Magento\Theme\Block\Html\Pager" name="product_list_toolbar_pager"/>
                </block>
                <action method="setToolbarBlockName">
                    <argument name="name" xsi:type="string">product_list_toolbar</argument>
                </action>
            </block>
        </referenceContainer>
    </body>
</page>

Vendor/Module/Block/Product/CustomList.php

namespace Vendor\Module\Block\Product;

use Magento\Catalog\Block\Product\ListProduct;
use Magento\Catalog\Model\ResourceModel\Collection\AbstractCollection;

class CustomList extends ListProduct
{
    public function getLoadedProductCollection()
    {
        return $this->_productCollection;
    }

    public function setProductCollection(AbstractCollection $collection)
    {
        $this->_productCollection = $collection;
    }
}

This will give you filtered collection on custom page via available special price today.

Most of this code was found here on Stack Exchange in questions with layered-navigation tag.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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