Sorting and sort direction applied together

The question:

Is it possible to apply sorting option and direction at the same time, using sorting select box?

The sorting select box could have options like:

  • Price Asc
  • Price Desc
  • Position Asc
  • Position Desc
  • ..

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

You can follow the steps describe below to achieve this customization task.

I assume you are using a custom theme “Vendor_theme” .

step 1) create the file sorter.phtml

under

/app/design/frontend/Vendor/theme/Magento_Catalog/templates/product/list/toolbar

File : sorter.phtml

<?php
/**
 * Copyright © Magento, Inc. All rights reserved.
 * See COPYING.txt for license details.
 */

// @codingStandardsIgnoreFile

?>
<?php
/**
 * Product list toolbar
 *
 * @var $block MagentoCatalogBlockProductProductListToolbar
 */
use MagentoCatalogModelProductProductListToolbar;
$currentDirection = $block->getCurrentDirection();
?>
<div class="toolbar-sorter sorter">
    <label class="sorter-label" for="sorter"><?= /* @escapeNotVerified */ __('Sort By') ?></label>
    <select id="sorter" data-role="sorter" class="sorter-options">
        <?php foreach ($block->getAvailableOrders() as $_key => $_order): ?>
            <option value="<?= /* @escapeNotVerified */ $_key ?>&asc"
                <?php if ($block->isOrderCurrent($_key) && ($block->getCurrentDirection()=='asc' || $block->getCurrentDirection()=='' )): ?>
                    selected="selected"
                <?php endif; ?>
                >
                <?= $block->escapeHtml(__($_order)) ?> [ Asc ]
            </option>

            <option value="<?= /* @escapeNotVerified */ $_key ?>&desc"
                <?php if ($block->isOrderCurrent($_key) && $block->getCurrentDirection()=='desc'): ?>
                    selected="selected"
                <?php endif; ?>
                >
                <?= $block->escapeHtml(__($_order)) ?> [ Desc ]
            </option>


        <?php endforeach; ?>
    </select>
    <?php if ($block->getCurrentDirection() == 'desc'): ?>
        <a title="<?= /* @escapeNotVerified */ __('Set Ascending Direction') ?>" href="#" rel="nofollow noreferrer noopener" rel="nofollow noreferrer noopener" class="action sorter-action sort-desc" data-role="direction-switcher" data-value="asc">
            <span><?= /* @escapeNotVerified */ __('Set Ascending Direction') ?></span>
        </a>
    <?php else: ?>
        <a title="<?= /* @escapeNotVerified */ __('Set Descending Direction') ?>" href="#" rel="nofollow noreferrer noopener" rel="nofollow noreferrer noopener" class="action sorter-action sort-asc" data-role="direction-switcher" data-value="desc">
            <span><?= /* @escapeNotVerified */ __('Set Descending Direction') ?></span>
        </a>
    <?php endif; ?>
</div>

step 2: create the file requirejs-config.js

under

/app/design/frontend/Vendor/theme/Magento_Catalog

File : requirejs-config.js

var config = {
    config: {    
        mixins: {            
            'Magento_Catalog/js/product/list/toolbar': {'Magento_Catalog/js/product/list/toolbar-mixin': true},
        },        
    }
};

step 3: create the file toolbar-mixin.js
under
/app/design/frontend/Vendor/theme/Magento_Catalog/web/js/product/list

File: toolbar-mixin.js

define([
    'jquery',    
    'uiComponent'
], function($, Component) {
    'use strict'; 
    return function(target) {
    return $.widget('mage.productListToolbarForm', $.mage.productListToolbarForm, {        
        _processSelect: function (event) {
            var optionvalue =  event.currentTarget.options[event.currentTarget.selectedIndex].value;
            var optionvalueParts = optionvalue.split("&");
            this.mychangeUrl(
                event.data.paramName,
                optionvalueParts[0],
                event.data.default,
                optionvalueParts[1]
            );
          },
          mychangeUrl: function (paramName, paramValue, defaultValue,listdir) {
            var decode = window.decodeURIComponent,
                urlPaths = this.options.url.split('?'),
                baseUrl = urlPaths[0],
                urlParams = urlPaths[1] ? urlPaths[1].split('&') : [],
                paramData = {},
                parameters, i;

            for (i = 0; i < urlParams.length; i++) {
                parameters = urlParams[i].split('=');
                paramData[decode(parameters[0])] = parameters[1] !== undefined ?
                    decode(parameters[1].replace(/+/g, '%20')) :
                    '';
            }
            paramData[paramName] = paramValue;
            console.log(paramData);

            if (paramValue == defaultValue) { //eslint-disable-line eqeqeq
                delete paramData[paramName];
            }            
            delete paramData['product_list_dir'];
            paramData = $.param(paramData);
            baseUrl = baseUrl + (paramData.length ? '?' + paramData : '');                        
            baseUrl = baseUrl + (paramData.length ? '&' + 'product_list_dir='+listdir : '?' + 'product_list_dir='+listdir);
            baseUrl= decodeURIComponent( baseUrl.replace(/+/g, '%20'));            
            location.href = baseUrl;
        },         

    });
  }
});

step 4:: Run below commadn from Magento root to remove static files and cache.

