3

I want to custom sort by option filter attribute add in tool bar section. Currently Magento 2 provide Position , Product Name , Price And Sorting option to low to high. But i need to change all sorting option Like Price High to Low , Price Low to High.

3

I created these custom sort by options:

  • price high - low --> (including all forms of discounts)
  • price low - high --> (including all forms of discounts)
  • name a-z
  • name z-a
  • newest
  • oldest

by creating a plugin to bypass the default functionality of the product sorter which can be found here:

Magento\Catalog\Block\Product\ProductList\Toolbar

and

Magento\Catalog\Model\Config

You start by creating your own module and registering it.

Then create:

{Vendor}/{ModuleName}/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="Magento\Catalog\Model\Config">
        <plugin name="Vendor_ModuleName::addCustomSortOptions" type="Vendor\ModuleName\Plugin\Model\Config" />
    </type>
    <type name="Magento\Catalog\Block\Product\ProductList\Toolbar">
        <plugin name="Vendor_ModuleName::implementCustomSortOptions" type="Vendor\ModuleName\Plugin\Product\ProductList\Toolbar" />
    </type>
</config>

Create

{Vendor}/{ModuleName}/Plugin/Model/Config.php

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

class Config
{
    /**
     * Adding custom options and changing labels
     *
     * @param \Magento\Catalog\Model\Config $catalogConfig
     * @param [] $options
     * @return []
     */
    public function afterGetAttributeUsedForSortByArray(\Magento\Catalog\Model\Config $catalogConfig, $options)
    {
        //Remove default sorting options
        unset($options['position']);
        unset($options['name']);
        unset($options['price']);

        //Change label of default sorting options if needed
        //$options['position'] = __('Relevance');

        //New sorting options
        $options['price_desc'] = __('Price High - Low');
        $options['price_asc'] = __('Price Low - High');
        $options['newest'] = __('Newest');
        $options['oldest'] = __('Oldest');
        $options['name_az'] = __('Product Name A - Z');
        $options['name_za'] = __('Product Name Z - A');

        return $options;
    }
}

Create

{vendor}/{modulename}/Plugin/Product/ProductList/Toolbar.php

<?php
namespace Vendor\ModuleName\Plugin\Product\ProductList;

class Toolbar
{
    /**
    * Plugin
    *
    * @param \Magento\Catalog\Block\Product\ProductList\Toolbar $subject
    * @param \Closure $proceed
    * @param \Magento\Framework\Data\Collection $collection
    * @return \Magento\Catalog\Block\Product\ProductList\Toolbar
    */
    public function aroundSetCollection(
        \Magento\Catalog\Block\Product\ProductList\Toolbar $toolbar,
        \Closure $proceed,
        $collection
    ) {
        $this->_collection = $collection;
        $currentOrder = $toolbar->getCurrentOrder();
        $currentDirection = $toolbar->getCurrentDirection();
        $result = $proceed($collection);

        if ($currentOrder) {
            switch ($currentOrder) {

            case 'newest':
                $this->_collection
                    ->getSelect()
                    ->order('e.created_at DESC');
            break;

            case 'oldest':
                $this->_collection
                    ->getSelect()
                    ->order('e.created_at ASC');

            break;

            case 'price_desc':
                $this->_collection
                    ->getSelect()
                    ->order('price_index.min_price DESC');
            break;

            case 'price_asc':
                $this->_collection
                    ->getSelect()
                    ->order('price_index.min_price ASC');
            break;

            case 'name_az':
                $this->_collection
                    ->getSelect()
                    ->order('e.name ASC');
            break;

            case 'name_za':
                $this->_collection
                    ->getSelect()
                    ->order('e.name DESC');
            break;

            default:        
                $this->_collection
                    ->setOrder($currentOrder, $currentDirection);
            break;

            }
        }
        //var_dump((string) $this->_collection->getSelect()); You can use this to get a list of all the available sort fields
        return $result;
    }
}
  • I followed above steps replace code from {vendor}/{modulename} to our {vendor}/{modulename}. after creating attributes form backend. but it seems no luck. – Anikesh Shahi Dec 16 '17 at 7:26
  • @AnikeshShahi what do you mean "after creating attributes from backend"? This works for sure in Magento 2.2. I suggest you double check if you changed all {vendor} & {modulename} with your own. And make sure you did setup:upgrade, setup:di:compile, clear static files and cache. – Lez Dec 17 '17 at 20:07
  • I already checked, attributes shows in drop down tool bar but not filtering as per selection. – Anikesh Shahi Dec 18 '17 at 5:08
  • @AnikeshShahi if you see the new options, but they don't work, you might have made a mistake in Toolbar.php or maybe you have conflicting modules (which both change the functionality of the toolbar). Maybe you could edit your question with your attempted solution and I could help you locate the mistake. – Lez Dec 18 '17 at 8:40
  • I want to sort the collection by custom price using default sort by price. Have you any solution? @Lez – Dhaduk Mitesh Apr 18 '18 at 6:04
1

You have to override \Magento\Catalog\Block\Product\ProductList\Toolbar and Magento\Catalog\Model\Config.

etc/di.xml

<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd">
   <preference for="Magento\Catalog\Block\Product\ProductList\Toolbar" type="{Vendor}\{Module}\Block\Plugin\Product\ProductList\Toolbar" />
    <type name="Magento\Catalog\Model\Config">
       <plugin name="override-config" type="{Vendor}\{Module}\Model\Plugin\Config" sortOrder="10"/>
    </type>
</config>

