5

We need to bring most viewed, most subscribed and latest options in the sort menu in product listing page of our magento 2.1 application (magento 2.1.7). I already refered the this link Product List Page Sort by Most View ( can we sort this by page views/hits). As this is for magento 1, most of the classes like Mage is not available in my magento 2.1 app.

Kindly share your suggestions to implement this in magento 2.1 application using code.

3

If you want to add option in the sort menu then you need to create a plugin as I achieved

1) create di.xml file and the below code

<?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="add_custom_sort" type="Test\MyMagento\Plugin\Catalog\CustomSort" sortOrder="10"/>
    </type>

</config>

2) create CustomSort.php file and the bleow code

<?php
namespace Test\MyMagento\Plugin\Catalog;

class CustomSort
{

    public function afterGetAttributeUsedForSortByArray(
    \Magento\Catalog\Model\Config $catalogConfig,
    $options
) {

    $options['mostviewd'] = __('Mostveiwd');
    return $options;

 }

}
2

None of these answers are good. Here is the right way to do it, tested with Magento 2.3:

1) You need to create two plugins. One that will add the "Most Viewed" filter as an option in the Sort By dropdown of the category view page and another one that will be processed after the setCollection() method of Magento\Catalog\Block\Product\ProductList\Toolbar which will be responsible for the actual sorting.

To do so, first declare the plugin in the di.xml file of your module: [Vendor]/[ModuleName]/etc/frontend/di.xml

<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="sortby_add_custom_option" type="[Vendor]\[ModuleName]\Plugin\Model\Config" />
    </type>
    <type name="Magento\Catalog\Block\Product\ProductList\Toolbar">
        <plugin name="sortby_extend_default_sort_filters" type="[Vendor]\[ModuleName]\Plugin\Block\Toolbar" />
    </type>
</config>

2) Now create the first plugin file:

[Vendor]\[ModuleName]\Plugin\Model\Config.php:

<?php
namespace [Vendor]\[ModuleName]\Plugin\Model;

class Config
{
    /**
     * Add custom Sort By option
     *
     * @param \Magento\Catalog\Model\Config $catalogConfig
     * @param array $options
     * @return array []
     * @SuppressWarnings(PHPMD.UnusedFormalParameter)
     */
    public function afterGetAttributeUsedForSortByArray(\Magento\Catalog\Model\Config $catalogConfig, $options)
    {
        // new sorting option
        $customOption['most_viewed'] = __('Most Viewed');

        // merge default sorting options with custom options
        $options = array_merge($customOption, $options);

        return $options;
    }

    /**
     * This method is optional. Use it to set Most Viewed as the default
     * sorting option in the category view page
     *
     * @param \Magento\Catalog\Model\Config $catalogConfig
     * @return string
     * @SuppressWarnings(PHPMD.UnusedFormalParameter)
     */
    public function afterGetProductListDefaultSortBy(\Magento\Catalog\Model\Config $catalogConfig)
    {
        return 'most_viewed';
    }
}

3) And now the second plugin file: [Vendor]\[ModuleName]\Plugin\Block\Toolbar.php:

<?php
namespace [Vendor]\[ModuleName]\Plugin\Block;

use Magento\Framework\App\ResourceConnection;
use Magento\Framework\DB\Select;

/**
 * Product list toolbar plugin
 */
class Toolbar
{
    const SORT_ORDER_DESC = 'DESC';

    /**
     * @var \Magento\Framework\Model\ResourceModel\Db\Collection\AbstractCollection
     */
    protected $_collection = null;

    /**
     * DB connection
     *
     * @var \Magento\Framework\DB\Adapter\AdapterInterface
     */
    protected $_conn;

    /**
     * @var boolean
     */
    protected $_subQueryApplied = false;

    /**
     * Constructor
     *
     * @param \Magento\Framework\App\ResourceConnection $resource
     */
    public function __construct(ResourceConnection $resource)
    {
        $this->_conn = $resource->getConnection('catalog');
    }

