18

I need to add an additional filter based on created_at attribute for sorting product list by latest product. I tried to figure it using below file

app/design/frontend/Vendor/ThemeName/Magento_Catalog/templates/product/list/toolbar/sorter.phtml  

but how can add our entity id to getAvailableOrders() ?

  • Please accept answer if this question resolved. – LucScu Jul 10 '17 at 14:27
18

If you want to use an attribute like created_at that it isn't in admin->stores->(attribute) product, because attributes defined in admin have the setting Sorting in Product Listing = Yes/No, you have to work with these two files:

\vendor\magento\module-catalog\Block\Product\ProductList\Toolbar.php \vendor\magento\module-catalog\Model\Config.php

In Toolbar.php you can see

$this->_availableOrder = $this->_catalogConfig->getAttributeUsedForSortByArray();

it calls getAttributeUsedForSortByArray() from Config.php that returns array of available attributes to sort listing collection.

Now, you have to add your created_at attribute here. How? I did it with a plugin

/**
 * Add sort order option created_at to frontend
 */
public function afterGetAttributeUsedForSortByArray(
    \Magento\Catalog\Model\Config $catalogConfig,
    $options
) {
    $options['created_at'] = __('New');
    return $options;
}

You inserted created_at in available attributes to sort, now you have only to build your custom collection to use it. Here i choose to override \vendor\magento\module-catalog\Block\Product\ProductList\Toolbar.php with mine Toolbar.php and override setCollection()

/**
 * 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);
    }

    // switch between sort order options
    if ($this->getCurrentOrder()) {
        // create custom query for created_at option
        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;
            default:
                $this->_collection->setOrder($this->getCurrentOrder(), $this->getCurrentDirection());
                break;
        }
    }

    // echo '<pre>';
    // var_dump($this->getCurrentOrder());
    // var_dump((string) $this->_collection->getSelect());
    // die;

    return $this;        
}

That's all, for me works like a charm.

  • If anyone wants to default to ascending, then change } elseif ( $this->getCurrentDirection() == 'asc' ) { to } else {. – thdoan Nov 3 '16 at 2:02
  • 2
    Also, if you don't want to use a plugin, you can also use the built-in public function $block->addOrderToAvailableOrders('created_at', 'New') in your sorter template. – thdoan Nov 3 '16 at 3:04
  • Can you have the solution for sorting custom product price? @Luca – Dhaduk Mitesh Apr 16 '18 at 11:45
  • @DhadukMitesh sure, you could just use the above code and change attribute code created_at with your custom price attribute code – LucScu Apr 17 '18 at 14:46
  • I have no custom price attribute. I use default price sort by. I only change in core file where price is sorting. and I want to set my custom price for a collection. but I can't set custom price in collection. – Dhaduk Mitesh Apr 18 '18 at 4:42
17

We can achieve it by using Plugins. Please create following files in your module.

app/code/Package/CustomToolbar/etc/di.xml

<type name="Magento\Catalog\Model\Config">
    <plugin name="Package_CustomToolbar::addCustomOptions" type="Package\CustomToolbar\Plugin\Model\Config" />
</type>
<type name="Magento\Catalog\Block\Product\ProductList\Toolbar">
    <plugin name="Package_CustomToolbar::addPriceDecendingFilterInToolbar" type="Package\CustomToolbar\Plugin\Product\ProductList\Toolbar" />
</type>

app/code/Package/CustomToolbar/Plugin/Model/Config.php

namespace Package\CustomToolbar\Plugin\Model;
use Magento\Store\Model\StoreManagerInterface;
class Config
{
    protected $_storeManager;

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

}

/**
 * Adding custom options and changing labels
 *
 * @param \Magento\Catalog\Model\Config $catalogConfig
 * @param [] $options
 * @return []
 */
public function afterGetAttributeUsedForSortByArray(\Magento\Catalog\Model\Config $catalogConfig, $options)
{
    $store = $this->_storeManager->getStore();
    $currencySymbol = $store->getCurrentCurrency()->getCurrencySymbol();

    //Remove specific default sorting options
    unset($options['position']);
    unset($options['name']);
    unset($options['price']);

    //Changing label
    $customOption['position'] = __('Relevance');

    //New sorting options
    $customOption['price_desc'] = __($currencySymbol.' (High to Low)');
    $customOption['price_asc'] = __($currencySymbol.' (Low to High)');

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

    return $options;
}
}

app/code/Package/CustomToolbar/Plugin/Product/ProductList/Toolbar.php

namespace Package\CustomToolbar\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 $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');
            }
        }

        return $result;
    }
}

This is working fine for me without rewriting any Magento class.

  • this doesn't address created_at and not working for 2.1.9 - for me at least – dawhoo Oct 30 '17 at 18:44
  • Could you please elaborate on how aroundSetCollection works? – TheKitMurkit Nov 26 '18 at 14:10
3

If you want to use just Create At attribute, you can activate this attribute in admin panel in sorting options.

Example:

<?php

namespace Vendor\Module\Setup;

use Magento\Eav\Setup\EavSetup;
use Magento\Eav\Setup\EavSetupFactory;
use Magento\Framework\Setup\ModuleContextInterface;
use Magento\Framework\Setup\ModuleDataSetupInterface;
use Magento\Framework\Setup\UpgradeDataInterface;

