I want to have a filter by product rating in layered navigation. Regarding this, I found a solution Magento 2 : Rating Filter in Layered Navigation. This is working fine if you modify vendor\magento\module-catalog\Model\Layer\FilterList.php in core folder(vendor folder). But I'm not able to override vendor\magento\module-catalog\Model\Layer\FilterList.php from app/code. Please share if anybody has any suggestion. Thanks in advance.
1 Answer
try this
Create a module and add the below files. Create plugin to override FilterList.php
File:- Vendor/Module/Model/Layer/Filter/Rating.php
This file code available here enter link description here
<?php
namespace Vendor\Module\Model\Layer\Filter;
use Magento\Catalog\Model\Category as CategoryModel;
use Magento\Catalog\Model\CategoryFactory as CategoryModelFactory;
use Magento\Catalog\Model\Layer;
use Magento\Framework\Registry;
class Rating extends \Magento\Catalog\Model\Layer\Filter\AbstractFilter
{
protected $_categoryId;
protected $_appliedCategory;
protected $_escaper;
protected $_coreRegistry;
private $dataProvider;
public function __construct(
\Magento\Catalog\Model\Layer\Filter\ItemFactory $filterItemFactory,
\Magento\Store\Model\StoreManagerInterface $storeManager,
\Magento\Catalog\Model\Layer $layer,
\Magento\Catalog\Model\Layer\Filter\Item\DataBuilder $itemDataBuilder,
\Magento\Framework\Escaper $escaper,
array $data = []
) {
parent::__construct($filterItemFactory, $storeManager, $layer, $itemDataBuilder, $data);
$this->_escaper = $escaper;
$this->_requestVar = 'rat';
}
public function getResetValue()
{
return $this->dataProvider->getResetValue();
}
public function apply(\Magento\Framework\App\RequestInterface $request)
{
$filter = $request->getParam($this->getRequestVar());
if (!$filter) {
return $this;
}
$filter = explode('-', $filter);
list($from, $to) = $filter;
$collection = $this->getLayer()->getProductCollection();
$collection->getSelect()->joinLeft(array('rova'=> 'rating_option_vote_aggregated'),'e.entity_id =rova.entity_pk_value',array("percent"))
->where("rova.percent between ".$from." and ".$to)
->group('e.entity_id');
return $this;
}
public function getName()
{
return __('Rating');
}
protected function _getItemsData()
{
$facets = array(
'0-20'=>'1 Start',
'21-40'=>'2 Start',
'41-60'=>'3 Start',
'61-80'=>'4 Start',
'81-100'=>'5 Start'
);
$collection = $this->getLayer()->getProductCollection();
$data = [];
if (count($facets) > 1) { // two range minimum
$i=1;
foreach ($facets as $key => $label) {
$count=$this->prepareData($key,$collection,$i);
$i++;
$this->itemDataBuilder->addItemData(
$this->_escaper->escapeHtml($label),
$key,
$count
);
}
}
return $this->itemDataBuilder->build();
}
private function prepareData($filter,$collection,$i)
{
$filter = explode('-', $filter);
list($from, $to) = $filter;
$collection->getSelect()->joinLeft(array('rova'.$i=> 'rating_option_vote_aggregated'),'e.entity_id =rova'.$i.'.entity_pk_value',array("percent"))
->where("rova".$i.".percent between ".$from." and ".$to)
->group('e.entity_id');
return $collection->getSize();
}
}
File:- Vendor/Module/etc/frontend/di.xml
<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../../../../lib/internal/Magento/Framework/ObjectManager/etc/config.xsd">
<type name="Magento\Catalog\Model\Layer\FilterList">
<plugin name="rating-filter-category-navigation" type="Vendor\Module\Model\Plugin\FilterList" />
</type>
</config>
File:- Vendor/Module/Model/Plugin/FilterList.php
<?php
namespace Vendor\Module\Model\Plugin;
class FilterList
{
protected $_objectManager;
protected $_layer;
protected $_storeManager;
protected $_stockResource;
protected $_scopeConfig;
public function __construct(
\Magento\Store\Model\StoreManagerInterface $storeManager,
\Magento\Framework\ObjectManagerInterface $objectManager,
\Magento\CatalogInventory\Model\Resource\Stock\Status $stockResource,
\Magento\Framework\App\Config\ScopeConfigInterface $scopeConfig
) {
$this->_storeManager = $storeManager;
$this->_objectManager = $objectManager;
$this->_stockResource = $stockResource;
$this->_scopeConfig = $scopeConfig;
}
public function afterGetFilters(
\Magento\Catalog\Model\Layer $layer
) {
if (!count($this->filters)) {
$this->filters = [
$this->objectManager->create($this->filterTypes[self::CATEGORY_FILTER], ['layer' => $layer]),
];
foreach ($this->filterableAttributes->getList() as $attribute) {
$this->filters[] = $this->createAttributeFilter($attribute, $layer);
}
}
$data = array_shift($this->filters);
$this->filters[]= $data;
return $this->filters;
}
}
I hope this will help you...!
-
Yes that's the way I took. But I stuck in the following function public function getFilters(\Magento\Catalog\Model\Layer $layer) { } Here I'm not able to get $this->filterableAttributes->getList() since it's a interface. How to get that value in app/code/custom_module– Soham.MMay 28, 2020 at 17:59
-
-
-
Thanks @Devidas for taking time for looking into it. I'm almost there. I followed the link you added in the comment magento.stackexchange.com/questions/312680/…. But I'm getting 500 server error. I checked no other PHP error is there in the code. Can you please tell me apart from the function what should I add in the class. It's a bit more to ask, but if you could tell me it'll be very helpful for me.– Soham.MMay 29, 2020 at 9:05