Skip to content

Magento2.4: How to Sort Product by ” Best Selling ” and ” Best reviewed ” Product?

I want to add custom sort options like ” Best Selling ” and ” Best reviewed “ in Catalog/Category sort order options
Below is the picture.
enter image description here

and i am trying this approach in below code but its not working.

etc/di.xml

<?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="MagentoVisualMerchandiserModelSorting">
        <plugin name="RLTSquare_VisualMerchandiser_Plugin_VisualMerchandiser_Model_SortingPlugin"
                type="RLTSquareVisualMerchandiserPluginVisualMerchandiserModelSortingPlugin" sortOrder="10"/>
    </type>
</config>

RLTSquareVisualMerchandiserPluginVisualMerchandiserModelSortingPlugin.php

<?php
declare(strict_types=1);

namespace RLTSquareVisualMerchandiserPluginVisualMerchandiserModel;

use RLTSquareVisualMerchandiserModelVisualMerchandiserSortingDateBottom;
use RLTSquareVisualMerchandiserModelVisualMerchandiserSortingDateTop;
use RLTSquareVisualMerchandiserModelVisualMerchandiserSortingBestSelling;
use RLTSquareVisualMerchandiserModelVisualMerchandiserSortingMostPopular;
use RLTSquareVisualMerchandiserModelVisualMerchandiserSortingDiscountTop;

use MagentoVisualMerchandiserModelSorting;
use MagentoVisualMerchandiserModelSortingSortInterface;

class SortingPlugin
{
    /**
     * @var SortInterface[]
     */
    protected array $sortingOptions = [];

    /**
     * @param DateBottom $dateBottom
     * @param DateTop $dateTop
     * @param BestSelling $bestSelling
     * @param MostPopular $mostPopular
     * @param DiscountTop $discountTop
     */
    public function __construct(
        DateBottom $dateBottom,
        DateTop $dateTop,
        BestSelling $bestSelling,
        MostPopular $mostPopular,
        DiscountTop $discountTop
    ) {
        $this->sortingOptions[20] = $dateBottom;
        $this->sortingOptions[21] = $dateTop;
        $this->sortingOptions[22] = $bestSelling;
        $this->sortingOptions[23]= $mostPopular;
        $this->sortingOptions[24]= $discountTop;
    }

    /**
     * @param Sorting $subject
     * @param array $result
     * @return array
     */
    public function afterGetSortingOptions(Sorting $subject, array $result): array
    {
        foreach ($this->sortingOptions as $idx => $instance) {
            $result[$idx] = $instance->getLabel();
        }

        return $result;
    }

    /**
     * @param Sorting $subject
     * @param callable $callback
     * @param $sortOption
     * @return SortInterface
     */
    public function aroundGetSortingInstance(Sorting $subject, callable $callback, $sortOption): SortInterface
    {
        if (isset($this->sortingOptions[$sortOption])) {
            return $this->sortingOptions[$sortOption];
        }

        return $callback($sortOption);
    }
}

RLTSquareVisualMerchandiserModelVisualMerchandiserSortingBestSelling.php

<?php

namespace RLTSquareVisualMerchandiserModelVisualMerchandiserSorting;

use MagentoCatalogModelResourceModelProductCollection;
use MagentoFrameworkDataCollection as CollectionAlias;
use MagentoVisualMerchandiserModelSortingSortAbstract;
use MagentoVisualMerchandiserModelSortingSortInterface;
use Zend_Db_Select;

class BestSelling extends SortAbstract implements SortInterface
{
    /**
     * @param Collection $collection
     * @return Collection
     */
    public function sort(
        Collection $collection
    ): Collection {
       $collection->getSelect()->joinLeft(
            'sales_order_item',
            'entity_id=sales_order_item.product_id',
            array('qty_ordered'=>'SUM(sales_order_item.qty_ordered)'))
            ->group('entity_id');
        $collection->getSelect()
            ->reset(Zend_Db_Select::ORDER)
            ->order('qty_ordered'.CollectionAlias::SORT_ORDER_DESC);
        return $collection;
    }

    /**
     * @return string
     */
    public function getLabel(): string
    {
        return __("Best Selling");
    }
}

RLTSquareVisualMerchandiserModelVisualMerchandiserSortingMostPopular.php

<?php

namespace RLTSquareVisualMerchandiserModelVisualMerchandiserSorting;

use MagentoCatalogModelResourceModelProductCollection;
use MagentoFrameworkDataCollection as CollectionAlias;
use MagentoVisualMerchandiserModelSortingSortAbstract;
use MagentoVisualMerchandiserModelSortingSortInterface;
use Zend_Db_Select;

class MostPopular extends SortAbstract implements SortInterface
{

    /**
     * @param Collection $collection
     * @return Collection
     */
    public function sort(
        Collection $collection
    ): Collection {
        $collection->getSelect()->joinLeft(
            ['rating_vote'=>$collection->getTable('rating_option_vote')],
            'rating_vote.review_id=main_table.review_id',
           ['sum'=>'SUM(percent)','count'=>'COUNT(*)','average'=>'SUM(percent)']);
        $collection->getSelect()
            ->reset(Zend_Db_Select::ORDER)
            ->group('rating_vote.review_id')
            ->order('average'.CollectionAlias::SORT_ORDER_DESC);
        return $collection;
    }
        /**
         * @return string
         */
        public function getLabel(): string
        {
            return __("Most Populars");
        }
}

but the above logic doest sort grid in picture above, any idea what am i doing wrong?
Thanks in advance