In Magento 2 How to add Star Rating Filter in to Layered Navigation?
-
I have change core as your code, it is work fine. but if I create a extension and rewrite class vendor\magento\module-catalog\Model\Layer\FilterList.php. it can't rewrite it. So can you please support any idea for this Thanks– user39839May 17, 2016 at 3:23
-
Can we implement this with AJAX ? I need to implement filter in magento 2 with AJAX– manpreetJun 25, 2016 at 13:18
3 Answers
create one file Called Rating.php as of now i did in core module only which can be implemented in your custom module vendor\magento\module-catalog\Model\Layer\Filter\Rating.php
<?php
/**
* Copyright © 2015 Magento. All rights reserved.
* See COPYING.txt for license details.
*/
namespace Magento\Catalog\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;
/**
* Layer category filter
*
* @author Magento Core Team <[email protected]>
*/
class Rating extends \Magento\Catalog\Model\Layer\Filter\AbstractFilter
{
/**
* Active Category Id
*
* @var int
*/
protected $_categoryId;
/**
* Applied Category
*
* @var \Magento\Catalog\Model\Category
*/
protected $_appliedCategory;
/**
* Core data
*
* @var \Magento\Framework\Escaper
*/
protected $_escaper;
/**
* Core registry
*
* @var \Magento\Framework\Registry
*/
protected $_coreRegistry;
/**
* @var CategoryDataProvider
*/
private $dataProvider;
/**
* Construct
*
* @param \Magento\Catalog\Model\Layer\Filter\ItemFactory $filterItemFactory
* @param \Magento\Store\Model\StoreManagerInterface $storeManager
* @param \Magento\Catalog\Model\Layer $layer
* @param \Magento\Catalog\Model\Layer\Filter\Item\DataBuilder $itemDataBuilder
* @param \Magento\Framework\Escaper $escaper
* @param CategoryFactory $categoryDataProviderFactory
* @param array $data
*/
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';
}
/**
* Get filter value for reset current filter state
*
* @return mixed|null
*/
public function getResetValue()
{
return $this->dataProvider->getResetValue();
}
/**
* Apply category filter to layer
*
* @param \Magento\Framework\App\RequestInterface $request
* @return $this
*/
public function apply(\Magento\Framework\App\RequestInterface $request)
{
/**
* Filter must be string: $fromPrice-$toPrice
*/
$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');
//$this->getLayer()->getState()->addFilter($this->_createItem($text, $filter));
//$collection->printlogquery(true);
return $this;
}
/**
* Get filter name
*
* @return \Magento\Framework\Phrase
*/
public function getName()
{
return __('Rating');
}
/**
* Get data array for building attribute filter items
*
* @throws \Magento\Framework\Exception\LocalizedException
* @return array
*/
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();
/* $this->itemDataBuilder->addItemData(
$this->tagFilter->filter('5 star'),
'80-100',
1
);
return $this->itemDataBuilder->build(); */
}
/**
* @param string $key
* @param int $count
* @return array
*/
private function prepareData($filter,$collection,$i)
{
$filter = explode('-', $filter);
list($from, $to) = $filter;
/** @var \Magento\CatalogSearch\Model\ResourceModel\Fulltext\Collection $productCollection */
$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');
//$collection->printlogquery(true); echo '<br>............................<br>';
return $collection->getSize();
}
}
and in vendor\magento\module-catalog\Model\Layer\FilterList.php add rating filter option if you wrote custom module add this option by plugin
public function getFilters(\Magento\Catalog\Model\Layer $layer)
{
if (!count($this->filters)) {
$this->filters = [
$this->objectManager->create($this->filterTypes[self::CATEGORY_FILTER], ['layer' => $layer]),
$this->objectManager->create($this->filterTypes['Magento\Catalog\Model\Layer\Filter\Rating'], ['layer' => $layer]),
];
foreach ($this->filterableAttributes->getList() as $attribute) {
$this->filters[] = $this->createAttributeFilter($attribute, $layer);
}
}
return $this->filters;
}
it will bring rating filter and do filter with product collection but still product count and adding to state i not done if some one did please pot it
-
1
-
-
-
I found this on GitHub: it also adds a custom filter in a module. You can find it here: github.com/tzyganu/magento2-stock-filter– MennoJan 13, 2017 at 9:10
-
1Can anyone give me suggestion to add discount filter with percentage and in range?– MagecodeSep 13, 2017 at 10:49
I have used the following code for custom prices.
<?xml version="1.0" ?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd">
<type name="Magento\Catalog\Model\Layer\FilterList">
<plugin disabled="false" name="BA_BPriceLayeredNav_Layer_FilterList" sortOrder="10" type="BA\BNav\Plugin\Frontend\Magento\Catalog\Model\Layer\FilterList"/>
</type>
</config>
app/code/BA/BNav/Plugin/Frontend/Magento/Catalog/Model/Layer/FilterList.php
<?php
namespace BA\BNav\Plugin\Frontend\Magento\Catalog\Model\Layer;
class FilterList
{
const CUSTOM_PRICE = 'custom_price';
protected $filterTypes = [
self::CUSTOM_PRICE => \BA\BasysPriceLayeredNav\Model\Layer\Filter\CustomPrice::class,
];
public function __construct(
\Magento\Framework\ObjectManagerInterface $objectManager
) {
$this->objectManager = $objectManager;
}
public function afterGetFilters(
\Magento\Catalog\Model\Layer\FilterList $subject,
$result,
$layer
) {
$result[] = $this->objectManager->create($this->filterTypes[self::CUSTOM_PRICE], ['layer' => $layer]);
return $result;
}
}
app/code/BA/BNav/Model/Layer/Filter/CustomPrice.php
<?php
namespace BA\BNav\Model\Layer\Filter;
use Psr\Log\LoggerInterface;
class CustomPrice extends \Magento\Catalog\Model\Layer\Filter\AbstractFilter
{
/**
* @var \Psr\Log\LoggerInterface
*/
protected $logger;
protected $resource;
protected $connection;
/**
* Construct
*
* @param \Magento\Catalog\Model\Layer\Filter\ItemFactory $filterItemFactory
* @param \Magento\Store\Model\StoreManagerInterface $storeManager
* @param \Magento\Catalog\Model\Layer $layer
* @param \Magento\Catalog\Model\Layer\Filter\Item\DataBuilder $itemDataBuilder
* @param \Magento\Framework\Escaper $escaper
* @param CategoryFactory $categoryDataProviderFactory
* @param array $data
*/
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\Pricing\PriceCurrencyInterface $priceCurrency,
array $data = [],
LoggerInterface $logger,
\Magento\Framework\App\ResourceConnection $resource
) {
parent::__construct($filterItemFactory, $storeManager, $layer, $itemDataBuilder, $data);
$this->_requestVar = 'ba_price';
$this->logger = $logger;
$this->resource = $resource;
$this->priceCurrency = $priceCurrency;
}
/**
* Apply category filter to layer
*
* @param \Magento\Framework\App\RequestInterface $request
* @return $this
*/
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()
->join(['mapp'=>'ba__product_map'], 'e.entity_id = mapp.entity_id')
->join(['productprice'=>'ba__product_price'], 'productprice.basys_id = mapp.basys_id')
->where('productprice.catalog_id = 1462')
->where('productprice.price >= ?', $from)
->where('productprice.price <= ?', $to);
$this->logger->info($collection->getSelect()->__toString());
$this->getLayer()
->getState()
->addFilter(
$this->_createItem($this->_renderRangeLabel(empty($from) ? 0 : $from, $to), $filter)
);
return $this;
}
/**
* Get filter name
*
* @return \Magento\Framework\Phrase
*/
public function getName()
{
return __('Custom Price');
}
/**
* Prepare text of range label
*
* @param float|string $fromPrice
* @param float|string $toPrice
* @return float|\Magento\Framework\Phrase
*/
protected function _renderRangeLabel($fromPrice, $toPrice)
{
$formattedFromPrice = $this->priceCurrency->format($fromPrice);
if ($toPrice === '') {
return __('%1 and above', $formattedFromPrice);
} else {
return __('%1 - %2', $formattedFromPrice, $this->priceCurrency->format($toPrice));
}
}
/**
* Get data array for building category filter items
*
* @return array
*/
protected function _getItemsData()
{
$ranges = [
'0-4.99'=>'£0 - £4.99',
'5-9.99'=>'£5 - £9.99',
'10-20'=>'£10 - £20'
];
$this->connection = $this->resource->getConnection();
foreach ($ranges as $key => $label) {
$count = $this->prepareData($key);
$this->itemDataBuilder->addItemData(
$label,
$key,
$count
);
}
return $this->itemDataBuilder->build();
}
private function prepareData($filter)
{
$filter = explode('-', $filter);
list($from, $to) = $filter;
$query = $this->connection->fetchAll('SELECT * FROM catalog_product_entity
WHERE price BETWEEN '.$from.' and '.$to);
return count($query);
}
}
protected function _getItemsData()
{
$s1='<div class="rating-summary" style="display: inline-block;margin-top: -5px;">
<div class="rating-result" title="20%">
<span style="width:20%"><span>1</span></span>
</div>
</div>';
$s2='<div class="rating-summary" style="display: inline-block;margin-top: -5px;">
<div class="rating-result" title="40%">
<span style="width:40%"><span>2</span></span>
</div>
</div>';
$s3='<div class="rating-summary" style="display: inline-block;margin-top: -5px;">
<div class="rating-result" title="60%">
<span style="width:60%"><span>3</span></span>
</div>
</div>';
$s4='<div class="rating-summary" style="display: inline-block;margin-top: -5px;">
<div class="rating-result" title="80%">
<span style="width:80%"><span>4</span></span>
</div>
</div>';
$s5='<div class="rating-summary" style="display: inline-block;margin-top: -5px;">
<div class="rating-result" title="100%">
<span style="width:100%"><span>5</span></span>
</div>
</div>';
$facets = array(
'0-20'=>$s1,
'21-40'=>$s2,
'41-60'=>$s3,
'61-80'=>$s4,
'81-100'=>$s5,
);
$data = [];
if (count($facets) > 1) { // two range minimum
$i=1;
foreach ($facets as $key => $label) {
// $count=$this->prepareData($key,$collection,$i);
$count='';
$filter = explode('-', $key);
list($from, $to) = $filter;
//$collection = $this->getLayer()->getProductCollection();
$collection= $this->getLayer()->getCurrentCategory()->getProductCollection();
$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');
// $collection->getSelect()->from('rating_option_vote_aggregated')->where("rating_option_vote_aggregated.percent between".$from."and".$to);
//echo $collection->getSelect()->__toString();die;
// $this->getLayer()->getState()->addFilter($this->_createItem($collection, $filter));
$count = $collection->count();
$i++;
// echo $count;
if($count > 0){
$this->itemDataBuilder->addItemData(
//$this->_escaper->escapeHtml($label),
$label,
$key,
$count
);
$count=0;
}
}
}
return $this->itemDataBuilder->build();
/* $this->itemDataBuilder->addItemData(
$this->tagFilter->filter('5 star'),
'80-100',
1
);
return $this->itemDataBuilder->build(); */
}