1

I am overriding Magento\Catalog\Block\Product\ListProduct In function _getProductCollection I have added some extra code.

public function _getProductCollection()
{ 
 $collection = parent::_getProductCollection(); 
 $collection->addAttributeToFilter('attribute', array('operator' =>
        'value')) 
    return $collection  
}

But my collection in not attaching this attribute. I am getting only default collection except adding operator attribute

Any idea ??

2
  • Instead of $collection->addAttributeToFilter('attribute', array('operator' => 'value')) try this $collection->addAttributeToFilter('operator', 'value') Commented Feb 7, 2019 at 8:57
  • How are you overriding the method? Using a preference? Perhaps you should try using a plugin, something like public function afterGetLoadedProductCollection() which only calls the protected function you're trying to override and returns a collection instance. Then you can try adding the attribute you need. Furthermore check the attribute settings. It must be used in product listing.
    – Zankar
    Commented Feb 7, 2019 at 8:58

3 Answers 3

6

First of all, your method should be compatible with the original method. So you should make it protected instead of public.

Now the problem.. The original _getProductCollection calls initializeProductCollection from the same class.
This method dispatches an event that can be used to alter the collection.

    $this->_eventManager->dispatch(
        'catalog_block_product_list_collection',
        ['collection' => $collection]
    );

So far so good.
Now the real problem.
There is an observer that hooks into this event.
In the review module in frontend/events.xml there is this:

<event name="catalog_block_product_list_collection">
    <observer name="review" instance="Magento\Review\Observer\CatalogBlockProductCollectionBeforeToHtmlObserver" shared="false" />
</event>

and the observer method looks like this:

public function execute(\Magento\Framework\Event\Observer $observer)
{
    $productCollection = $observer->getEvent()->getCollection();
    if ($productCollection instanceof \Magento\Framework\Data\Collection) {
        $productCollection->load();
        $this->_reviewFactory->create()->appendSummary($productCollection);
    }

    return $this;
}

As you can see, there is this line $productCollection->load();.
This actually executes the sql query from the collection and loads the products from the db.
Any other modifications you add to the collection after load is called (or after the collection gets iterated) is useless. It will not affect the collection in any way.

Possible solutions:

  1. Create a before plugin for the Magento\Review\Observer\CatalogBlockProductCollectionBeforeToHtmlObserver::execute method and attach your filter to the collection. But this is not really that clean and it doesn't insure that there will be no other events that do the same. This would only work if the observer mentioned above is run before any other observer that might call load on the collection. If you don't have such modules, you should be safe, but if you install one in the future it might take a lot of time to identify the problem.

  2. Create an after on the method Magento\Catalog\Model\Layer::getProductCollection that gets executed inside the method you are changing. But this may (or may not) have side effects and change the collection in other places.

  3. There may be other solutions that I don't know of.

7
  • I am not quite sure if we can create plugin for Magento\Catalog\Model\Layer
    – Daniel_12
    Commented Feb 7, 2019 at 9:08
  • 1
    technically or business wise? Technically is possible.
    – Marius
    Commented Feb 7, 2019 at 9:12
  • whats the best solution for this?
    – Daniel_12
    Commented Feb 7, 2019 at 9:14
  • I don't know. I would go with the plugin on the layer model. but I would check for side effects. I don't know where to tell you to look because I don't know the business case.
    – Marius
    Commented Feb 7, 2019 at 9:16
  • I created obsever on catalog_block_product_list_collection event and good part is that works
    – Daniel_12
    Commented Feb 7, 2019 at 12:05
1

I created observer for catalog_block_product_list_collection and added my filter there and am able to get the desired products

1

For overriding Magento\Catalog\Block\Product\ListProduct In function _getProductCollection. Create observer for catalog_block_product_list_collection event in custom module.

Create events.xml in the module app/code/Vendor/Module/etc/frontend/events.xml there is this:

<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="urn:magento:framework:Event/etc/events.xsd">
    <!-- event catalog_product_collection_load_after -->
    <event name="catalog_block_product_list_collection">
        <observer name="product_collection_available" instance="Vendor\Module\Observer\ProductCollectionObserver"/>
    </event>
</config>

and the observer method app/code/Vendor/Module/Observer/ProductCollectionObserver.php looks like this:

<?php
namespace Vendor\Module\Observer;

use Magento\Framework\Event\Observer;
use Magento\Framework\Event\ObserverInterface;

/**
 * ProductCollectionObserver
 */
class ProductCollectionObserver implements ObserverInterface
{
    /**
     * Handler for load product collection event
     *
     * @param Observer $observer
     * @return void
     */
    public function execute(Observer $observer)
    {
        /* set your filter here */
        $observer->getEvent()
            ->getCollection()
            ->addAttributeToSelect('*')
            ->addAttributeToFilter('attribute_code', ['operator' => 'value']);
        /* attribute_code (custom or default both are work) */
        /* If multiselect type attribute use finset as showing below */
//            ->addAttributeToFilter('attribute_code', ['finset' => [$attrOptionId]]); $attrOptionId like (1,2,3)
    
       return $this;
    }
}

Thank You!

3
  • Thanks @Mukesh. Can you please let me know how can I achieve the same for Search page results? I want to apply same filter on search page results. TIA :) Commented Mar 2, 2022 at 18:26
  • 1
    @AhsanHorani catalog_block_product_list_collection event works for me with search page results as well. But it won't update pagination block and layered navigation in category page so please check this answer magento.stackexchange.com/questions/142562/…. You can use some other event to check catalog_product_load_after or catalog_product_collection_apply_limitations_after. Thank You! Commented Mar 3, 2022 at 13:49
  • I use above code but its giving error while finding a sku ->addAttributeToFilter('sku',array('test')); " SELECT ROUND((e.min_price) * 1, 2) AS min_price_expr FROM catalog_product_index_price AS e LEFT JOIN review_entity_summary AS review_summary ON e.entity_id = review_summary.entity_pk_value AND review_summary.store_id = 1 AND review_summary.entity_type = (SELECT review_entity.entity_id FROM review_entity INNER JOIN cataloginventory_stock_status AS stock_status_index ON e.entity_id = stock_status_index.product_id WHERE (((e.sku= 'test')))
    – Anees
    Commented Sep 6, 2023 at 16:26

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.