Magento 2 Jak dodać niestandardowe sortowanie według opcji

22

Muszę dodać dodatkowy filtr oparty na created_atatrybucie do sortowania listy produktów według najnowszego produktu. Próbowałem to rozgryźć, używając poniższego pliku

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

ale jak dodać identyfikator naszego podmiotu getAvailableOrders()?

Chamal Chamikara
źródło

Odpowiedzi:

23

Jeśli chcesz użyć takiego atrybutu created_at, nie ma go w admin-> sklepach -> (atrybutach), ponieważ atrybuty zdefiniowane w adminie mają ustawienie Sorting in Product Listing = Yes/No, musisz pracować z tymi dwoma plikami:

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

W Toolbar.phpwidać

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

wywołuje getAttributeUsedForSortByArray()z Config.phptego tablicę dostępnych atrybutów do sortowania kolekcji list.

Teraz musisz dodać created_attutaj swój atrybut. W jaki sposób? Zrobiłem to za pomocą wtyczki

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

Wstawiłeś created_atdostępne atrybuty do sortowania, teraz musisz tylko zbudować swoją własną kolekcję, aby z niej skorzystać. Tutaj wybieram zastąpienie \vendor\magento\module-catalog\Block\Product\ProductList\Toolbar.php moim Toolbar.phpi zastąpieniesetCollection()

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

To wszystko, dla mnie działa jak urok.

LucScu
źródło
Jeśli ktoś chce domyślnie rosnąć, zmień } elseif ( $this->getCurrentDirection() == 'asc' ) {na } else {.
thdoan
2
Ponadto, jeśli nie chcesz używać wtyczki, możesz również użyć wbudowanej funkcji publicznej $block->addOrderToAvailableOrders('created_at', 'New')w szablonie sortowania.
thdoan
Czy masz rozwiązanie do sortowania niestandardowej ceny produktu? @Luca
Dhaduk Mitesh
@DhadukMitesh na pewno możesz po prostu użyć powyższego kodu i zmienić kod atrybutu za created_atpomocą niestandardowego kodu atrybutu ceny
LucScu 17'18
Nie mam niestandardowego atrybutu ceny. Używam sortowania według ceny domyślnej. Zmieniam tylko podstawowy plik, w którym sortuje się cena. i chcę ustawić niestandardową cenę kolekcji. ale nie mogę ustawić niestandardowej ceny w kolekcji.
Dhaduk Mitesh
19

Możemy to osiągnąć za pomocą wtyczek. Utwórz następujące pliki w swoim 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;
    }
}

Działa to dla mnie dobrze bez przepisywania klas Magento.

Sumit Verma
źródło
nie dotyczy to
pliku create_at
Czy mógłbyś wyjaśnić, jak działa około SetCollection?
TheKitMurkit
niezdefiniowana zmienna $ collection,
jafar pinjar
4

Jeśli chcesz użyć tylko atrybutu Utwórz w , możesz aktywować ten atrybut w panelu administracyjnym w opcjach sortowania.

Przykład:

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

Ten kod z Setup / UpgradeData.php , ale lepiej będzie użyć InstallData.php .

iproger
źródło
Gdzie jest dodawany ten kod w systemie plików?
YorkieMagento
1
Po co tworzyć niestandardowy moduł do zmiany pola db? nie uważam, że to najlepszy sposób.
LucScu
2

Krok 1 : Najpierw powinieneś utworzyć register.php

Nazwa dostawcy: Arun

Nazwa modułu: NewSorting

Dostawca / nazwa modulatora / rejestracja.php

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

Krok 2 : Utwórz plik 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>

Krok 3 : Tworzysz wtyczkę

Dostawca / nazwa modulatora / 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>

Krok 4 : Następnie utwórz config.php

Producent / nazwa modulatora / wtyczka / 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;
    }
}

Krok 5 : Zastąp Toolbar.php ***

Producent / nazwa modulatora / wtyczka / produkt / lista produktów / 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;
    }
}

działa idealnie

Arunprabakaran M
źródło
Jakieś polecenia, które należy uruchomić w CLI po aktualizacji tych plików, proszę?
YorkieMagento
Konieczność uruchomienia po aktualizacji instalacji interfejsu CLI, wdrożeniu zawartości statycznej, czyszczeniu pamięci podręcznej, ponownym indeksowaniu
Arunprabakaran M
Dzięki MSA, ale kiedy uruchamiam polecenie aktualizacji, mówi „nic do aktualizacji”. Korzystanie z 2.2.5. Skopiowałem wszystkie powyższe ... ale zastanawiałeś się, co wspomniałeś w pliku Registration.php i gdzie go znaleźć?
YorkieMagento
Zaktualizowałem ścieżkę zawartości pliku Registration.php: Vendor / Modulename /
register.php
Dodano moduł dokładnie tak, jak powyżej, a opcja „nowa” wyświetla się z przodu. Wydaje się, że zastąpił opcję „pozycja”, czy jest to oczekiwane? Nie widzę opcji w katalogu w panelu administracyjnym, ponieważ chciałbym ustawić tę opcję domyślną ... Dziękuję.
YorkieMagento
1

Sposób nie wymaga pisania kodów

  1. Znajdź created_atatrybut produktu w tabeli DB eav_attribute, ustaw jego kolumnę frontend_labelna Created At(wartość domyślna to null).

  2. Znajdź created_atatrybut produktu w tabeli DB catalog_eav_attribute, ustaw jego kolumnę used_for_sort_byna 1(domyślnie 0).

  3. Wyczyść pamięć podręczną witryny i działa.

Przykład: zmień tabelę według 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
źródło
Nie zmieniłbym bezpośrednio wartości db, szczególnie jeśli są to podstawowe dane.
LucScu,
@LucScu To tylko kolejny łatwiejszy sposób. Zmieniło to dwa pola DB, które nie mają znaczenia. Możesz również użyć kodów do zastąpienia funkcji, ale funkcja objęta usługą zostanie zmieniona podczas aktualizacji wersji i musisz zaktualizować kody niestandardowe. Obie metody mają zalety i wady. Używanie niestandardowych kodów dla prostej funkcji to trochę przesada.
Key Shang
@SagarParikhSGR Użyłem go i działa. Zwróć uwagę na właściwe użycie attribute_id.
Key Shang
@KeyShang mój zły, działa idealnie, głosował :)
Sagar Parikh SGR