分类
安装使用

Magento 2 + Elasticsearch 产品列表排序修改

本文来自社区成员 土豆 的投稿

在Magento2.4.x 版本之前也有人介绍过商品列表默认产品排序为新产品在前面的方法,但是在Magento2.4.X 强制使用Elasticserach后就不生效了。

例如:

https://forum.magentochina.org/t/magento2%E5%A6%82%E4%BD%95%E4%BF%AE%E6%94%B9%E9%BB%98%E8%AE%A4%E7%9A%84%E4%BA%A7%E5%93%81%E6%8E%92%E5%BA%8F%E6%96%B9%E5%BC%8F/130

if ($this->getCurrentOrder()) {
     if(($this->getCurrentOrder())=='position'){
             $this->_collection->setOrder('entity_id','desc');
     }
     else {
             $this->_collection->setOrder($this->getCurrentOrder(),$this->getCurrentDirection());
     }
 }

但是在 Magento2.4 开始强制使用 elasticsearch (简称ES) 后,以上方法已经不能生效。简单的说是因为FULLTEXT全文索引的缘故。由于使用了ES 后, 列表的相关商品数据都会通过索引进入ES 缓存里, 而使用类似 entity_id desc 这样的无法生效,因为 entity_id 并没有进入到ES 缓存数据的字段中。通过观察, Magento2.4.x 的 ES 里缓存的数据都是由属性为单位进入到ES 缓存中, 但是商品的 created_at 字段未进入到ES。 我在这里介绍只需要2个步骤,就可以让 created_at 属性进入到ES并作用于商品列表页默认叠加排序 (也包括搜索页)。

首先, 商品 created_at 属性在后台商品属性编辑里都无法查询到(因为它是Magento2里的隐藏属性),可以通过直接修改数据库或者更新脚本等方法, 更新以下SQL:

UPDATE catalog_eav_attribute AS cea
     INNER JOIN eav_attribute AS ea
         ON ea.attribute_id = cea.attribute_id AND ea.entity_type_id = 4
 SET cea.used_in_product_listing = 1, cea.used_for_sort_by = 1
 WHERE ea.attribute_code IN ('created_at');

以上更新会让 created_at 属性进入到商品列表字段和SORT BY的应用, 然后执行

php bin/magento index:reindex

刷新索引,等刷新完毕后, 再次查看ES 的商品缓存数据就包含了 created_at 数据。第一步完成。

然后,需要修改商品列表的 Toolbar 类, 原生文件是:

vendor/magento/module-catalog/Block/Product/ProductList/Toolbar.php

我们需要利用plugin修改它其中2个方法。 先在你已有的自定义模块 etc/di.xml 文件中添加以下代码:

<type name="Magento\Catalog\Block\Product\ProductList\Toolbar">
	<plugin name="yourpackage_yourmodel_block_productlist_toolbar"
		type="Yourpackage\Yourmodel\Plugin\Block\Product\ProductList\Toolbar"
		sortOrder="10000" />
</type>

其中 sortOrder 设置为10000的缘故是让这条修改权重尽可能的最后执行, 考虑到可能其他某些插件会优先执行其他算法。然后添加

Yourpackage\Yourmodel\Plugin\Block\Product\ProductList\Toolbar.php

该文件代码如下:

<?php
namespace Yourpackage\Yourmodel\Plugin\Block\Product\ProductList;

use Magento\Catalog\Block\Product\ProductList\Toolbar as VendorProductToolbar;

class Toolbar extends VendorProductToolbar
{ public function afterSetCollection( VendorProductToolbar $toolbar, $result) { $collection = $result->getCollection(); if (!$collection->isLoaded()){ $collection->setOrder('created_at','DESC'); $result->_collection = $collection; } return $result; } public function afterGetAvailableOrders(VendorProductToolbar $toolbar, $result) { if(array_key_exists('created_at', $result)){ unset($result['created_at']); } return $result; } }

其中 afterSetCollection 是最终增加 created_at 属性的 SORT 排序, 在使用ES的情况下, 每个应用于 SORT的属性字段都要事先单独插入到ES缓存中(就是第一步所作的内容),并设置 used_for_sort_by 为真,否则无法自动查询到匹配的排序字段。正是因为我们设置了 used_for_sort_by 为真,在商品列表 sort by 下拉窗口默认就会展示出来created_at,所以我们需要用 afterGetAvailableOrders 方法去隐藏该选项。

完成以上操作后,刷新缓存后就可以看到效果了。