0

I'm able to add layered navigation to a custom page, but if I try to extend \Magento\Catalog\Model\Layer class i've got this exception:

1 exception(s):
Exception #0 (Exception): Notice: Undefined offset: -1015 in /mnt/vdb/vhosts/emlineamoto.com/subdomains/dev/vendor/magento/framework/Search/Dynamic/Algorithm.php on line 302

Here the code i use:

<?xml version="1.0" encoding="utf-8"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd">
    <virtualType name="Magento\LayeredNavigation\Block\Navigation\Outlet" type="Magento\LayeredNavigation\Block\Navigation">
        <arguments>
            <argument name="layerResolver" xsi:type="object">Bileamara\SpecialCollection\Model\Layer\Resolver</argument>
            <argument name="filterList" xsi:type="object">searchFilterList</argument>
        </arguments>
    </virtualType>
    <type name="Bileamara\SpecialCollection\Model\Layer\Resolver">
        <arguments>
            <argument name="layersPool" xsi:type="array">
                <item name="outlet" xsi:type="string">Bileamara\SpecialCollection\Model\Layer\Outlet</item>
            </argument>
        </arguments>
    </type>
    <virtualType name="Bileamara\SpecialCollection\Model\Layer\Context" type="Magento\Catalog\Model\Layer\Context">
        <arguments>
            <argument name="collectionProvider" xsi:type="object">Magento\CatalogSearch\Model\Layer\Category\ItemCollectionProvider</argument>
            <argument name="stateKey" xsi:type="object">Magento\Catalog\Model\Layer\Category\StateKey</argument>
            <argument name="collectionFilter" xsi:type="object">Magento\Catalog\Model\Layer\Category\CollectionFilter</argument>
        </arguments>
    </virtualType>
    <type name="Bileamara\SpecialCollection\Model\Layer\Outlet">
        <arguments>
            <argument name="context" xsi:type="object">Bileamara\SpecialCollection\Model\Layer\Context</argument>
        </arguments>
    </type>
</config>

and class:

<?php
namespace Bileamara\SpecialCollection\Model\Layer;

class Outlet extends \Magento\Catalog\Model\Layer
{   
    public function getProductCollection()
    {
        if (isset($this->_productCollections[$this->getCurrentCategory()->getId()])) {
            $collection = $this->_productCollections[$this->getCurrentCategory()->getId()];
        } else {
            $collection = $this->collectionProvider->getCollection($this->getCurrentCategory());
            $collection->addFieldToFilter('real_stock',1);
            $this->prepareProductCollection($collection);
            $this->_productCollections[$this->getCurrentCategory()->getId()] = $collection;
        }

        return $collection;
    }
}

any suggestions?

1 Answer 1

1

I made it work.

So I share the code, maybe will be helpfull for some one.

VENDOR/MODULE/etc/frontend/di.xml

<?xml version="1.0" encoding="utf-8"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd">
    <virtualType name="Magento\LayeredNavigation\Block\Navigation\Outlet" type="Magento\LayeredNavigation\Block\Navigation">
        <arguments>
            <argument name="filterList" xsi:type="object">spcFilterList</argument>
        </arguments>
    </virtualType>
    <virtualType name="spcFilterList" type="Magento\Catalog\Model\Layer\FilterList">
        <arguments>
            <argument name="filterableAttributes" xsi:type="object">VENDOR\MODULE\Model\Layer\Outlet\FilterableAttributeList</argument>
            <argument name="filters" xsi:type="array">
                <item name="attribute" xsi:type="string">Magento\CatalogSearch\Model\Layer\Filter\Attribute</item>
                <item name="price" xsi:type="string">Magento\CatalogSearch\Model\Layer\Filter\Price</item>
                <item name="decimal" xsi:type="string">Magento\CatalogSearch\Model\Layer\Filter\Decimal</item>
                <item name="category" xsi:type="string">Magento\CatalogSearch\Model\Layer\Filter\Category</item>
            </argument>
        </arguments>
    </virtualType>
    <virtualType name="VENDOR\MODULE\Model\Layer\Outlet\FilterableAttributeList" type="Magento\Catalog\Model\Layer\Category\FilterableAttributeList">
        <arguments>
            <argument name="layer" xsi:type="object">VENDOR\MODULE\Model\Layer\Outlet</argument>
        </arguments>
    </virtualType>
    <virtualType name="VENDOR\MODULE\Model\Layer\Outlet\Context" type="Magento\Catalog\Model\Layer\Context">
        <arguments>
            <argument name="collectionProvider" xsi:type="object">Magento\CatalogSearch\Model\Layer\Category\ItemCollectionProvider</argument>
            <argument name="stateKey" xsi:type="object">Magento\Catalog\Model\Layer\Category\StateKey</argument>
            <argument name="collectionFilter" xsi:type="object">Magento\Catalog\Model\Layer\Category\CollectionFilter</argument>
        </arguments>
    </virtualType>
    <type name="VENDOR\MODULE\Model\Layer\Outlet">
        <arguments>
            <argument name="context" xsi:type="object">VENDOR\MODULE\Model\Layer\Outlet\Context</argument>
        </arguments>
    </type>
    <virtualType name="VENDOR\MODULE\Block\Outlet\ListProduct" type="Magento\Catalog\Block\Product\ListProduct">
        <arguments>
            <argument name="catalogLayer" xsi:type="object">VENDOR\MODULE\Model\Layer\Outlet</argument>
        </arguments>
    </virtualType>
    <type name="Magento\Catalog\Model\Layer\Resolver">
        <arguments>
            <argument name="layersPool" xsi:type="array">
                <item name="category" xsi:type="string">Magento\Catalog\Model\Layer\Category</item>
                <item name="search" xsi:type="string">Magento\Catalog\Model\Layer\Search</item>
                <item name="outlet" xsi:type="string">VENDOR\MODULE\Model\Layer\Outlet</item>
            </argument>
        </arguments>
    </type>
