1

I am trying to create a page that show a list of products that have price which is greater than some specific amount and i also want to add Layered navigation for filter these product collection based upon different attribute. But in Magento 2.4.1 when i implement the code for layered navigation in layout file it not properly work and show a layered navigation.

So Here the specific attribute product list are correctly show on custom page, but when i add layered navigation functionality the custom page are not properly render and Layered navigation not work properly.

Custom Product List Page

And When i click on Above page generated link it show product page data like this:-

Product page data

And if we click on any generate data link it redirected to custom product page with already layered navigation applied but not properly worked.

Custom Product page

My Module File Structure

app/code/Test/Special/Block/Navigation State.php

<?php
namespace Test\Special\Block\Navigation;
class State extends \Magento\LayeredNavigation\Block\Navigation\State
{
    public function __construct(
        \Magento\Framework\View\Element\Template\Context $context,
        \Test\Special\Model\Layer\Resolver $layerResolver,
        array $data=[])
{
            parent::__construct($context, $layerResolver, $data);

}
}

app/code/Test/Special/Block/Product ListProduct.php

<?php
namespace Test\Special\Block\Product;
class ListProduct extends \Magento\Catalog\Block\Product\ListProduct
{
    public function __construct(
        \Magento\Catalog\Block\Product\Context $context,
        \Magento\Framework\Data\Helper\PostHelper $postDataHelper,
        \Test\Special\Model\Layer\Resolver $layerResolver,
        \Magento\Catalog\Api\CategoryRepositoryInterface $categoryRepository,
        \Magento\Framework\Url\Helper\Data $urlHelper,
        array $data = []
    ) {
        parent::__construct($context, $postDataHelper, $layerResolver,
            $categoryRepository, $urlHelper, $data);
    }
}

app/code/Test/Special/Block Link.php

<?php
namespace Test\Special\Block;
class Link extends \Magento\Framework\View\Element\Html\Link
{
    protected function _toHtml()
    {
        if (false != $this->getTemplate()) {
            return parent::_toHtml();
        }
        return '<li><a ' . $this->getLinkAttributes() . ' >' . $this->escapeHtml($this->getLabel()) . '</a></li>';
    }
}

app/code/Test/Special/Block Navigation.php

<?php
namespace Test\Special\Block;
class Navigation extends \Magento\LayeredNavigation\Block\Navigation
{
    public function __construct(
        \Magento\Framework\View\Element\Template\Context $context,
        \Test\Special\Model\Layer\Resolver $layerResolver,
        \Magento\Catalog\Model\Layer\FilterList $filterList,
        \Magento\Catalog\Model\Layer\AvailabilityFlagInterface $visibilityFlag,
        array $data = []
    ) {
        parent::__construct($context, $layerResolver, $filterList,
            $visibilityFlag);
    }
}

app/code/Test/Special/Controller/Index Index.php

<?php
namespace Test\Special\Controller\Index;
class Index extends \Magento\Framework\App\Action\Action
{
    protected $_pageFactory;

    public function __construct(
        \Magento\Framework\App\Action\Context $context,
        \Magento\Framework\View\Result\PageFactory $pageFactory)
    {
        $this->_pageFactory = $pageFactory;
        return parent::__construct($context);
    }

    public function execute()
    {
        return $this->_pageFactory->create();
    }
}

app/code/Test/Special/etc/frontend routes.php

<?xml version="1.0" ?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:App/etc/routes.xsd">
    <router id="standard">
        <route frontName="special-machine" id="special">
            <module name="Test_Special"/>
        </route>
    </router>
</config>

app/code/Test/Special/etc di.xml

<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../../../lib/internal/Magento/Framework/ObjectManager/etc/config.xsd">
    <preference for="Magento\Catalog\Model\Layer\ContextInterface" type="Magento\Catalog\Model\Layer\Context" />
    <preference for="Magento\Catalog\Model\Layer\ItemCollectionProviderInterface" type="Magento\Catalog\Model\Layer\Category\ItemCollectionProvider" />
    <preference for="Magento\Catalog\Model\Layer\StateKeyInterface" type="Magento\Catalog\Model\Layer\Category\StateKey" />
    <preference for="Magento\Catalog\Model\Layer\CollectionFilterInterface" type="Magento\Catalog\Model\Layer\Category\CollectionFilter" />
    <preference for="Magento\Catalog\Model\Layer\FilterableAttributeListInterface" type="Magento\Catalog\Model\Layer\Category\FilterableAttributeList" />
    <preference for="Magento\Catalog\Model\Layer\AvailabilityFlagInterface" type="Magento\Catalog\Model\Layer\Category\AvailabilityFlag" />
    <preference for="Magento\Catalog\Model\ResourceModel\Layer\Filter\Price" type="Test\Special\Model\ResourceModel\Layer\Filter\Price" />
</config>

app/code/Test/Special/etc module.xml

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

app/code/Test/Special/Model/Layer Resolver.php

<?php
namespace Test\Special\Model\Layer;
class Resolver extends \Magento\Catalog\Model\Layer\Resolver
{
    protected $layer;
    protected $layersPool;

    public function __construct(
        \Magento\Framework\ObjectManagerInterface $objectManager,
        \Test\Special\Model\Layer $layer,
        array $layersPool
    ) {
        $this->layer = $layer;
        $this->layersPool = $layersPool;
        parent::__construct($objectManager, $layersPool);
    }

