1

Add rating tab in layered navigation in magento 2

I want override Magento\Catalog\Model\Layer\FilterList to Vender\Modulename\Model\Layer\FilterList

<preference for="Magento\Catalog\Model\Layer\FilterList" type="Vender\Modulename\Model\Layer\FilterList" />

But it's not working

Magento 2 : Rating Filter in Layered Navigation

also try to above link it's working fine but how to implement in our module b'coz it's core file

Can anyone give me suggestion.

3 Answers 3

1

in app/code/Vender/Modulename/etc/di.xml

<type name="Magento\Catalog\Model\Layer\FilterList">
        <plugin name="filterlist" type="Vender\Modulename\Model\Layer\FilterList"/>
</type>

app/code/Vender/Modulename/Model/Layer/FilterList.php

<?php
/**
 * Copyright © 2016 Magento. All rights reserved.
 * See COPYING.txt for license details.
 */

namespace Vender\Modulename\Model\Layer;


    class FilterList 
    {


        public function __construct(
            \Magento\Catalog\Block\Product\Context $context,
            \Magento\Framework\ObjectManagerInterface $objectManager


        ) {
            $this->objectManager = $objectManager;                  

        }


        public function aroundGetFilters( \Magento\Catalog\Model\Layer\FilterList $subject, \Closure $proceed, \Magento\Catalog\Model\Layer $layer)
        {


            $result = $proceed($layer);
            $result[] = $this->objectManager->create('Vender\Modulename\Model\Layer\Filter\Rating', ['layer' => $layer]);

            return $result;

        }


    }
    ?>

app/code/Vender/Modulename/Model/Layer/Filter/Rating.php

<?php
/**
 * Copyright © 2015 Magento. All rights reserved.
 * See COPYING.txt for license details.
 */

namespace Vender/Modulename\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,
        \Magento\Framework\ObjectManagerInterface $objectManager,
        \Magento\Catalog\Model\Product $productModel,
        \Magento\Catalog\Model\Product\Attribute\Source\Status $productStatus,
        \Magento\Catalog\Model\Product\Visibility $productVisibility,
        array $data = []
    ) {
        parent::__construct($filterItemFactory, $storeManager, $layer, $itemDataBuilder, $data);
        $this->_escaper = $escaper;
        $this->objectManager = $objectManager; 
        $this->_productModel = $productModel;
        $this->productStatus = $productStatus;
        $this->productVisibility = $productVisibility;
        $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()
    {
        $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->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'); 

            $count=count($collection);



               $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(); */
    }
    /**
     * @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();
    }
}
?>
3
  • count is not working how to add custom select query for get count value Oct 7, 2016 at 14:08
  • Thanks @john but count and pagination not working except working good:) Jan 13, 2017 at 9:21
  • count is not working.any ideas?
    – Liz Eipe C
    Oct 29, 2020 at 23:51
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(); */
}
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_BasysPriceLayeredNav_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\BasysPriceLayeredNav\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'=>'catalog_product_map'], 'e.entity_id = mapp.entity_id')
        ->join(['productprice'=>'catalog_product_price'], 'productprice.b_id = mapp.b_id')
        ->where('productprice.price BETWEEN '.$from.' and '.$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);
    }
}

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

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