</config>

VENDOR/MODULE/Controller/Outelt/View

<?php
namespace VENDOR\MODULE\Controller\Outlet;

use Magento\Framework\App\Action\HttpGetActionInterface;
use Magento\Framework\App\Action\HttpPostActionInterface;
use Magento\Framework\App\Action\Context;
use Magento\Catalog\Model\Layer\Resolver;

class View extends \Magento\Framework\App\Action\Action implements HttpGetActionInterface, HttpPostActionInterface
{
    private $layerResolver;

    public function __construct(
        Context $context,
        Resolver $layerResolver
    ) {
        parent::__construct($context);
        $this->layerResolver = $layerResolver;
    }

    public function execute()
    {
        $this->layerResolver->create('outlet');

        $this->_view->loadLayout();
        $this->_view->renderLayout();
    }
}

VENDOR/MODULE/Model/Layer/Outlet.php

<?php
namespace VENDOR\MODULE\Model\Layer;

use Magento\Catalog\Api\CategoryRepositoryInterface;
use Magento\Catalog\Model\ResourceModel;

class Outlet extends \Magento\Catalog\Model\Layer
{
    /**
     * @param ContextInterface $context
     * @param StateFactory $layerStateFactory
     * @param \Magento\Catalog\Model\ResourceModel\Product\Attribute\CollectionFactory $attributeCollectionFactory
     * @param \Magento\Catalog\Model\ResourceModel\Product $catalogProduct
     * @param \Magento\Store\Model\StoreManagerInterface $storeManager
     * @param \Magento\Framework\Registry $registry
     * @param CategoryRepositoryInterface $categoryRepository
     * @param array $data
     */
    public function __construct(
        \Magento\Catalog\Model\Layer\ContextInterface $context,
        \Magento\Catalog\Model\Layer\StateFactory $layerStateFactory,
        \Magento\Catalog\Model\ResourceModel\Product\Attribute\CollectionFactory $attributeCollectionFactory,
        \Magento\Catalog\Model\ResourceModel\Product $catalogProduct,
        \Magento\Store\Model\StoreManagerInterface $storeManager,
        \Magento\Framework\Registry $registry,
        CategoryRepositoryInterface $categoryRepository,
        array $data = []
    ) {
        parent::__construct(
            $context,
            $layerStateFactory,
            $attributeCollectionFactory,
            $catalogProduct,
            $storeManager,
            $registry,
            $categoryRepository,
            $data
        );
    }

    public function getProductCollection()
    {
        if (isset($this->_productCollections[$this->getCurrentCategory()->getId()])) {
            $collection = $this->_productCollections[$this->getCurrentCategory()->getId()];
        } else {
            $collection = $this->collectionProvider->getCollection($this->getCurrentCategory());
            $collection->addFieldToFilter('ATTRIBUTE_CODE', 'ATTRIBUTE_VALUE');
            $this->prepareProductCollection($collection);
            $this->_productCollections[$this->getCurrentCategory()->getId()] = $collection;
        }

        return $collection;
    }
}

Here I've filtered collection by custom attribute to have a special collection page.

Using "addFieldToFilter" allows you to show configurable products that have children with attributes corresponding to the selection.

VENDOR/MODULE/view/frontend/layout/module_outlet_view.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">
    <head>
        <title>Outlet</title>
    </head>
    <body>
        <attribute name="class" value="page-with-filter"/>
        <attribute name="class" value="page-products"/>
        <referenceContainer name="sidebar.main">
            <block class="Magento\LayeredNavigation\Block\Navigation\Outlet" 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\Outlet\ListProduct" name="category.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" 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>
            <block class="Magento\Cookie\Block\RequireCookie" name="require-cookie" template="Magento_Cookie::require_cookie.phtml">
                <arguments>
                    <argument name="triggers" xsi:type="array">
                        <item name="compareProductLink" xsi:type="string">.action.tocompare</item>
                        <item name="addToWishlistLink" xsi:type="string">.action.towishlist</item>
                    </argument>
                </arguments>
            </block>
            <referenceBlock name="category.product.addto">
                <block class="Magento\Wishlist\Block\Catalog\Product\ProductList\Item\AddTo\Wishlist"
                       name="category.product.addto.wishlist" as="wishlist" before="compare"
                       template="Magento_Wishlist::catalog/product/list/addto/wishlist.phtml"/>
            </referenceBlock>
            <referenceContainer name="category.product.list.additional">
                <block class="Magento\Wishlist\Block\AddToWishlist" name="category.product.list.additional.wishlist_addto" template="Magento_Wishlist::addto.phtml" />
            </referenceContainer>
        </referenceContainer>
        <referenceBlock name="page.main.title">
            <arguments>
                <argument name="id" xsi:type="string">page-title-heading</argument>
                <argument name="add_base_attribute_aria" xsi:type="string">page-title-heading toolbar-amount</argument>
            </arguments>
        </referenceBlock>
    </body>
</page>

Here is your custom collection page!

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.