1

I use a custom product collection which is used on all category view pages (basically, instead of using Magento's collection, I wrote my own module with the custom collection to implement a cookie-based vehicle filtering system).

I realize that when using a custom collection, the layered navigation, and main product search functionality does not work. Anytime I click a filter on the navigation, it will just show the custom collection without any changes. And when I type in something in the search box, it gets ignored and does not actually filter any products based on what I searched for.

My question is, how do I extend the search functionality and the layered navigation functionalities to cooperate with my custom collection?

EDIT: Here is my full custom product collection code located inside the Block folder in my module (Block/CustomCollection.php):

<?php
namespace Company\CustomCollection\Block;

use Magento\Framework\Registry;
use Magento\Catalog\Block\Product\ListProduct;


class CustomCollection extends \Magento\Catalog\Block\Product\ListProduct
{    
    private $registry;

    public function __construct(Registry $registry, 
         \Magento\Catalog\Block\Product\Context $context,        
        array $data = []
    )
    {    
        $this->registry = $registry;
        parent::__construct($context, $data);
    }

    protected function _prepareLayout()
    {

        parent::_prepareLayout();
        $this->pageConfig->getTitle()->set(__('Productss'));

            return $this;
    }


    public function getLoadedProductCollection()
    {
        $objectManager = \Magento\Framework\App\ObjectManager::getInstance();
        $car = $objectManager->get('Module\CarData\Save\Custom')->get("selectedcar");
        $category = $this->registry->registry('current_category');

        if(!empty($data)) {
        $data = array("Toyota"=>"24",  
            "Honda"=>"25", 
            "Lexus"=>"26" 
             );
        $collection = parent::getLoadedProductCollection();
        $collection->addAttributeToFilter('vehicle', array('like' => '%' . $data[$car] . '%'));

        $collection->setPageSize(7); // fetching only 7 products
    } else {
        $collection = parent::getLoadedProductCollection();
        $collection->setPageSize(7); // fetching only 7 products

    }
        return $collection;
    }

}
?>

EDIT: Here is my FULLY FUNCTIONAL CustomLayer.php

<?php
namespace Company\CustomCollection\Plugin;

use Magento\Catalog\Api\CategoryRepositoryInterface;
use Magento\Framework\Exception\NoSuchEntityException;
use Magento\Catalog\Model\ResourceModel\Product\Attribute\CollectionFactory as AttributeCollectionFactory;
use Magento\Catalog\Model\Layer\ContextInterface;

class Layer
{
  public function aroundGetProductCollection(
    \Magento\Catalog\Model\Layer $subject,
    \Closure $proceed
  ) {

        $objectManager = \Magento\Framework\App\ObjectManager::getInstance();
        $car = $objectManager->get('Module\CarData\Save\Custom')->get("selectedcar");
        $result = $proceed();

  if(!empty($data)) {
            $data = array("Toyota"=>"24",  
            "Honda"=>"25", 
            "Lexus"=>"26" 
             );
        $result->addAttributeToFilter('vehicle', array('like' => '%' . $data[$car] . '%'));


} else {
$result->addAttributeToFilter('price', array('lt' => 1201));
}
    return $result;
  }
}

DI.XML

<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd">
    <preference for="Magento\Catalog\Block\Product\ListProduct" type="Company\CustomCollection\Block\CustomCollection" />
    <type name="Magento\Catalog\Model\Layer">
    <plugin name="CustomLayer" type="Company\CustomCollection\Plugin\CustomLayer" />
    </type>
</config>

I have literally looked everywhere online, and it seems there is nothing about this. I can't be the only one with this issue. A lot of people utilize their own collections, however, what happens when they need to search or if they need to use the layered navigation filter?!

Any help would be appreciated, thanks!!

  • 1
    Why dont you get product collection by using prent::getProductCollection(), then add your custom filtering to it. This way you preserve original functionality. – Zivorad Dec 16 '17 at 10:11
  • Does this replace the need to use ProductCollectionFactory? How would I go about incorporating parent::getProductCollection into my cookie based filter? Do you have an example of this? Thanks so much! – Justin Dec 16 '17 at 18:39
0

You should avoid Object Manager, this is just an untested example based on your code. This goes inside YourNamespace\YourModule\Block\CustomCollection.php. This class also needs to extend \Magento\Catalog\Block\Product\ListProduct.

public function __construct(
    \Magento\Catalog\Block\Product\Context $context,
    \Magento\Framework\Data\Helper\PostHelper $postDataHelper,
    \Magento\Catalog\Model\Layer\Resolver $layerResolver,
    CategoryRepositoryInterface $categoryRepository,
    \Magento\Framework\Url\Helper\Data $urlHelper,
    Registry $registry, 
    array $data = []
) {
    $this->registry = $registry;
    parent::__construct(
        $context,
        $postDataHelper,
        $layerResolver,
        $categoryRepository,
        $urlHelper,
        $data
    );
}
public function getProductCollection()
{
    $objectManager = \Magento\Framework\App\ObjectManager::getInstance();
    $car = $objectManager->get('Module\CarData\Save\Custom')->get("selectedcar");
    $data = array("Toyota"=>"24", 
        "Honda"=>"25", 
        "Lexus"=>"26" 
        );
    $collection = parent::getProductCollection();
    $collection->addAttributeToFilter('car', array('like' => '%' . $data[$car] . '%'));

    return $collection;
}

This code assumes you used DI to overwrite core class. In essence, you can tell Magento to use your class instead of his core wherever it is used. I recommend using a plugin for this instance, but you don't need to bother with it. This goes inside YourNamespace\YourModule\etc\frontend\di.xml

<config>
    <preference for="Magento\Catalog\Block\Product\ListProduct" type="YourNamespace\YourModule\Block\CustomCollection" />
</config>

I am unable to test this code at the moment, so it might contain some syntax errors, or the Core class could be wrong. Here is the reference for DI. Magento DI

  • 1
    Ah, I knew it couldn't be this easy. So I went ahead and executed the code...and I received a "Fatal error: Uncaught Error: Call to a member function count() on null in "...app/design/frontend/customtheme/Magento_Catalog/template‌​s/product/list.phtml‌​" So I went into the original list.phtml file, and it looks like I may have screwed myself by using "$blockObj = $block->getLayout()->createBlock('Module\Block\MyProductCollection'); $_productCollection = $blockObj->getProductCollection();" This code basically tells list.phtml to find my module with the modified product collection, and use that – Justin Dec 17 '17 at 5:15
  • instead of the original "$_productCollection = $block->getLoadedProductCollection();" because otherwise, I don't know how to tell magento to use my custom cookie-based filtered collection. Any suggestions on how to fix this whole mess up? :/ – Justin Dec 17 '17 at 5:45
  • @Justin You will need to use DI to overwrite Core Block. I will edit the answer. – Zivorad Dec 17 '17 at 5:49
  • 1
    I have read about Dependency Injection...but the concept is a bit confusing to me still. If you don't mind, can you show me an example? That would be great. Not sure where to put the di script (inside the specific block, etc.) thanks – Justin Dec 17 '17 at 5:53
  • di.xml goes inside your module, i don't have access to a computer currently so i can't be of more help. – Zivorad Dec 17 '17 at 5:54

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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