Magento 2 Comment ajouter un tri personnalisé par option

22

J'ai besoin d'ajouter un filtre supplémentaire basé sur l' created_atattribut pour trier la liste des produits par dernier produit. J'ai essayé de le comprendre en utilisant le fichier ci-dessous

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

mais comment ajouter notre identifiant d'entité getAvailableOrders()?

Chamal Chamikara
la source

Réponses:

23

Si vous souhaitez utiliser un attribut tel created_atqu'il ne se trouve pas dans le produit admin-> stores -> (attribute), car les attributs définis dans admin ont le paramètre Sorting in Product Listing = Yes/No, vous devez travailler avec ces deux fichiers:

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

En Toolbar.phpvous pouvez voir

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

il appelle à getAttributeUsedForSortByArray()partir de ce Config.phpqui renvoie un tableau d'attributs disponibles pour trier la collection de listes.

Maintenant, vous devez ajouter votre created_atattribut ici. Comment? Je l'ai fait avec un plugin

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

Vous avez inséré created_atles attributs disponibles pour trier, il ne vous reste plus qu'à créer votre collection personnalisée pour l'utiliser. Ici, je choisis de passer outre \vendor\magento\module-catalog\Block\Product\ProductList\Toolbar.php au mien Toolbar.phpet de passer outresetCollection()

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

C'est tout, pour moi ça marche comme un charme.

LucScu
la source
Si quelqu'un souhaite passer par défaut à croissant, passez } elseif ( $this->getCurrentDirection() == 'asc' ) {à } else {.
thdoan
2
De plus, si vous ne souhaitez pas utiliser de plugin, vous pouvez également utiliser la fonction publique intégrée $block->addOrderToAvailableOrders('created_at', 'New')dans votre modèle de tri.
thdoan
Pouvez-vous avoir la solution pour trier les prix des produits personnalisés? @Luca
Dhaduk Mitesh
@DhadukMitesh bien sûr, vous pouvez simplement utiliser le code ci-dessus et changer le code d'attribut created_atavec votre code d'attribut de prix personnalisé
LucScu
Je n'ai pas d'attribut de prix personnalisé. J'utilise le prix par défaut trié par. Je ne change que dans le fichier core où le prix est trié. et je veux définir mon prix personnalisé pour une collection. mais je ne peux pas définir de prix personnalisé dans la collection.
Dhaduk Mitesh
19

Nous pouvons y parvenir en utilisant des plugins. Veuillez créer les fichiers suivants dans votre 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;
    }
}

Cela fonctionne bien pour moi sans réécrire aucune classe Magento.

Sumit Verma
la source
cela ne concerne pas created_at et ne fonctionne pas pour 2.1.9 - pour moi au moins
dawhoo
Pourriez-vous nous expliquer comment fonctionne AroundSetCollection?
TheKitMurkit
variable undefined $ collection,
jafar pinjar
4

Si vous souhaitez utiliser uniquement l' attribut Créer à , vous pouvez activer cet attribut dans le panneau d'administration dans les options de tri.

Exemple:

<?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) {
            }
        }
    }
}

Ce code de Setup / UpgradeData.php , mais sera préférable d'utiliser InstallData.php à la place.

iproger
la source
Où ce code est-il ajouté dans le système de fichiers?
YorkieMagento
1
Pourquoi créer un module personnalisé pour changer un champ db? je ne pense pas que ce soit la meilleure façon.
LucScu
2

Étape 1 : Vous devez d'abord créer registration.php

Nom du vendeur: Arun

Nom du module: NewSorting

Fournisseur / nom de module / registration.php

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

Étape 2 : vous créez module.xml

Fournisseur / nom de module / 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>

Étape 3 : vous créez un plugin

Fournisseur / nom de module / 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>

Étape 4 : puis créez config.php

Fournisseur / Nom de module / Plugin / Modèle / 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;
    }
}

Étape 5 : remplacer le Toolbar.php ***

Fournisseur / nom de module / plugin / produit / liste de produits / barre d'outils.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;
    }
}

ça marche parfaitement

Arunprabakaran M
la source
Des commandes à exécuter dans CLI après la mise à jour de ces fichiers s'il vous plaît?
YorkieMagento
Besoin de s'exécuter après la mise à niveau de la configuration CLI, le déploiement de contenu statique, le nettoyage du cache, la
réindexation
Merci MSA, mais lorsque j'exécute la commande de mise à niveau, il indique «rien à mettre à jour». Utilisation de 2.2.5. J'ai copié tout ce qui précède ... mais je me suis demandé ce qu'il y avait dans le fichier Registration.php que vous mentionnez et où le trouver?
YorkieMagento
J'ai mis à jour le chemin du contenu du fichier Registration.php: Vendor / Modulename / registration.php
Arunprabakaran M
Module ajouté exactement comme ci-dessus et la «nouvelle» option s'affiche à l'avant. Il semble avoir remplacé l'option «position» est-ce prévu? Je ne vois pas l'option dans le catalogue dans le panneau d'administration, car je voudrais faire cette option par défaut ... Merci.
YorkieMagento
1

Le chemin n'a pas besoin d'écrire des codes

  1. Recherchez l' created_atattribut de produit dans la table DB eav_attribute, définissez sa colonne frontend_labelsur Created At(la valeur par défaut est null).

  2. Recherchez l' created_atattribut de produit dans la table DB catalog_eav_attribute, définissez sa colonne used_for_sort_bysur 1(la valeur par défaut est 0).

  3. Nettoyez le cache du site et cela fonctionne.

Exemple: changer la table par 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;
Key Shang
la source
Je ne changerais pas directement les valeurs de la base de données, surtout s'il s'agit de données de base.
LucScu
@LucScu C'est juste un autre moyen plus simple. Cela a changé deux champs DB qui n'ont pas d'importance. Vous pouvez également utiliser des codes pour remplacer la fonction, mais la fonction couverte sera modifiée lors de la mise à niveau de la version et vous devrez mettre à jour vos codes personnalisés. Les deux méthodes présentent des avantages et des inconvénients. Utiliser des codes personnalisés pour une fonction simple est un peu exagéré.
Key Shang
@SagarParikhSGR Je l'ai utilisé et ça marche. Faites attention à utiliser le droit attribute_id.
Key Shang
@KeyShang mon mauvais, ça fonctionne parfaitement, a voté :)
Sagar Parikh SGR