class UpgradeData implements UpgradeDataInterface
{
    protected $eavSetupFactory;

    /**
     * UpgradeData constructor.
     *
     * @param EavSetupFactory $eavSetupFactory
     */
    public function __construct(
        EavSetupFactory $eavSetupFactory
    ) {
        $this->eavSetupFactory = $eavSetupFactory;
    }

    /**
     * @param ModuleDataSetupInterface $setup
     * @param ModuleContextInterface $context
     */
    public function upgrade(
        ModuleDataSetupInterface $setup,
        ModuleContextInterface $context
    ) {
        /** @var EavSetup $eavSetup */
        $eavSetup = $this->eavSetupFactory->create(['setup' => $setup]);

        if (version_compare($context->getVersion(), '2.1.1', '<')) {
            try {
                $entityType = $eavSetup->getEntityTypeId('catalog_product');
                $label = 'Created At';
                $eavSetup->updateAttribute($entityType, 'created_at', 'frontend_label', $label, null);
                $eavSetup->updateAttribute($entityType, 'created_at', 'used_for_sort_by', 1, null);
            } catch (LocalizedException $e) {
            }
        }
    }
}

This code from Setup/UpgradeData.php, but will be better to use InstallData.php instead.

  • Where is this code added in the file system? – YorkieMagento Nov 29 '18 at 9:41
  • 1
    Why create a custom module to change a db field? i don't think is the best way. – LucScu Jan 23 at 8:41
2

Step 1: First you should create registration.php

Vendor name: Arun

Module name: NewSorting

Vendor/Modulename/registration.php

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

Step 2: You create module.xml

Vendor/Modulename/etc/module.xml

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

Step 3: You create plugin

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="Arun_NewSorting::addCustomOptions" type="Arun\NewSorting\Plugin\Model\Config" />
    </type>
    <type name="Magento\Catalog\Block\Product\ProductList\Toolbar">
        <plugin name="Arun_NewSorting::addPriceDecendingFilterInToolbar" type="Arun\NewSorting\Plugin\Product\ProductList\Toolbar" />
    </type>
</config>

Step 4: then create config.php

Vendor/Modulename/Plugin/Model/Config.php

<?php
namespace Arun\NewSorting\Plugin\Model;

use Magento\Store\Model\StoreManagerInterface;

class Config  {


    protected $_storeManager;

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


    public function afterGetAttributeUsedForSortByArray(\Magento\Catalog\Model\Config $catalogConfig, $options)
    {
        $store = $this->_storeManager->getStore();
        $currencySymbol = $store->getCurrentCurrency()->getCurrencySymbol();

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

        unset($options['position']);
        unset($options['name']);
        unset($options['price']);

        //Changing label
        $customOption['position'] = __( 'Relevance' );

        //New sorting options
        $customOption['created_at'] = __( ' New' );


        $customOption['name'] = $default_options['name'];

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

        return $options;
    }
}

Step 5: Override the Toolbar.php***

Vendor/Modulename/Plugin/Product/ProductList/Toolbar.php

<?php
namespace Arun\NewSorting\Plugin\Product\ProductList;

class Toolbar
{

    public function aroundSetCollection(
        \Magento\Catalog\Block\Product\ProductList\Toolbar $subject,
        \Closure $proceed,
        $collection
    ) {
        $currentOrder = $subject->getCurrentOrder();
        $result = $proceed($collection);

        if ($currentOrder) {
            if ($currentOrder == 'created_at') {
                $subject->getCollection()->setOrder('created_at', 'desc');
            } 
        }

        return $result;
    }
}

it's work perfectly

  • Any commands to be run in CLI after updating these files please? – YorkieMagento Nov 21 '18 at 12:15
  • Need to run following CLI setup upgrade, static-content deploy, cache clean, reindex – MSA Nov 22 '18 at 7:02
  • Thanks MSA but when I run the upgrade command it says 'nothing to update'. Using 2.2.5. Copied all of the above... but wondered what is in Registration.php file you mention and where to locate it? – YorkieMagento Nov 22 '18 at 15:38
  • I updated Registration.php file content path:Vendor/Modulename/registration.php – MSA Nov 23 '18 at 11:18
  • Added module exactly as above and the 'new' option shows on front end. It seems to have replaced the 'position' option is that expected? I cannot see the option in catalog in admin panel, as I would like to make this default option... Thank you. – YorkieMagento Nov 26 '18 at 17:13
0

The way doesn't need write codes

  1. Find the created_at product attribute in DB table eav_attribute, set its column frontend_label to Created At(default is null).

  2. Find the created_at product attribute in DB table catalog_eav_attribute, set its column used_for_sort_by to 1(default is 0).

  3. Clean site cache and it is working.

Example: change table by mysql

# Get the attribute_id of 'created_at'
select attribute_id from eav_attribute where attribute_code = 'created_at' and entity_type_id=4;

# Set frontend_label
update eav_attribute set frontend_label = 'Created At' where attribute_id=112;

# Set used_for_sort_by
update catalog_eav_attribute set used_for_sort_by = 1 where attribute_id=112;

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.