How to Add Magento 2 Sort & Filter by Rating

How to Add Magento 2 Sort and Filter by Rating

It is essential for eCommerce stores to provide an effective sorting and filtering system, as it improves navigation and user experience on the website. Magento 2, by default, offers sorting only by Price, Position, and Product Name, but sometimes, this isn’t enough.

In this article, we will explore an option that can enhance the navigational functionality – sorting products by rating. This allows users to sort products based on the experiences of other buyers, which significantly increases confidence and speeds up the purchase decision.

There are two approaches how to add Magento 2 sort by rating functionality:

  1. Creating a custom plugin (for developers). This approach enhances your default sorting functionality, but it involves coding and familiarity with Magento 2 development.
  1. Using Magento 2 Layered Navigation extension.

Let’s explore these approaches deeper.

Enable Magento 2 Sort by Rating with a Custom Plugin

To add the “Rating” option to the default sorting functionality, we need to create a custom extension and plugins that modify its behavior. Follow the steps in this section to get everything done correctly.

Step 1 – Create a Magento 2 basic extension

This step explains how to set up the basic structure for your custom module. You need to create two files:

  1. app/code/VendorName/ModuleName/etc/module.xml – This file defines the module name and any dependencies it has on other modules. Add the following code to the file:
<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Module/etc/module.xsd">
     <module name="VendorName_ModuleName">
         <sequence>
             <module name="Magento_Catalog"/>
         </sequence>
     </module>
</config>
  1. app/code/VendorName/ModuleName/registration.php – This file registers the module with Magento.
<?php

\Magento\Framework\Component\ComponentRegistrar::register(
    \Magento\Framework\Component\ComponentRegistrar::MODULE,
    'VendorName_ModuleName',
    __DIR__
);

Step 2 – Create a plugin for the class Magento\Catalog\Model\Config

Plugins are a powerful way to extend the functionality of existing Magento classes without modifying the core code. In this step, you’re creating a plugin that modifies the get
AttributeUsedForSortByArray method of the Magento\Catalog\Model\Config class. In other words, this plugin displays a “Rating” option on the category page toolbar in Magento 2.

  1. Declare a plugin in the
    app/code/VendorName/ModuleName/etc/frontend/di.xml file
<?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\Config">
        <plugin
            name="vendor_catalog_config_plugin"
            type="VendorName\ModuleName\Plugin\Catalog\Model\Config" />
    </type>
</config>
  1. Create plugin class
    app/code/VendorName/ModuleName/Plugin/Catalog/Model/Config.php
<?php

namespace VendorName\ModuleName\Plugin\Catalog\Model;

class Config
{
    public function afterGetAttributeUsedForSortByArray(\Magento\Catalog\Model\Config $subject, $result)
    {
        $ratingField['rating'] = __("Rating");
        $result = array_merge($result, $ratingField);

        return $result;
    }
}
Enable Magento 2 Sort by Rating with a Custom Plugin — step 2

Step 3 – Create a plugin for the class Magento\Catalog\Model\Config\Source\ListSort

Following the same logic, you need to create plugins for different classes to add the “Rating” option for sorting in different locations.

In this step, let’s create a plugin that displays a “Rating” option in the global configuration: Stores -> Configuration -> Catalog -> Catalog -> Storefront -> Product Listing Sort by.

  1. Declare plugin in the
    app/code/VendorName/ModuleName/etc/adminhtml/di.xml file.
<?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\Config\Source\ListSort">
        <plugin
            name="vendor_catalog_list_sort_plugin"
            type="VendorName\ModuleName\Plugin\Catalog\Model\Config\Source\ListSort" />
    </type>
</config>
  1. Create plugin class
    app/code/VendorName/ModuleName/Plugin/Catalog/Model/Config/Source/ListSort.php
<?php

namespace VendorName\ModuleName\Plugin\Catalog\Model\Config\Source;

class ListSort
{
    public function afterToOptionArray(\Magento\Catalog\Model\Config\Source\ListSort $subject, $result)
    {
        $result[] = ['label' => __("Rating"), 'value' => "rating"];

        return $result;
    }
}
Enable Magento 2 Sort by Rating with a Custom Plugin — step 3

Step 4 – Create a plugin for the class Magento\Catalog\Model\Category\Attribute\Source\Sortby

Next, you need to create a plugin to display a “Rating” option on the category level: Catalog -> Categories -> Select the Category to configure -> Display Settings -> Default Product Listing Sort By.

  1. Declare plugin in the
    app/code/VendorName/ModuleName/etc/adminhtml/di.xml file.
<?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\Config\Source\ListSort">
        <plugin
            name="vendor_catalog_list_sort_plugin"
            type="VendorName\ModuleName\Plugin\Catalog\Model\Config\Source\ListSort" />
    </type>
    <type name="Magento\Catalog\Model\Category\Attribute\Source\Sortby">
        <plugin
            name="vendor_catalog_category_list_sort_plugin"
            type="VendorName\ModuleName\Plugin\Catalog\Model\Category\Attribute\Source\Sortby" />
    </type>