sudo rm -rf var/view_preprocessed/*
sudo rm -rf var/pub/static/*
sudo rm -rf var/cache/*
sudo rm -rf var/generated
sudo rm -rf var/composer_home
sudo rm -rf var/page_cache
sudo rm -rf var/view_preprocessed
sudo rm -rf pub/static/frontend/*

enter image description here

Method 2

Create a module with name STech_Sortby by following below steps:

Step 1: Create registration.php under

app/code/STech/Sortby/registration.php

<?php

MagentoFrameworkComponentComponentRegistrar::register(
    MagentoFrameworkComponentComponentRegistrar::MODULE,
    'STech_Sortby',
    __DIR__
);

Step 2: Create module.xml under

app/code/STech/Sortby/etc/module.xml

<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../../../lib/internal/Magento/Framework/Module/etc/module.xsd">
    <module name="STech_Sortby" setup_version="0.0.1">
        <sequence>
            <module name="Magento_Catalog"/>
        </sequence>
    </module>
</config>

Step 3: Create di.xml under

app/code/STech/Sortby/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="MagentoCatalogBlockProductProductListToolbar">
        <plugin name="custom_block_toolbar" type="STechSortbyPluginCatalogBlockToolbar" />
    </type>
    <type name="MagentoCatalogModelConfig">
        <plugin name="custom_catalog_model_config" type="STechSortbyPluginCatalogModelConfig" />
    </type>
</config>

Step 4: Create Toolbar.php under

app/code/STech/Sortby/Plugin/Catalog/Block/Toolbar.php

<?php
namespace STechSortbyPluginCatalogBlock;

class Toolbar
{
    public function aroundSetCollection(
    MagentoCatalogBlockProductProductListToolbar $subject,
    Closure $proceed,
    $collection
    ) {
    $currentOrder = $subject->getCurrentOrder();
    $result = $proceed($collection);

    if ($currentOrder) {
        if ($currentOrder == 'price_desc') {
            $subject->getCollection()->setOrder('price', 'desc');
        } elseif ($currentOrder == 'price_asc') {
            $subject->getCollection()->setOrder('price', 'asc');
        } elseif ($currentOrder == 'position_asc') {
            $subject->getCollection()->addAttributeToSort('position', 'asc')->addAttributeToSort('entity_id', 'asc');
        } elseif ($currentOrder == 'position_desc') {
            $subject->getCollection()->addAttributeToSort('position', 'desc')->addAttributeToSort('entity_id', 'desc');
        }
    }

    return $result;
    }

}

Step 5: Create Config.php under

app/code/STech/Sortby/Plugin/Catalog/Model/Config.php

<?php
namespace STechSortbyPluginCatalogModel;

class Config
{
    public function afterGetAttributeUsedForSortByArray(
    MagentoCatalogModelConfig $catalogConfig,
    $options
    ) {
        unset($options['position']);
        unset($options['price']);
        $options['price_asc'] = __('Price Asc');
        $options['price_desc'] = __('Price Desc');
        $options['position_asc'] = __('Position Asc');
        $options['position_desc'] = __('Position Desc');
        return $options;

    }

}

Thats it!. Now run setup upgrade and other required commands and check.

Method 3

This can be done using Magento2 Plugins.
check this one:

Create the following files in your module: (Assuming you have your own module registered already)

Create your Plugin under Vendor/Modulename/etc/di.xml

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="MagentoCatalogModelConfig">
    <plugin name="Vendor_Modulename::addCustomOptions" type="VendorModulenamePluginModelConfig" />
</type>
<type name="MagentoCatalogBlockProductProductListToolbar">
    <plugin name="Vendor::addPriceDescendingFilterInToolbar" type="VendorModulenamePluginProductProductListToolbar" />
</type>

Then create a config.php under namespace Vendor/Modulename/Plugin/Model/Config.php

and put this code:

<?php

namespace VendorModulenamePluginModel;

use MagentoStoreModelStoreManagerInterface;

class Config  {


protected $_storeManager;

public function __construct(
    StoreManagerInterface $storeManager
) {
    $this->_storeManager = $storeManager;
}


public function afterGetAttributeUsedForSortByArray(MagentoCatalogModelConfig $catalogConfig, $options)
{
    $store = $this->_storeManager->getStore();
    $currencySymbol = $store->getCurrentCurrency()->getCurrencySymbol();

    // Remove specific default sorting options
    $default_options = [];
    $default_options['name'] = $options['name'];

    //New sorting options
    $customOption['price_asc'] = __( ' Price ascending' );

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

    return $options;
}
}

Then override the Toolbar.php ***Vendor/Modulename/Plugin/Product/ProductList/Toolbar.php

use this code

<?php
namespace VendorModulenamePluginProductProductList;

class Toolbar
{

public function aroundSetCollection(
    MagentoCatalogBlockProductProductListToolbar $subject,
    Closure $proceed,
    $collection
) {
    $currentOrder = $subject->getCurrentOrder();
    $result = $proceed($collection);

    if ($currentOrder) {
        if ($currentOrder == 'price_asc') {
            $subject->getCollection()->setOrder('price', 'asc');
        }
    }


    return $result;
}
}


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

Leave a Comment