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.
And When i click on Above page generated link it show product page data like this:-
And if we click on any generate data link it redirected to custom product page with already layered navigation applied but not properly worked.
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?