4

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 – user39839 May 17 '16 at 3:23
  • Can we implement this with AJAX ? I need to implement filter in magento 2 with AJAX – manpreet Jun 25 '16 at 13:18
8

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 <core@magentocommerce.com>
 */
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

| improve this answer | |
  • 1
    @pradeepkumar Filter is working fine but paging is not working.. – zed Blackbeard Nov 3 '16 at 12:26
  • Hi zed Blackbeard same issue here plz share solution – Nikhil Vaghela Nov 8 '16 at 9:04
  • Is there any have paginatoin solution – Nikhil Vaghela Nov 8 '16 at 9:05
  • 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 – Menno Jan 13 '17 at 9:10
  • 1
    Can anyone give me suggestion to add discount filter with percentage and in range? – Magecode Sep 13 '17 at 10:49
0
 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(); */
}
| improve this answer | |
0

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);
    }
}
| improve this answer | |

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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