0

Custom Sorting option not working in Magetno 2.4 search

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

app/code/Arun/NewSorting/Plugin/Model/Config.php

<?php
namespace Arun\NewSorting\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)
{
    //Change label of default sorting options if needed
    //$options['position'] = __('Relevance');
    $options['newest'] = __('Newest');

    return $options;
}

}

app/code/Arun/NewSorting/Plugin/Product/ProductList/Toolbar.php

<?php
namespace Arun\NewSorting\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;

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

        }
    }
    //var_dump((string) $this->_collection->getSelect());
    return $result;
}
}

When i select the Newest filter it shows the message No Result Found.

Any one tell me what is the issue or any other things which i have missed.

Any help is appriciated.

1

2 Answers 2

1

Toolbar plugin is no longer necessary since elasticsearch is used.

lol

I spent a lot of my time researching Magento 2.4.6 (PHP 8.1+) with lots of the modules installed (also Amasty ShopBy (layered navigation)) and found an easy working way :

just create a plugin for Magento\Catalog\Model\Config , add your needed new order by options and after that just add a preference for Toolbar block (as you did in question):

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()) {
            if (($this->getCurrentOrder()) == 'position') {
                $this->_collection->setOrder(
                    'product_id',
                    SortOrder::SORT_DESC
                );
            // add custom sort order fields to a collection name_za, price_hl
            } elseif ($this->getCurrentOrder() == 'name_za') {
                $this->_collection->setOrder('name', SortOrder::SORT_DESC);
            } elseif ($this->getCurrentOrder() == 'name') {
                $this->_collection->setOrder('name', SortOrder::SORT_ASC);
            } elseif ($this->getCurrentOrder() == 'price') {
                $this->_collection->setOrder('name', SortOrder::SORT_ASC);
            } elseif ($this->getCurrentOrder() == 'price_hl') {
                $this->_collection->setOrder('price', SortOrder::SORT_DESC);
            } else {
                $this->_collection->setOrder($this->getCurrentOrder(), $this->getCurrentDirection());
            }
        }
        return $this;
    }

so use :

$this->_collection->setOrder('price', SortOrder::SORT_DESC);

or

$this->_collection->setOrder($this->getCurrentOrder(), $this->getCurrentDirection());

in my case for some reason (some of the modules modified the default order direction and set it as "DESC", but as the default, it must be "ASC"). So please double-check the default direction and I hope that you'll be happy :)

1

In magento 2.4 and above, all sort goes through elasticsearch. To use custom sort order FOR NON EAV properties you have to add data to elasticsearch first. But from the begginig. This is how i do this on magento 2.4.5-p1 and PHP8.1:

  1. Config plugin 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="catalog_config_plugin" type="Vendor\Module\Plugin\ConfigPlugin"/>
    </type>
</config>
  1. ConfingPlugin.php
<?php

declare(strict_types=1);

namespace Venndor\Module\Plugin;

use Magento\Catalog\Model\Config;

class ConfigPlugin
{
    /**
     * @var string
     */
    public const CUSTOM_SORTING_SORT_KEY = 'custom_sorting';

    /**
     * Plugin to add custom sorting key and option
     *
     * @param Config $catalogConfig
     * @param array<string, mixed> $options
     * @return array<string, mixed>
     */
    public function afterGetAttributeUsedForSortByArray(Config $catalogConfig, $options): array
    {
        $customOption[self::CUSTOM_SORTING_SORT_KEY] = __('Custom sorting');

        return array_merge($options, $customOption);
    }
}

  1. Then you have to add CustomDataProvider for elasticsearch to add product data during indexing. So again we have to add that in 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="catalog_config_plugin" type="Vendor\Module\Plugin\ConfigPlugin"/>
    </type>
    <virtualType name="additionalFieldsProviderForElasticsearch"
                 type="Magento\AdvancedSearch\Model\Adapter\DataMapper\AdditionalFieldsProvider">
        <arguments>
            <argument name="fieldsProviders" xsi:type="array">
                <item name="custom_sorting" xsi:type="object">
                    \Vendor\Module\Model\Adapter\BatchDataMapper\CustomDataProvider
                </item>
            </argument>
        </arguments>
    </virtualType>
</config>


  1. And here CustomDataProviderClass
<?php

declare(strict_types=1);

namespace Vendor\Module\Model\Adapter\BatchDataMapper;

use Magento\AdvancedSearch\Model\Adapter\DataMapper\AdditionalFieldsProviderInterface;

class CustomDataProvider implements AdditionalFieldsProviderInterface
{
    /**
     * Add custom sorting field to data mapper used by elasticsearch
     *
     *  @param array<int, int> $productIds
     *  @return array<int, array<string, mixed>>
     */
    public function getFields(array $productIds, $storeId): array
    {
        $fields = [];
        
        $id=0;

        foreach ($productIds as $productId) {
            $fields[$productId] = [\Vendor\Module\Plugin\ConfigPlugin::CUSTOM_SORTING_SORT_KEY => $id];
            $id++;
        }

        return $fields;
    }
}

In this CustomDataProvider for test purposes I assigned value of some generic $id that is incrementing for each product but this is the place where proper value for product should be assigned.

Toolbar plugin is no longer necessary since elasticsearch is used.

Now, after reindex it should work.

0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.