cancel
Showing results for 
Search instead for 
Did you mean: 

Incorrect product count in layered navigation after overriding list product collection.

SOLVED

Incorrect product count in layered navigation after overriding list product collection.

I have customized(override) product list collection getProductCollection and filtered collection as required. Added below.

 

 

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

/* custom filter condition starts here*/
$productUniqueIds = array(10,11,12,13);
$collection->addAttributeToFilter('entity_id',array('in' => $productUniqueIds));
/* custom filter condition ends here */

return $collection;
}

 

But I am facing an issue in the layered navigation product count after applying filters on product collection. All counts are wrong. What I guess is I need to apply custom filters on layered navigation's collection as well, but I am not able to find it so far.

I have debugged and reached till _createItem function in vendor/magento/module-catalog/Model/Layer/Filter/AbstractFilter.php file. Product counts are coming from there, but I couldn't find from where exactly product collection gets returned.

Please share your ideas if you have. Any help would be appreciated.

2 ACCEPTED SOLUTIONS

Accepted Solutions

Re: Incorrect product count in layered navigation after overriding list product collection.

All credits to Mr. Rakesh Jesadiya for this answer.

As per question asked, I think following my answer can help you.

-> There is a Build(...) in Magento\CatalogSearch\Model\Search\IndexBuilder.php . That is actually used to build all layered navigation filters.

What I did is, made plugin to override that Build(...) function and create around method to it.

Added custom collection query as required and returned product ids from the query.

Further added where query in main select query for returning filters.


Create di.xml in your custom module.

>Custom/Layernavigation/etc/di.xml

Add following code :

<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd">
<!-- Magento Catalog search Override IndexBuilder.php plugin file -->
<type name="Magento\CatalogSearch\Model\Search\IndexBuilder">
<plugin name="Custom_Layernavigation::CustomLayernavigation"
type="Custom\Layernavigation\Plugin\CatalogSearch\Model\Search\IndexBuilder" />
</type>
</config>

Now, create plugin file to override build function that builds all filters.

>Custom/Layernavigation/Plugin/CatalogSearch/Model/Search/IndexBuilder.php

<?php

namespace Custom\Layernavigation\Plugin\CatalogSearch\Model\Search;

use Magento\Framework\DB\Select;
use Magento\Framework\Search\Request\FilterInterface;
use Magento\Framework\Search\Request\Filter\BoolExpression;
use Magento\Framework\Search\Request\Query\Filter;
use Magento\Framework\Search\RequestInterface;
use Magento\Framework\Search\Request\QueryInterface as RequestQueryInterface;
use Magento\Framework\App\ResourceConnection;

class IndexBuilder
{
/**
* @var \Magento\Framework\App\Config\ScopeConfigInterface
*/
protected $scopeConfig;

/**
* @var \Magento\Store\Model\StoreManagerInterface
*/
protected $storeManager;


public function __construct(
\Magento\Store\Model\StoreManagerInterface $storeManager,
\Magento\Catalog\Model\ResourceModel\Product\CollectionFactory $productCollectionFactory,
\Magento\Catalog\Model\Product\Visibility $productVisibility,
\Magento\Catalog\Helper\Category $categoryHelper,
\Magento\Framework\Registry $registry
) {
$this->storeManager = $storeManager;
$this->_productCollectionFactory = $productCollectionFactory; 
$this->_productVisibility = $productVisibility;
$this->categoryHelper = $categoryHelper;
$this->registry = $registry;
}

/**
* Build index query
*
* @param $subject
* @param callable $proceed
* @param RequestInterface $request
* @return Select
* @SuppressWarnings(PHPMD.UnusedFormatParameter)
*/
public function aroundBuild($subject, callable $proceed, RequestInterface $request)
{
$select = $proceed($request);
$storeId = $this->storeManager->getStore()->getStoreId();
$rootCatId = $this->storeManager->getStore($storeId)->getRootCategoryId();
$productUniqueIds = $this->getCustomCollectionQuery();
$select->where('search_index.entity_id IN (' . join(',', $productUniqueIds) . ')');

return $select;
}

/**
*
* @return ProductIds[]
*/
public function getCustomCollectionQuery() {
/* get all category ids of current store */
$websiteId = $this->storeManager->getStore()->getWebsiteId();
$currentStoreAllCategories = $this->categoryHelper->getStoreCategories(false,true,true);

$collection = $this->_productCollectionFactory->create();
$collection->addAttributeToSelect(array('entity_id','sku'));
// filter current website products
$collection->addWebsiteFilter($websiteId);
// set visibility filter
$collection->setVisibility($this->_productVisibility->getVisibleInSiteIds());

/*SKU Filter Here*/
$sku = array('24-MB04', '24-MB03', '24-MB02');
$collection->addAttributeToFilter('sku', array('in' => $sku));

$getProductAllIds = $collection->getAllIds();
$getProductUniqueIds = array_unique($getProductAllIds);
return $getProductUniqueIds;
}

}


