Magento 2 Wie man eine benutzerdefinierte Sortierung nach Option hinzufügt


21

Ich muss einen zusätzlichen Filter basierend auf dem created_atAttribut hinzufügen , um die Produktliste nach dem neuesten Produkt zu sortieren. Ich habe versucht, es mit der folgenden Datei herauszufinden

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

Aber wie kann unsere Entitäts-ID hinzugefügt werden getAvailableOrders()?

Antworten:


22

Wenn Sie ein Attribut verwenden möchten, created_atdas sich nicht in admin-> stores -> (attribute) product befindet, da in admin definierte Attribute die Einstellung haben Sorting in Product Listing = Yes/No, müssen Sie mit diesen beiden Dateien arbeiten:

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

In können Toolbar.phpSie sehen

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

es ruft getAttributeUsedForSortByArray()von Config.phpdiesem Array von verfügbaren Attributen zum Sortieren der Auflistungssammlung auf.

Jetzt müssen Sie hier Ihr created_atAttribut hinzufügen . Wie? Ich habe es mit einem Plugin gemacht

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

Sie haben created_atin die verfügbaren Attribute zum Sortieren eingefügt. Jetzt müssen Sie nur noch Ihre benutzerdefinierte Sammlung erstellen, um sie zu verwenden. Hier entscheide ich mich \vendor\magento\module-catalog\Block\Product\ProductList\Toolbar.php mit meinem zu überschreibenToolbar.php und zu überschreibensetCollection()

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

Das ist alles, für mich wirkt es wie ein Zauber.


Wenn jemand standardmäßig aufsteigend wechseln möchte, wechseln Sie } elseif ( $this->getCurrentDirection() == 'asc' ) {zu } else {.
Donnerstag,

2
Wenn Sie kein Plugin verwenden möchten, können Sie auch die integrierte öffentliche Funktion $block->addOrderToAvailableOrders('created_at', 'New')in Ihrer Sortiervorlage verwenden.
Donnerstag,

Können Sie die Lösung für das Sortieren von benutzerdefinierten Produktpreisen finden? @Luca
Dhaduk Mitesh

@DhadukMitesh sicher, Sie könnten einfach den obigen Code verwenden und den Attributcode created_atmit Ihrem benutzerdefinierten
Preisattributcode

Ich habe kein benutzerdefiniertes Preisattribut. Ich verwende die Standardpreis-Sortierung nach. Ich ändere nur in der Kerndatei, in der der Preis sortiert wird. und ich möchte meinen benutzerdefinierten Preis für eine Sammlung festlegen. Ich kann jedoch keinen benutzerdefinierten Preis für die Sammlung festlegen.
Dhaduk Mitesh

18

Wir können es erreichen, indem wir Plugins verwenden. Bitte erstellen Sie folgende Dateien in Ihrem Modul.

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

Dies funktioniert gut für mich, ohne eine Magento-Klasse neu zu schreiben.


das adressiert created_at nicht und funktioniert nicht für 2.1.9 - zumindest für mich
dawhoo 30.10.17

Könnten Sie bitte erläutern, wie aroundSetCollection funktioniert?
TheKitMurkit

undefinierte Variable $ collection,
jafar pinjar

4

Wenn Sie nur das Attribut " Erstellen um" verwenden möchten , können Sie dieses Attribut im Verwaltungsbereich in den Sortieroptionen aktivieren.

Beispiel:

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

Dieser Code von Setup / UpgradeData.php , es ist jedoch besser, stattdessen InstallData.php zu verwenden.


Wo wird dieser Code im Dateisystem hinzugefügt?
YorkieMagento

1
Warum ein benutzerdefiniertes Modul erstellen, um ein DB-Feld zu ändern? Ich denke nicht, dass es der beste Weg ist.
LucScu

2

Schritt 1 : Zuerst solltest du registration.php erstellen

Herstellername: Arun

Modulname: NewSorting

Vendor / Modulname / registration.php

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

Schritt 2 : Sie erstellen die Datei module.xml

Hersteller / Modulname / 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>

Schritt 3 : Sie erstellen ein Plugin

Hersteller / Modulname / 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>

Schritt 4 : Dann erstelle config.php

Hersteller / Modulname / 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;
    }
}

Schritt 5 : Überschreiben Sie die Toolbar.php ***

Hersteller / Modulname / Plugin / Produkt / Produktliste / 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;
    }
}

es funktioniert perfekt


Müssen nach dem Aktualisieren dieser Dateien Befehle in der CLI ausgeführt werden?
YorkieMagento

Muss nach dem Upgrade des CLI-Setups ausgeführt werden, Bereitstellung statischer Inhalte, Cache-Bereinigung, Neuindexierung
Arunprabakaran M

Vielen Dank an MSA, aber wenn ich den Upgrade-Befehl ausführe, heißt es "nichts zu aktualisieren". Verwenden von 2.2.5. Alles oben Genannte kopiert ... aber ich habe mich gefragt, was in der Registration.php-Datei enthalten ist, die Sie erwähnen, und wo Sie sie finden können.
YorkieMagento

Ich habe den Inhaltspfad der Registration.php-Datei aktualisiert: Vendor / Modulname / registration.php
Arunprabakaran M

Modul genau wie oben hinzugefügt und die Option 'Neu' wird im Frontend angezeigt. Es scheint die 'Position'-Option ersetzt zu haben, ist das zu erwarten? Ich kann die Option im Katalog im Admin-Bereich nicht sehen, da ich diese Standardoption festlegen möchte ... Vielen Dank.
YorkieMagento

0

Der Weg braucht keine Schreibcodes

  1. Suchen Sie das created_atProduktattribut in der DB-Tabelle eav_attributeund setzen Sie seine Spalte frontend_labelauf Created At(Standard ist null).

  2. Suchen Sie das created_atProduktattribut in der DB-Tabelle catalog_eav_attributeund setzen Sie die Spalte used_for_sort_byauf1 (Standard ist 0).

  3. Bereinigen Sie den Site-Cache und es funktioniert.

Beispiel: change table von 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;

Ich würde die DB-Werte nicht direkt ändern, insbesondere wenn es sich um Kerndaten handelt.
LucScu

@ LucScu Es ist nur ein weiterer einfacher Weg. Es wurden zwei DB-Felder geändert, die keine Rolle spielen. Sie können auch Codes verwenden, um die Funktion zu überschreiben. Die abgedeckte Funktion wird jedoch beim Versions-Upgrade geändert, und Sie müssen Ihre benutzerdefinierten Codes aktualisieren. Beide Methoden haben Vor- und Nachteile. Verwenden Sie benutzerdefinierte Codes für eine einfache Funktion ist ein bisschen übertrieben.
Key Shang
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.