Product List Page Sort by Most View in magento 2.1

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;

 }

}

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!