The question:
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.
The Solutions:
Below are the methods you can try. The first solution is probably the best. Try others if the first one doesn’t work. Senior developers aren’t just copying/pasting – they read the methods carefully & apply them wisely to each case.
Method 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="MagentoCatalogModelConfig">
<plugin name="add_custom_sort" type="TestMyMagentoPluginCatalogCustomSort" sortOrder="10"/>
</type>
</config>
2) create CustomSort.php
file and the bleow code
<?php
namespace TestMyMagentoPluginCatalog;
class CustomSort
{
public function afterGetAttributeUsedForSortByArray(
MagentoCatalogModelConfig $catalogConfig,
$options
) {
$options['mostviewd'] = __('Mostveiwd');
return $options;
}
}
Method 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 MagentoCatalogBlockProductProductListToolbar
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="MagentoCatalogModelConfig">
<plugin name="sortby_add_custom_option" type="[Vendor][ModuleName]PluginModelConfig" />
</type>
<type name="MagentoCatalogBlockProductProductListToolbar">
<plugin name="sortby_extend_default_sort_filters" type="[Vendor][ModuleName]PluginBlockToolbar" />
</type>
</config>
2) Now create the first plugin file:
[Vendor][ModuleName]PluginModelConfig.php
:
<?php
namespace [Vendor][ModuleName]PluginModel;
class Config
{
/**
* Add custom Sort By option
*
* @param MagentoCatalogModelConfig $catalogConfig
* @param array $options
* @return array []
* @SuppressWarnings(PHPMD.UnusedFormalParameter)
*/
public function afterGetAttributeUsedForSortByArray(MagentoCatalogModelConfig $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 MagentoCatalogModelConfig $catalogConfig
* @return string
* @SuppressWarnings(PHPMD.UnusedFormalParameter)
*/
public function afterGetProductListDefaultSortBy(MagentoCatalogModelConfig $catalogConfig)
{
return 'most_viewed';
}
}
3) And now the second plugin file:
[Vendor][ModuleName]PluginBlockToolbar.php
:
<?php
namespace [Vendor][ModuleName]PluginBlock;
use MagentoFrameworkAppResourceConnection;
use MagentoFrameworkDBSelect;
/**
* Product list toolbar plugin
*/
class Toolbar
{
const SORT_ORDER_DESC = 'DESC';
/**
* @var MagentoFrameworkModelResourceModelDbCollectionAbstractCollection
*/
protected $_collection = null;
/**
* DB connection
*
* @var MagentoFrameworkDBAdapterAdapterInterface
*/
protected $_conn;
/**
* @var boolean
*/
protected $_subQueryApplied = false;
/**
* Constructor
*
* @param MagentoFrameworkAppResourceConnection $resource
*/
public function __construct(ResourceConnection $resource)
{
$this->_conn = $resource->getConnection('catalog');
}
/**
* Plugin - Used to modify default Sort By filters
*
* @param MagentoCatalogBlockProductProductListToolbar $subject
* @param null $result
* @param MagentoFrameworkDataCollection $collection
* @return Toolbar
* @SuppressWarnings(PHPMD.UnusedFormalParameter)
*/
public function afterSetCollection(MagentoCatalogBlockProductProductListToolbar $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!
Method 3
I got the solution:
1) override the MagentoCatalogBlockProductProductListToolbar
(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 MagentoCatalogBlockProductProductListToolbar to our new class. Then
2) Open our new overrided class (for me it is WebkulCatalogBlockRewriteProductProductListToolbar)
, 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_Catalogtemplatesproductlisttoolbarsorter.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. 🙂
All methods was sourced from stackoverflow.com or stackexchange.com, is licensed under cc by-sa 2.5, cc by-sa 3.0 and cc by-sa 4.0