Magento 2 Cómo agregar ordenación personalizada por opción

22

Necesito agregar un filtro adicional basado en el created_atatributo para ordenar la lista de productos por último producto. Traté de resolverlo usando el archivo de abajo

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

pero ¿cómo podemos agregar nuestra identificación de entidad getAvailableOrders()?

Chamal Chamikara
fuente

Respuestas:

23

Si desea usar un atributo como created_atese no está en admin-> stores -> (attribute) product, porque los atributos definidos en admin tienen la configuración Sorting in Product Listing = Yes/No, debe trabajar con estos dos archivos:

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

En Toolbar.phppuedes ver

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

llama getAttributeUsedForSortByArray()desde Config.phpque devuelve una matriz de atributos disponibles para ordenar la colección de listados.

Ahora, debe agregar su created_atatributo aquí. ¿Cómo? Lo hice con 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;
}

Insertó created_atlos atributos disponibles para ordenar, ahora solo tiene que construir su colección personalizada para usarla. Aquí elijo anular \vendor\magento\module-catalog\Block\Product\ProductList\Toolbar.php con el mío Toolbar.phpy anularsetCollection()

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

Eso es todo, para mí funciona de maravilla.

LucScu
fuente
Si alguien quiere pasar de forma predeterminada a ascendente, cambie } elseif ( $this->getCurrentDirection() == 'asc' ) {a } else {.
Thdoan
2
Además, si no desea usar un complemento, también puede usar la función pública incorporada $block->addOrderToAvailableOrders('created_at', 'New')en su plantilla de clasificación.
thdoan
¿Puede tener la solución para clasificar el precio del producto personalizado? @Luca
Dhaduk Mitesh
@DhadukMitesh seguro, puede usar el código anterior y cambiar el código de atributo created_atcon su código de atributo de precio personalizado
LucScu
No tengo un atributo de precio personalizado. Yo uso el precio predeterminado ordenar por. Solo cambio en el archivo central donde se ordena el precio. y quiero establecer mi precio personalizado para una colección. pero no puedo establecer un precio personalizado en la colección.
Dhaduk Mitesh
19

Podemos lograrlo usando Plugins. Cree los siguientes archivos en su 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;
    }
}

Esto está funcionando bien para mí sin reescribir ninguna clase de Magento.

Sumit Verma
fuente
esto no se dirige a created_at y no funciona para 2.1.9 - al menos para mí
dawhoo
¿Podría explicar cómo funciona aroundSetCollection?
TheKitMurkit
colección $ variable indefinida,
jafar pinjar
4

Si desea utilizar solo el atributo Crear en , puede activar este atributo en el panel de administración en las opciones de clasificación.

Ejemplo:

<?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 , pero será mejor usar InstallData.php en su lugar.

iproger
fuente
¿Dónde se agrega este código en el sistema de archivos?
YorkieMagento
1
¿Por qué crear un módulo personalizado para cambiar un campo db? No creo que sea la mejor manera.
LucScu
2

Paso 1 : Primero debes crear registro.php

Nombre del vendedor: Arun

Nombre del módulo: NewSorting

Proveedor / nombre del módulo / registro.php

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

Paso 2 : crea module.xml

Proveedor / Nombre del 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>

Paso 3 : crea un complemento

Proveedor / Nombre del 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>

Paso 4 : luego crea config.php

Proveedor / Nombre del módulo / Complemento / 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;
    }
}

Paso 5 : anula la barra de herramientas.php ***

Proveedor / Nombre del módulo / Complemento / Producto / Lista de productos / 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 un trabajo perfecto

Arunprabakaran M
fuente
¿Algún comando que se ejecute en la CLI después de actualizar estos archivos, por favor?
YorkieMagento
Necesita ejecutarse después de la actualización de la configuración de la CLI, implementación de contenido estático, limpieza de caché,
reindexación
Gracias MSA pero cuando ejecuto el comando de actualización dice 'nada que actualizar'. Usando 2.2.5. Copié todo lo anterior ... pero se preguntó qué hay en el archivo Registration.php que menciona y dónde ubicarlo.
YorkieMagento
Actualicé la ruta de contenido del archivo Registration.php: Vendor / Modulename / Registration.php
Arunprabakaran M
Se agregó el módulo exactamente como se indica arriba y la opción 'nuevo' se muestra en el front end. Parece haber reemplazado la opción de 'posición', ¿es eso lo esperado? No puedo ver la opción en el catálogo en el panel de administración, ya que me gustaría hacer esta opción predeterminada ... Gracias.
YorkieMagento
1

El camino no necesita escribir códigos

  1. Busque el created_atatributo del producto en la tabla DB eav_attribute, establezca su columna frontend_labelen Created At(el valor predeterminado es nulo).

  2. Encuentre el created_atatributo del producto en la tabla DB catalog_eav_attribute, establezca su columna used_for_sort_byen 1(el valor predeterminado es 0).

  3. Limpie el caché del sitio y está funcionando.

Ejemplo: cambiar tabla por 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
fuente
No cambiaría directamente los valores de db, especialmente si se trata de datos básicos.
LucScu
@LucScu Es solo otra forma más fácil. Cambió dos campos de DB que no importan. También podría usar códigos para anular la función, pero la función cubierta se cambiará en la actualización de la versión, y debe actualizar sus códigos personalizados. Ambos métodos tienen ventajas y desventajas. Usar códigos personalizados para una función simple es un poco exagerado.
Key Shang
@SagarParikhSGR Lo usé y está funcionando. Presta atención al uso del derecho attribute_id.
Key Shang hace
@KeyShang, mi mal, está funcionando perfectamente, votado :)
Sagar Parikh SGR hace