</config>
  1. Create plugin class app/code/VendorName/ModuleName/Plugin/Catalog/Model/Category/Attribute/Source/Sortby.php
<?php

namespace VendorName\ModuleName\Plugin\Catalog\Model\Category\Attribute\Source;

class Sortby
{
    public function afterGetAllOptions(\Magento\Catalog\Model\Category\Attribute\Source\Sortby $subject, $result)
    {
        $result[] = ['label' => __("Rating"), 'value' => "rating"];

        return $result;
    }
}
Enable Magento 2 Sort by Rating with a Custom Plugin — step 4

Step 5 – Add a rating field to the Elasticsearch index

By default, Magento uses Elasticsearch for product search. In this step, we need to provide rating data for products being indexed in Elasticsearch and define a new “rating” field for the Elasticsearch index.

  1. Create class
    app/code/VendorName/ModuleName/Model/Adapter/BatchDataMapper/RatingProvider.php to add rating data to Elasticsearch.
<?php

namespace VendorName\ModuleName\Model\Adapter\BatchDataMapper;

use Magento\AdvancedSearch\Model\Adapter\DataMapper\AdditionalFieldsProviderInterface;
use Magento\Framework\App\ResourceConnection;

class RatingProvider implements AdditionalFieldsProviderInterface
{
    private $resourceConnection;

    public function __construct(ResourceConnection $resourceConnection)
    {
        $this->resourceConnection = $resourceConnection;
    }

    public function getFields(array $productIds, $storeId)
    {
        $ratings = $this->getRatings($productIds, (int) $storeId);

        $fields = [];

        foreach ($productIds as $productId) {
            $productRating = $ratings[$productId] ?? 0;
            $fields[$productId] = ["rating" => $productRating];
        }

        return $fields;
    }

    private function getRatings($productIds, $storeId)
    {
        $connection = $this->resourceConnection->getConnection();
        $select = $connection
            ->select()
            ->from(
                ['main_table' => $connection->getTableName('review_entity_summary')],
                ['entity_pk_value', 'rating_summary']
            )
            ->where('main_table.store_id = ?', $storeId)
            ->order('entity_pk_value');

         if ($productIds) {
             $select->where('main_table.entity_pk_value IN(?)', $productIds);
         }

         return $connection->fetchPairs($select) ?: [];
    }
}
  1. Create class
    app/code/VendorName/ModuleName/Model/Elasticsearch/Adapter/FieldMapper to add a rating field to the Elasticsearch index.
<?php
namespace VendorName\ModuleName\Model\Elasticsearch\Adapter\FieldMapper;

use Magento\Elasticsearch\Model\Adapter\FieldMapper\Product\FieldProvider\FieldType\ConverterInterface;
use Magento\Elasticsearch\Model\Adapter\FieldMapper\Product\FieldProviderInterface;


class RatingField implements FieldProviderInterface
{
    private $fieldTypeConverter;


    public function __construct(
        ConverterInterface $fieldTypeConverter
    ) {
        $this->fieldTypeConverter = $fieldTypeConverter;
    }

    public function getFields(array $context = []): array
    {
        return [
            'rating' => [
                'type' => $this->fieldTypeConverter->convert(ConverterInterface::INTERNAL_DATA_TYPE_INT)
            ]
        ];
    }
}
  1. Declare the new “Rating” field in the app/code/VendorName/ModuleName/etc/di.xml file for the Elasticsearch index.
<?xml version="1.0"?>

<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd">
    <virtualType name="additionalFieldsProviderForElasticsearch" type="Magento\AdvancedSearch\Model\Adapter\DataMapper\AdditionalFieldsProvider">
       <arguments>
           <argument name="fieldsProviders" xsi:type="array">
               <item name="rating" xsi:type="object">VendorName\ModuleName\Model\Adapter\BatchDataMapper\RatingProvider</item>
           </argument>
       </arguments>
   </virtualType>

   <type name="Magento\Elasticsearch\Model\Adapter\FieldMapper\Product\CompositeFieldProvider">
       <arguments>
           <argument name="providers" xsi:type="array">
               <item name="rating_sort" xsi:type="object">VendorName\ModuleName\Model\Elasticsearch\Adapter\FieldMapper\RatingField</item>
           </argument>
       </arguments>
   </type>
</config>

Step 6 – Create a plugin for the class Magento\Catalog\Block\Product\ProductList\Toolbar

In this step, you will create a plugin to modify the product collection used for displaying product lists. It checks if the current sort order is “rating”. If yes, it joins the “review_entity_summary” table to the product collection and sorts by the “rating_summary” field.

  1. Declare plugin in the app/code/VendorName/ModuleName/etc/di.xml file.
<?xml version="1.0"?>