Please correct me If I'm wrong.

View solution in original post

Re: Incorrect product count in layered navigation after overriding list product collection.

For Magento 2, if you want to give custom conditions for product collection, your custom conditions works fine for your product collection in listing page but when you check for layered navigation in the left sidebar, You may have the wrong result for product collection.

When you set custom conditions for product collection by before or after plugin for getLoadedProductCollection() or override php file, that print proper query for your result and when you check that query with a database you gave the proper result for a product.

In Magento 2 you need to override or create a plugin for build() function of IndexBuilder.php file from Catalog search module to accomplish your task.

Check the blog for details instructions, Set Custom conditions for product collection

You need to create a module, to apply custom conditions to product collection and based on above blogs module you got a proper result for collection.

If Issue Solved, Click Kudos/Accept As solutions. Get Magento insight from
Magento 2 Blogs/Tutorial

View solution in original post

15 REPLIES 15

Re: Incorrect product count in layered navigation after overriding list product collection.

All credits to Mr. Rakesh Jesadiya for this answer.

As per question asked, I think following my answer can help you.

-> There is a Build(...) in Magento\CatalogSearch\Model\Search\IndexBuilder.php . That is actually used to build all layered navigation filters.

What I did is, made plugin to override that Build(...) function and create around method to it.

Added custom collection query as required and returned product ids from the query.

Further added where query in main select query for returning filters.


Create di.xml in your custom module.

>Custom/Layernavigation/etc/di.xml

Add following code :

<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd">
<!-- Magento Catalog search Override IndexBuilder.php plugin file -->
<type name="Magento\CatalogSearch\Model\Search\IndexBuilder">
<plugin name="Custom_Layernavigation::CustomLayernavigation"
type="Custom\Layernavigation\Plugin\CatalogSearch\Model\Search\IndexBuilder" />
</type>
</config>

Now, create plugin file to override build function that builds all filters.

>Custom/Layernavigation/Plugin/CatalogSearch/Model/Search/IndexBuilder.php

<?php

namespace Custom\Layernavigation\Plugin\CatalogSearch\Model\Search;

use Magento\Framework\DB\Select;
use Magento\Framework\Search\Request\FilterInterface;
use Magento\Framework\Search\Request\Filter\BoolExpression;
use Magento\Framework\Search\Request\Query\Filter;
use Magento\Framework\Search\RequestInterface;
use Magento\Framework\Search\Request\QueryInterface as RequestQueryInterface;
use Magento\Framework\App\ResourceConnection;