    public function create($layerType)
    {
        if (isset($this->layer)) {
            throw new \RuntimeException('Catalog Layer has been already created');
        }
        if (!isset($this->layersPool[$layerType])) {
            throw new \InvalidArgumentException($layerType . ' does not belong to any registered layer');
        }
        $this->layer = $this->objectManager->create($this->layersPool[$layerType]);
    }
}

app/code/Test/Special/Model/ResourceModel/Layer/Filter Price.php

<?php
namespace Test\Special\Model\ResourceModel\Layer\Filter;
use Magento\Framework\App\Http\Context;
use Magento\Framework\Indexer\DimensionFactory;
use Magento\Framework\Search\Request\IndexScopeResolverInterface;

class Price extends \Magento\Catalog\Model\ResourceModel\Layer\Filter\Price
{
    public function __construct(
        \Magento\Framework\Model\ResourceModel\Db\Context $context,
        \Magento\Framework\Event\ManagerInterface $eventManager,
        \Test\Special\Model\Layer\Resolver $layerResolver,
        \Magento\Customer\Model\Session $session,
        \Magento\Store\Model\StoreManagerInterface $storeManager,
        $connectionName = null,
        IndexScopeResolverInterface $priceTableResolver = null,
        Context $httpContext = null,
        DimensionFactory $dimensionFactory = null
    ) {
        parent::__construct($context, $eventManager, $layerResolver, $session, $storeManager, $connectionName, $priceTableResolver, $httpContext, $dimensionFactory);
    }
}

app/code/Test/Special/Model Layer.php

<?php
namespace Test\Special\Model;
use Magento\Catalog\Api\CategoryRepositoryInterface;
use Magento\Catalog\Model\ResourceModel\Product\Attribute\CollectionFactory as AttributeCollectionFactory;
use Magento\Catalog\Model\ResourceModel\Product\CollectionFactory;
class Layer extends \Magento\Catalog\Model\Layer
{
    protected $_productCollectionFactory;
    public function __construct(
        \Magento\Catalog\Model\Layer\ContextInterface $context,
        \Magento\Catalog\Model\Layer\StateFactory $layerStateFactory,
        AttributeCollectionFactory $attributeCollectionFactory,
        \Magento\Catalog\Model\ResourceModel\Product $catalogProduct,
        \Magento\Store\Model\StoreManagerInterface $storeManager,
        \Magento\Framework\Registry $registry,
        CategoryRepositoryInterface $categoryRepository,
        CollectionFactory $productCollectionFactory,
        array $data = []
    ) {
        $this->_productCollectionFactory = $productCollectionFactory;
        parent::__construct(
            $context,
            $layerStateFactory,
            $attributeCollectionFactory,
            $catalogProduct,
            $storeManager,
            $registry,
            $categoryRepository,
            $data
        );
    }
    public function getProductCollection()
    {
            $productCollection = $this->_productCollectionFactory->create()
                ->addAttributeToSelect('*')
                ->addAttributeToFilter('price', ['lt' => 95])
                ->setOrder('entity_id', 'ASC');
            return $productCollection;
    }
}

app/code/Test/Special/view/frontend/layout special_index_index.xml

<?xml version="1.0"?>
<page xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" layout="2columns-left" xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/page_configuration.xsd">
<body>
    <attribute name="class" value="page-products"/>
    <referenceContainer name="content">
        <block class="Test\Special\Block\Product\ListProduct" name="layerednavigation_index_index" 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" name="category.product.type.details.renderers.default" as="default"/>
            </block>
            <block class="Magento\Catalog\Block\Product\ProductList\Item\Container" name="category.product.addto" as="addto">
                <block class="Magento\Catalog\Block\Product\ProductList\Item\AddTo\Compare"
                       name="category.product.addto.compare" as="compare"
                       template="Magento_Catalog::product/list/addto/compare.phtml"/>
            </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>


    <!--Magento core-->
    <!--<referenceContainer name="sidebar.main">-->
        <!--<block class="Magento\LayeredNavigation\Block\Navigation\Category" 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">-->
                <!--<arguments>-->
                    <!--<argument name="product_layer_view_model" xsi:type="object">Magento\LayeredNavigation\ViewModel\Layer\Filter</argument>-->
                <!--</arguments>-->
            <!--</block>-->
        <!--</block>-->
    <!--</referenceContainer>-->

    <!--Custom layered Navigation-->
    <referenceContainer name="sidebar.main">
        <block class="Test\Special\Block\Navigation" name="catalog.leftnav" as="navigation" before="-" template="Magento_LayeredNavigation::layer/view.phtml">
            <block class="Test\Special\Block\Navigation\State" name="catalog.navigation.state" as="state" template="Magento_LayeredNavigation::layer/state.phtml"/>
            <block class="Magento\LayeredNavigation\Block\Navigation\FilterRenderer" name="catalog.navigation.renderer" as="renderer" template="Magento_LayeredNavigation::layer/filter.phtml"/>
        </block>
    </referenceContainer>

</body>
</page>

Can anyone please help me to correct the syntax or guide me how to achieve Layered Navigation in custom product collection?

0

Your Answer

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