如果其他人需要在Magento 2中执行此操作,请坏死此线程。
下面是我的解决方案。请记住,它是黑客的,会破坏很多东西,所以只有当你是一个Magento开发人员,知道他/她在做什么,可以修复或生活在这个代码的负面影响。
登记php
<?php
use \Magento\Framework\Component\ComponentRegistrar;
ComponentRegistrar::register(ComponentRegistrar::MODULE, 'Antti_ConfigurableProductSplitter', __DIR__);
etc/模块。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="Antti_ConfigurableProductSplitter" >
<sequence>
<module name="Magento_Catalog" />
</sequence>
</module>
</config>
etc/前端/事件。xml
<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Event/etc/events.xsd">
<event name="catalog_block_product_list_collection">
<observer name="cps_catalog_block_product_list_collection" instance="Antti\ConfigurableProductSplitter\Observer\CatalogBlockProductCollectionBeforeToHtmlObserver" shared="false" />
</event>
<event name="cps_product_data_merge_after">
<observer name="cps_product_data_merge_after" instance="Antti\ConfigurableProductSplitter\Observer\SetColorPreselectedAfterProductDataMerge" shared="false" />
</event>
</config>
Observer/CatalogBlockProductCollectionBeforeToHtmlObserver。php
<?php
namespace Antti\ConfigurableProductSplitter\Observer;
use Magento\Framework\Event\ObserverInterface;
use Antti\ConfigurableProductSplitter\Model\ProductCollectionSplitter;
class CatalogBlockProductCollectionBeforeToHtmlObserver implements ObserverInterface
{
private $productSplitter;
public function __construct(
ProductCollectionSplitter $productSplitter
) {
$this->productSplitter = $productSplitter;
}
public function execute(\Magento\Framework\Event\Observer $observer)
{
$productCollection = $observer->getEvent()->getCollection();
if ($productCollection instanceof \Magento\Framework\Data\Collection) {
if (!$productCollection->isLoaded()) {
$productCollection->load();
}
$this->productSplitter->splitConfigurables($productCollection);
}
return $this;
}
}
Observer/SetColorPreselectedAfterProductDataMerge。php
<?php
namespace Antti\ConfigurableProductSplitter\Observer;
use Magento\Framework\Event\ObserverInterface;
use Magento\Catalog\Api\Data\ProductInterface;
use Magento\Eav\Model\Config as EavConfig;
class SetColorPreselectedAfterProductDataMerge implements ObserverInterface
{
private $eavConfig;
public function __construct(
EavConfig $eavConfig
) {
$this->eavConfig = $eavConfig;
}
public function execute(\Magento\Framework\Event\Observer $observer)
{
$product = $observer->getEvent()->getSimple();
$merged = $observer->getEvent()->getMerged();
$this->setColorPreselected($merged, $product->getColor());
return $this;
}
private function setColorPreselected(ProductInterface &$product, int $color)
{
$attribute = $this->eavConfig->getAttribute(\Magento\Catalog\Model\Product::ENTITY, 'color');
$preconfiguredValues = new \Magento\Framework\DataObject();
$preconfiguredValues->setData('super_attribute', [$attribute->getId() => $color]);
$product->setPreconfiguredValues($preconfiguredValues);
$product->setRequestPath(sprintf('%s#%d=%d', $product->getRequestPath(), $attribute->getId(), $color));
}
}
模型/产品数据合并。php
<?php
namespace Antti\ConfigurableProductSplitter\Model;
use Magento\Catalog\Api\Data\ProductInterface;
use Magento\Framework\EntityManager\EventManager;
class ProductDataMerger
{
private $eventManager;
public function __construct(
EventManager $eventManager
) {
$this->eventManager = $eventManager;
}
public function merge(ProductInterface $product, ProductInterface $parentProduct)
{
$merged = clone $parentProduct;
$merged->setParentId($merged->getId());
$merged->setId($product->getId());
$this->setImageFromChildProduct($merged, $product);
$this->eventManager->dispatch(
'cps_product_data_merge_after',
['merged' => $merged, 'simple' => $product, 'configurable' => $parentProduct]
);
return $merged;
}
public function setImageFromChildProduct(ProductInterface &$product, ProductInterface $childProduct)
{
foreach (['image', 'small_image', 'thumbnail'] as $imageType) {
if ($childProduct->getData($imageType) && $childProduct->getData($imageType) !== 'no_selection') {
$product->setData($imageType, $childProduct->getData($imageType));
} else {
$product->setData($imageType, $childProduct->getData('image'));
}
}
}
}
型号/产品集合拆分器。php
<?php
namespace Antti\ConfigurableProductSplitter\Model;
use Magento\ConfigurableProduct\Model\Product\Type\Configurable;
use Antti\ConfigurableProductSplitter\Model\ProductDataMerger;
use Magento\Catalog\Model\Layer\Resolver;
class ProductCollectionSplitter
{
private $catalogLayer;
private $productDataMerger;
public function __construct(
Resolver $layerResolver,
ProductDataMerger $productDataMerger
) {
$this->catalogLayer = $layerResolver->get();
$this->productDataMerger = $productDataMerger;
}
public function splitConfigurables(\Magento\Framework\Data\Collection $collection)
{
$items = $collection->getItems();
if (sizeof($items) == 0) {
return $this;
}
$configurables = $otherProducts = [];
$colorFilterValue = $this->getCurrentColorFilterValue();
foreach ($items as $index => $product) {
if ($product->getTypeId() === Configurable::TYPE_CODE) {
$childProducts = $product->getTypeInstance()->getUsedProductCollection($product);
if ($colorFilterValue !== null) {
$childProducts->addAttributeToFilter('color', ['eq' => $colorFilterValue]);
}
$childProducts->groupByAttribute('color');
foreach ($childProducts as $childProduct) {
$childProduct->setParentId($product->getId());
$otherProducts[] = $childProduct;
}
$configurables[$product->getId()] = $product;
} else {
$otherProducts[] = $product;
}
$collection->removeItemByKey($index);
}
foreach ($otherProducts as $product) {
if ($product->getParentId() && isset($configurables[$product->getParentId()])) {
$product = $this->productDataMerger->merge($product, $configurables[$product->getParentId()]);
}
$collection->addItem($product);
}
return $this;
}
private function getCurrentColorFilterValue()
{
foreach ($this->catalogLayer->getState()->getFilters() as $filter) {
if($filter->getFilter()->getAttributeModel()->getName() == 'color') {
return $filter->getValueString();
}
}
return null;
}
}
已知问题:
-
由于加载后修改了集合项目,因此集合计数将为
无效,这可能会在其他地方引起问题。
-
此外,集合中的产品ID将无效,因为可配置项的ID将被简单产品的ID替换。
-
如果集合将再次加载到其他地方,则可配置产品不会被拆分。
-
产品每页限制器不再工作。
-
产品列表上的产品计数无效。
-
Klevu等第三方搜索模块可能无法工作
-
其他第三方模块的实现可能存在问题。
-
产品库存数据、评论等在产品列表中被打破(尽管在前端可能很容易修复)。
-
不确定在没有url重写的情况下实现是否可以工作(不过应该很容易修复)。
-
其他我可能不知道的问题。