<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd">
    <virtualType name="additionalFieldsProviderForElasticsearch" type="Magento\AdvancedSearch\Model\Adapter\DataMapper\AdditionalFieldsProvider">
       <arguments>
           <argument name="fieldsProviders" xsi:type="array">
               <item name="rating" xsi:type="object">VendorName\ModuleName\Model\Adapter\BatchDataMapper\RatingProvider</item>
           </argument>
       </arguments>
   </virtualType>

   <type name="Magento\Elasticsearch\Model\Adapter\FieldMapper\Product\CompositeFieldProvider">
       <arguments>
           <argument name="providers" xsi:type="array">
               <item name="rating_sort" xsi:type="object">VendorName\ModuleName\Model\Elasticsearch\Adapter\FieldMapper\RatingField</item>
           </argument>
       </arguments>
   </type>
   <type name="Magento\Catalog\Block\Product\ProductList\Toolbar">
       <plugin name="vendor_catalog_toolbar_plugin" type="VendorName\ModuleName\Plugin\Catalog\Block\Product\ProductList\Toolbar" />
   </type>
</config>
  1. Create plugin class app/code/VendorName/ModuleName/Plugin/Catalog/Block/Product/ProductList/Toolbar.php
<?php

namespace VendorName\ModuleName\Plugin\Catalog\Block\Product\ProductList;

class Toolbar
{
    public function aroundSetCollection(
        \Magento\Catalog\Block\Product\ProductList\Toolbar $subject,
        \Closure $proceed,
        $collection
    ) {
        $currentOrder = $subject->getCurrentOrder();
        if ($currentOrder == "rating" ) {
            $dir = $subject->getCurrentDirection();
            $collection->getSelect()->joinLeft(
                ['review_entity_summary'],
                'e.entity_id = review_entity_summary.entity_pk_value AND review_entity_summary.store_id = "' . $collection->getStoreId() . '"',
                [
                    'rating_summary',
                    'rating' => 'review_entity_summary.rating_summary'
                ]
            );
            $collection->setOrder($currentOrder, $dir);
        }

        return $proceed($collection);
    }
}

Step 7 – Install the Extension and Index the New Rating Field in Elasticsearch

Run the following commands to install the extension, compile the code, deploy static content, and reindex the Elasticsearch index to include the new “Rating” field.

php bin/magento setup:upgrade
php bin/magento setup:di:compile
php bin/magento setup:static-content:deploy
php bin/magento indexer:reindex catalogsearch_fulltext

How to Make “Rating” the Default Sort Option in Magento 2

After you add the Magento 2 sort products by rating feature, you can set it as the default option for sorting the product list. To do this, go to the global configurations under Stores -> Configuration -> Catalog -> Catalog -> Storefront -> Product Listing Sort by option.

How to Make “Rating” the Default Sort Option — global configurations

You can also configure the default sorting option at the category level. To do this, navigate to Catalog -> Categories -> select the required Category -> Display Settings -> Default Product Listing Sort By, and select “Rating”.

How to Make “Rating” the Default Sort Option — Catalog

Enable Magento 2 Filter By Rating with Layered Navigation Extension

Another way to allow customers to sort products by rating in Magento 2 is through the Layered Navigation Extension. While it doesn’t add the “Rating” option directly to the sorting functionality, it enhances Magento 2 navigation filters by adding new ones, including “Rating”. This greatly improves the default filtering functionality, allowing users to find the products they are looking for much faster.

Enable Magento 2 Filter By Rating with Layered Navigation Extension — Frontend

To add the Magento 2 rating filter to your website, you need to follow these steps:

Step-by-step guide:

  1. Get and install the Layered navigation extension.
  2. Enable the module. Once the layered navigation is installed, you need to enable it and configure the basic settings. Refer to user guides to install and configure it properly.
  3. Include “Rating” in Layered Navigation. In the “Attribute Filters” section of the same page, you have to locate the “Rating” filter in the “Attributes Used in Layered Navigation” column. That’s it.
Enable Magento 2 Filter By Rating with Layered Navigation Extension — Backend

Conclusion

Magento 2 is a flexible platform that allows flexible customization and new functionalities to be added. In this tutorial, we have provided two ways to add Magento 2 sort by rating feature.

The first option is to perform custom development to enhance the default Magento 2 sorting functionality with the new “rating” option. By following the detailed steps and using code snippets we provide, you can add not only the “rating” sorting option, but laso any others, such as “Newset”, “Best Seller”, “Most Viewed”, etc.

Also, you can extend the functionality by changing the default sort direction from ascending to descending order. In this case, products with the highest ratings will be shown first. To do this, you need to modify the plugin in step 6 and set the sort direction to DESC instead of using the current direction $dir.

The second option is to install the Layered Navigation extension to add the “Rating” filter quickly and effortlessly. The extension not only allows users to filter products by rating, but also offers other essential filters that help users significantly narrow down their search results and save time, leading to higher conversion rates.

With both custom development and the extension offering efficient solutions, you can empower your customers to sort and filter by ratings, ultimately increasing their satisfaction and boosting your store’s conversion rates.