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!!

2
  • 1
    Why dont you get product collection by using prent::getProductCollection(), then add your custom filtering to it. This way you preserve original functionality. Dec 16, 2017 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, 2017 at 18:39

1 Answer 1

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

52
  • 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, 2017 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, 2017 at 5:45
  • @Justin You will need to use DI to overwrite Core Block. I will edit the answer. Dec 17, 2017 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, 2017 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. Dec 17, 2017 at 5:54

Your Answer

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

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