{vendor}{module}\Block\Plugin\Product\ProductList\Toolbar.php

namespace {Vendor}\{module}\Block\Plugin\Product\ProductList;

class Toolbar extends \Magento\Catalog\Block\Product\ProductList\Toolbar {
  public function setCollection($collection) {
    $this->_collection = $collection;
    $this->_collection->setCurPage($this->getCurrentPage());
    $limit = (int) $this->getLimit();
    if ($limit) {
        $this->_collection->setPageSize($limit);
    }
    if ($this->getCurrentOrder()) {
        switch ($this->getCurrentOrder()) {
            case 'created_at':
                if ($this->getCurrentDirection() == 'desc') {
                    $this->_collection
                            ->getSelect()
                            ->order('e.created_at DESC');
                } elseif ($this->getCurrentDirection() == 'asc') {
                    $this->_collection
                            ->getSelect()
                            ->order('e.created_at ASC');
                }
                break;
            case 'in_stock':
                $this->_collection
                        ->getSelect()
                        ->joinLeft(
                                ['admin' => $collection->getTable('cataloginventory_stock_item')], 'e.entity_id = admin.product_id')->where('admin.is_in_stock = 1');
                break;
            case 'out_stock':
                $this->_collection
                        ->getSelect()
                        ->joinLeft(
                                ['admin' => $collection->getTable('cataloginventory_stock_item')], 'e.entity_id = admin.product_id')->where('admin.is_in_stock = 0');
                break;
            default:
                $this->_collection->setOrder($this->getCurrentOrder(), $this->getCurrentDirection());
                break;
        }
    }
    return $this;
  }
}

{Vendor}{Module}\Model\Plugin\Config.php

namespace {Vendor}\{Module}\Model\Plugin;
class Config {

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

    $options['created_at'] = __('Newest');
    $options['in_stock'] = __('In Stock');
    $options['out_stock'] = __('Out of Stock');
    return $options;
   }
}
  • Small remark. You need join cataloginventory_stock_status not cataloginventory_stock_item table – KAndy Dec 9 '16 at 14:06
  • Have you any solution for it? i have for cataloginventory_stock_item. and its working fine – chirag Dec 9 '16 at 14:22
  • I want to sort the collection by custom price using default sort by price. Have you any solution? @Lez – Dhaduk Mitesh Apr 18 '18 at 6:05
0

I did something similar using following code.

app/code/Anshu/Sortby/registration.php

<?php
\Magento\Framework\Component\ComponentRegistrar::register(
    \Magento\Framework\Component\ComponentRegistrar::MODULE,
    'Anshu_Sortby',
    __DIR__
);

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

<?xml version="1.0" encoding="UTF-8"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Module/etc/module.xsd">
    <module name="Anshu_Sortby" setup_version="1.0.0">
        <sequence>
            <module name="Magento_Catalog"/>
        </sequence>
    </module>
</config>

app/code/Anshu/Sortby/etc/di.xml

<?xml version="1.0" encoding="UTF-8"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd">   <preference for="Magento\Catalog\Block\Product\ProductList\Toolbar" type="Anshu\Sortby\Block\Catalog\Product\ProductList\Toolbar" />
    <preference for="Magento\Catalog\Model\Config" type="Anshu\Sortby\Model\Config" />
</config>

app/code/Anshu/Sortby/Model/Config.php

<?php

namespace Anshu\Sortby\Model;

class Config extends \Magento\Catalog\Model\Config
{

    /**
     * Retrieve Attributes Used for Sort by as array
     * key = code, value = name
     *
     * @return array
     */
    public function getAttributeUsedForSortByArray()
    {
        $options = ['position' => __('Most Popular')];
        foreach ($this->getAttributesUsedForSortBy() as $attribute) {
            /* @var $attribute \Magento\Eav\Model\Entity\Attribute\AbstractAttribute */
            $options[$attribute->getAttributeCode()] = $attribute->getStoreLabel();
        }

        $options['position'] = __('Most Popular');
        $options['price'] =  __('Price: Low to High');
        $options['price_desc'] = __('Price: High to Low');
        return $options;
    }

}

app/code/Anshu/Sortby/Block/Catalog/Product/ProductList/Toolbar.php

<?php

namespace Anshu\Sortby\Block\Catalog\Product\ProductList;

use Magento\Catalog\Helper\Product\ProductList;
use Magento\Catalog\Model\Product\ProductList\Toolbar as ToolbarModel;

class Toolbar extends \Magento\Catalog\Block\Product\ProductList\Toolbar
{
    /**
     * Set collection to pager
     *
     * @param \Magento\Framework\Data\Collection $collection
     * @return $this
     */
    public function setCollection($collection)
    {
        $this->_collection = $collection;

        $this->_collection->setCurPage($this->getCurrentPage());

        // we need to set pagination only if passed value integer and more that 0
        $limit = (int)$this->getLimit();
        if ($limit) {
            $this->_collection->setPageSize($limit);
        }
        if ($this->getCurrentOrder()) {
            switch ($this->getCurrentOrder()) {
                case 'price':
                    $this->_collection->setOrder($this->getCurrentOrder(), 'ASC');
                    break;

                case 'price_desc':
                    $this->_collection
                            ->getSelect()
                            ->order('price_index.price DESC');

                default:
                    //$this->_collection->setOrder($this->getCurrentOrder(), $this->getCurrentDirection());
                    $this->_collection->setOrder($this->getCurrentOrder(), 'DESC');
                break;
            }
        }

        return $this;
    }

}

I hope this will be helpful.

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.