    /**
     * Plugin - Used to modify default Sort By filters
     *
     * @param \Magento\Catalog\Block\Product\ProductList\Toolbar $subject
     * @param null $result
     * @param \Magento\Framework\Data\Collection $collection
     * @return Toolbar
     * @SuppressWarnings(PHPMD.UnusedFormalParameter)
     */
    public function afterSetCollection(\Magento\Catalog\Block\Product\ProductList\Toolbar $subject,
        $result,
        $collection
    ) {
        $this->_collection = $collection;

        if ($subject->getCurrentOrder() == 'most_viewed') {
            if (!$this->_subQueryApplied) {
                $reportEventTable = $this->_collection->getResource()->getTable('report_event');
                $subSelect = $this->_conn->select()->from(
                    ['report_event_table' => $reportEventTable],
                    'COUNT(report_event_table.event_id)'
                )->where(
                    'report_event_table.object_id = e.entity_id'
                );

                $this->_collection->getSelect()->reset(Select::ORDER)->columns(
                    ['views' => $subSelect]
                )->order(
                    'views '  . self::SORT_ORDER_DESC
                );

                $this->_subQueryApplied = true;
            }
        }

        return $this;
    }
}

That’s it. Enjoy!

3
  • Thank you so much for correct me. It's working perfectly. Feb 18 '19 at 12:23
  • Hi, while using your way, getting error Exception #0 (Exception): Notice: Undefined variable: reportEventTable on Toolbar.php on line 60. Please help with the solution.
    – Udit Gupta
    Feb 19 '19 at 7:33
  • Hi @UditGupta, I edited the answer to correct a typo in the variable name. Sorry about that. Feb 19 '19 at 11:13
-1

I got the solution:

1) override the Magento\Catalog\Block\Product\ProductList\Toolbar

(Refer here to override the block in magento 2 : https://webkul.com/blog/overriding-rewriting-classes-magento2/)

And then need to copy all contents from Magento\Catalog\Block\Product\ProductList\Toolbar to our new class. Then

2) Open our new overrided class (for me it is Webkul\Catalog\Block\Rewrite\Product\ProductList\Toolbar), go to getAvailableOrders() then add these codes there:

 $this->addOrderToAvailableOrders('mostviewd', 'MOST POPULAR');
    $this->addOrderToAvailableOrders('mostsold', 'MOST SOLD');
    $this->addOrderToAvailableOrders('latest', 'LATEST');

By adding this, we can get these sort params in $block->getAvailableOrders() in ...\Magento_Catalog\templates\product\list\toolbar\sorter.phtml

3) Modify setCollection() function:

---------------------------
  if ($this->getCurrentOrder()) {
        if($this->getCurrentOrder()=='mostviewd') {
           // echo 'if'; die;
            $this->_collection->getSelect()->
            joinInner('report_event AS _table_views',
                ' _table_views.object_id = e.entity_id',
                'COUNT(_table_views.event_id) AS views')->
            group('e.entity_id')->order('views DESC');
        }
        else if($this->getCurrentOrder()=='mostsold') {
            $this->getCollection()->getSelect()
                ->joinLeft(
                    array('order_items' => $collection->getResource()->getTable('sales_order_item')),
                    'order_items.product_id = e.entity_id',
                    array('qty_ordered' => 'SUM(order_items.qty_ordered)')
                )
                ->group('e.entity_id')
                ->order('qty_ordered DESC');
        }
        else if($this->getCurrentOrder()=='latest') {
            $this->_collection->setOrder('entity_id', 'desc');
        }

        else{

            $this->_collection->setOrder($this->getCurrentOrder(), $this->getCurrentDirection());
        }
      ................

Then manage your sorter.phtml to show the sort option. Thats it. Hope it will help someone else. :)

2
  • The result is perfect but in the toolbar there is showing only 1 item and pagination is not displayed. Can anyone face this type of issue? Appreciate in advance. Feb 12 '19 at 12:41
  • @KartikAsodariya using a joinLeft() with a group() is the culprit. Not to mention that overwriting the Toolbar block via preference is NOT a good practice. We should use a plugin for that. See my answer for an alternative way to achieve it using a plugin and without messing the layered navigation and pagination. Feb 17 '19 at 12:50

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.