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.

This site is temporarily in read-only mode and not accepting new answers.

Not the answer you're looking for? Browse other questions tagged .