class IndexBuilder
{
/**
* @var \Magento\Framework\App\Config\ScopeConfigInterface
*/
protected $scopeConfig;

/**
* @var \Magento\Store\Model\StoreManagerInterface
*/
protected $storeManager;


public function __construct(
\Magento\Store\Model\StoreManagerInterface $storeManager,
\Magento\Catalog\Model\ResourceModel\Product\CollectionFactory $productCollectionFactory,
\Magento\Catalog\Model\Product\Visibility $productVisibility,
\Magento\Catalog\Helper\Category $categoryHelper,
\Magento\Framework\Registry $registry
) {
$this->storeManager = $storeManager;
$this->_productCollectionFactory = $productCollectionFactory; 
$this->_productVisibility = $productVisibility;
$this->categoryHelper = $categoryHelper;
$this->registry = $registry;
}

/**
* Build index query
*
* @param $subject
* @param callable $proceed
* @param RequestInterface $request
* @return Select
* @SuppressWarnings(PHPMD.UnusedFormatParameter)
*/
public function aroundBuild($subject, callable $proceed, RequestInterface $request)
{
$select = $proceed($request);
$storeId = $this->storeManager->getStore()->getStoreId();
$rootCatId = $this->storeManager->getStore($storeId)->getRootCategoryId();
$productUniqueIds = $this->getCustomCollectionQuery();
$select->where('search_index.entity_id IN (' . join(',', $productUniqueIds) . ')');

return $select;
}

/**
*
* @return ProductIds[]
*/
public function getCustomCollectionQuery() {
/* get all category ids of current store */
$websiteId = $this->storeManager->getStore()->getWebsiteId();
$currentStoreAllCategories = $this->categoryHelper->getStoreCategories(false,true,true);

$collection = $this->_productCollectionFactory->create();
$collection->addAttributeToSelect(array('entity_id','sku'));
// filter current website products
$collection->addWebsiteFilter($websiteId);
// set visibility filter
$collection->setVisibility($this->_productVisibility->getVisibleInSiteIds());

/*SKU Filter Here*/
$sku = array('24-MB04', '24-MB03', '24-MB02');
$collection->addAttributeToFilter('sku', array('in' => $sku));

$getProductAllIds = $collection->getAllIds();
$getProductUniqueIds = array_unique($getProductAllIds);
return $getProductUniqueIds;
}

}


Please correct me If I'm wrong.

Re: Incorrect product count in layered navigation after overriding list product collection.

For Magento 2, if you want to give custom conditions for product collection, your custom conditions works fine for your product collection in listing page but when you check for layered navigation in the left sidebar, You may have the wrong result for product collection.

When you set custom conditions for product collection by before or after plugin for getLoadedProductCollection() or override php file, that print proper query for your result and when you check that query with a database you gave the proper result for a product.

In Magento 2 you need to override or create a plugin for build() function of IndexBuilder.php file from Catalog search module to accomplish your task.

Check the blog for details instructions, Set Custom conditions for product collection

You need to create a module, to apply custom conditions to product collection and based on above blogs module you got a proper result for collection.

If Issue Solved, Click Kudos/Accept As solutions. Get Magento insight from
Magento 2 Blogs/Tutorial

Re: Incorrect product count in layered navigation after overriding list product collection.

@kazim_noorani @Rakesh Jesadiya It's not working after enabling elastic search. Can anyone please help with this?

Re: Incorrect product count in layered navigation after overriding list product collection.

Is the issue is fixed in elastic search?

Re: Incorrect product count in layered navigation after overriding list product collection.

Thanks for posting the code in your answer.

Re: Incorrect product count in layered navigation after overriding list product collection.

Did you find a solution to the Elastic Search problem? I have the same problem.

Re: Incorrect product count in layered navigation after overriding list product collection.

The mentioned IndexBuilder does not exist in Magento 2.4. Is there any other class available as per Magento 2.4

Re: Incorrect product count in layered navigation after overriding list product collection.

2 years later any updates on this? We are in desperate need for a solution in Magento 2.4

Re: Incorrect product count in layered navigation after overriding list product collection.

Seems like this is impossible in Magento 2.4.x because of Elastic search.
Because Elastic search returns filtered product ids and aggregation data (basically collection count and filter counts along with product ids)

This products ids will be again searched in MySQL to get category page collection, So we can modify only the product collection as much as we need in MySQL search but not the count and layer navigation counts.
In my case I added one drop down attribute and went with the Magento filtration flow. At least I can have this attribute values will be indexed to Elastic search and can be filtered.
(I can customise the values that applied to filter dynamically so it helped to achieve what I need)