Magento 2 Como adicionar uma classificação personalizada por opção

22

Preciso adicionar um filtro adicional com base no created_atatributo para classificar a lista de produtos por produto mais recente. Eu tentei descobrir isso usando o arquivo abaixo

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

mas como adicionar nosso ID de entidade getAvailableOrders()?

Chamal Chamikara
fonte

Respostas:

23

Se você deseja usar um atributo como created_atesse, ele não está em admin-> stores -> (attribute) product, porque os atributos definidos em admin têm a configuração Sorting in Product Listing = Yes/No, você deve trabalhar com esses dois arquivos:

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

Em Toolbar.phpque você pode ver

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

chama a getAttributeUsedForSortByArray()partir Config.phpdesse retorno da matriz de atributos disponíveis para classificar a coleção de listagens.

Agora, você deve adicionar seu created_atatributo aqui. Quão? Eu fiz isso com um plugin

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

Você inseriu created_atos atributos disponíveis para classificação, agora você só precisa criar sua coleção personalizada para usá-la. Aqui eu escolho substituir \vendor\magento\module-catalog\Block\Product\ProductList\Toolbar.php pelo meu Toolbar.phpe substituirsetCollection()

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

Isso é tudo, para mim funciona como um encanto.

LucScu
fonte
Se alguém quiser usar o padrão ascendente, mude } elseif ( $this->getCurrentDirection() == 'asc' ) {para } else {.
Thdan #
2
Além disso, se você não quiser usar um plug-in, também poderá usar a função pública interna $block->addOrderToAvailableOrders('created_at', 'New')no seu modelo de classificador.
thdoan
Você pode ter a solução para classificar o preço do produto personalizado? @Luca
Dhaduk Mitesh
@DhadukMitesh certeza, você pode simplesmente usar o código de código e alteração de atributo acima created_atcom o seu código personalizado atributo preço
LucScu
Não tenho atributo de preço personalizado. Eu uso a classificação padrão de preços por. Eu mudo apenas no arquivo principal onde o preço está classificando. e quero definir meu preço personalizado para uma coleção. mas não posso definir o preço personalizado na coleção.
Dhaduk Mitesh
19

Podemos conseguir isso usando Plugins. Por favor, crie os seguintes arquivos no seu módulo.

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

Isso está funcionando bem para mim sem reescrever nenhuma classe Magento.

Sumit Verma
fonte
isso não faz created_at endereço e não trabalhar para 2.1.9 - pelo menos para mim
dawhoo
Você poderia explicar como o aroundSetCollection funciona?
TheKitMurkit
variável $ indefinida coleção,
jafar pinjar 27/11
4

Se você deseja usar apenas o atributo Criar em , é possível ativar esse atributo no painel de administração nas opções de classificação.

Exemplo:

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

Este código de Setup / UpgradeData.php , mas será melhor usar o InstallData.php .

iproger
fonte
Onde esse código é adicionado no sistema de arquivos?
YorkieMagento
1
Por que criar um módulo personalizado para alterar um campo db? Eu não acho que é o melhor caminho.
LucScu 23/01
2

Etapa 1 : primeiro você deve criar registration.php

Nome do fornecedor: Arun

Nome do módulo: NewSorting

Fornecedor / Nome do módulo / registration.php

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

Etapa 2 : você cria module.xml

Fornecedor / Nome do módulo / 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>

Etapa 3 : você cria o plug-in

Fornecedor / Nome do módulo / 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>

Etapa 4 : depois crie o config.php

Fornecedor / Nome do módulo / Plugin / Modelo / 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;
    }
}

Etapa 5 : Substitua o Toolbar.php ***

Fornecedor / Nome do módulo / Plugin / Produto / Lista de produtos / 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;
    }
}

é funcionar perfeitamente

Arunprabakaran M
fonte
Quaisquer comandos a serem executados na CLI após a atualização desses arquivos, por favor?
YorkieMagento
Necessidade de executar após a atualização de configuração CLI, implantar estática de conteúdo, cache limpo, reindex
Arunprabakaran M
Graças à MSA, mas quando executo o comando upgrade, ele diz 'nada para atualizar'. Usando 2.2.5. Copiou todos os itens acima ... mas imaginou o que havia no arquivo Registration.php que você mencionou e onde localizá-lo?
YorkieMagento
Atualizei o caminho do conteúdo do arquivo Registration.php: Vendor / Modulename / registration.php
Arunprabakaran M
Adicionado módulo exatamente como acima e a opção 'new' aparece no front end. Parece ter substituído a opção 'posição' que é esperada? Não consigo ver a opção no catálogo no painel de administração, pois gostaria de fazer essa opção padrão ... Obrigado.
YorkieMagento
1

O caminho não precisa escrever códigos

  1. Localize o created_atatributo do produto na tabela DB eav_attribute, defina sua coluna frontend_labelcomo Created At(o padrão é nulo).

  2. Localize o created_atatributo do produto na tabela DB catalog_eav_attribute, defina sua coluna used_for_sort_bycomo 1(o padrão é 0).

  3. Limpe o cache do site e ele está funcionando.

Exemplo: alterar tabela pelo 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
fonte
Eu não mudaria diretamente os valores de banco de dados, especialmente se forem dados principais.
LucScu 5/12
@LucScu É apenas mais uma maneira mais fácil. Alterou dois campos de banco de dados que não importam. Você também pode usar códigos para substituir a função, mas a função coberta será alterada na atualização da versão e você precisará atualizar seus códigos personalizados. Ambos os métodos têm vantagens e desvantagens. Usar códigos personalizados para uma função simples é um pouco exagerado.
Key Shang
@SagarParikhSGR Eu usei e está funcionando. Preste atenção ao usar o direito attribute_id.
Key Shang
@KeyShang meu mal, está funcionando perfeitamente, votou :)
Sagar Parikh SGR