【问题标题】:How to display configurable product in each color in Magento product listing?如何在 Magento 产品列表中以每种颜色显示可配置产品?
【发布时间】:2011-02-20 06:56:25
【问题描述】:

我有一个可配置的产品,有多种颜色和尺寸可供选择。我希望可配置产品为每种颜色出现一次。我的想法是将每种颜色的可配置产品的一个简单产品分配给可配置产品的类别。然后我想更改列表,以便(彩色)简单产品链接到它的主产品(可配置产品)。

另一种方法是,将可配置产品分配给一个类别,然后用不同的颜色多次列出。但我认为这会很复杂。

解决方案

真诚地,我丢失了我的代码。但这是我的管理方式:

  1. 将所有从属产品的visibility 设置为catalog,以便它们 出现在产品列表中
  2. 覆盖产品模型及其 getProductUrl 函数:
    public function getProductUrl($useSid = null)
    {
    $product = $this;
    $product->loadParentProductIds();
        $parentIds = $product->getParentProductIds();

    if(count($parentIds) > 0 && $product->getTypeId() == Mage_Catalog_Model_Product_Type::TYPE_SIMPLE)
    {
            $parent = Mage::getModel("catalog/product")->setId($parentIds[0])->load();
            return $this->getUrlModel()->getProductUrl($parent, $useSid);
    }

    return $this->getUrlModel()->getProductUrl($product, $useSid);
    }

这样,每个从属产品都链接到它的主产品。棘手的部分是将属性附加到 url。您可以在 url 中添加#attributecode1=value1&attributecode2=value2 以预选属性选择框。我只有这部分又快又脏,我很确定有人可以做得更好。

预选示例:

http://demo.magentocommerce.com/anashria-womens-premier-leather-sandal-7.html http://demo.magentocommerce.com/anashria-womens-premier-leather-sandal-7.html#502=43

【问题讨论】:

  • 澄清一下,您有一系列简单的 SKU,并且您想为它们提供一堆产品页面,每个页面都允许客户选择颜色和尺寸?如果是这样,如果没有指定颜色,是否真的适合给产品贴上颜色标签?

标签: php magento2


【解决方案1】:

我不明白你们为什么不根据每种颜色的尺寸制作可配置的产品?这样你就不需要破解 Magento 的工作方式了。

如果您将一个简单产品作为可配置产品的一部分在前端可见,那么它不会链接到可配置产品,如果它是其中的一部分(正如您所发现的那样)。这对您来说也没有任何意义,因为如果您的可配置产品基于尺寸和颜色,那么简单产品将具有固定尺寸和颜色。

如果您只是为每种衬衫颜色制作了一个可配置的产品,那么您就完成了,功能齐全,并且没有黑客攻击。然后,您还可以使用相关产品来展示其他衬衫颜色。

黑客攻击越少越好。这是我的看法。

【讨论】:

  • 您的建议是正确的,但客户希望颜色和产品可以在详情页面上进行配置。无论如何,昨天我写了一个模块来显示我想要的产品。
【解决方案2】:

删除这个线程以防其他人需要在 Magento 2 中执行此操作。

以下是我的解决方案。请记住,它很hacky并且会破坏很多东西,所以只有当你是一个知道他/她在做什么并且可以修复或忍受这段代码的负面影响的Magento开发人员时才使用。

registration.php

<?php
use \Magento\Framework\Component\ComponentRegistrar;

ComponentRegistrar::register(ComponentRegistrar::MODULE, 'Antti_ConfigurableProductSplitter', __DIR__);

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="Antti_ConfigurableProductSplitter" >
        <sequence>
            <module name="Magento_Catalog" />
        </sequence>
    </module>
</config>

etc/frontend/events.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
{
    /**
     * @var ProductCollectionSplitter
     */
    private $productSplitter;

    /**
     * CatalogBlockProductCollectionBeforeToHtmlObserver constructor.
     *
     * @param ProductCollectionSplitter $productSplitter
     */
    public function __construct(
        ProductCollectionSplitter $productSplitter
    ) {
        $this->productSplitter = $productSplitter;
    }

    /**
     * @param \Magento\Framework\Event\Observer $observer
     *
     * @return $this
     * @throws \Magento\Framework\Exception\LocalizedException
     */
    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;
    }
}

观察者/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
{
    /**
     * @var EavConfig
     */
    private $eavConfig;

    /**
     * ProductDataMerger constructor.
     *
     * @param EavConfig $eavConfig
     */
    public function __construct(
        EavConfig $eavConfig
    ) {
        $this->eavConfig = $eavConfig;
    }

    /**
     * @param \Magento\Framework\Event\Observer $observer
     *
     * @return $this
     * @throws \Magento\Framework\Exception\LocalizedException
     */
    public function execute(\Magento\Framework\Event\Observer $observer)
    {
        $product = $observer->getEvent()->getSimple();
        $merged = $observer->getEvent()->getMerged();

        $this->setColorPreselected($merged, $product->getColor());

        return $this;
    }

    /**
     * @param ProductInterface $product
     * @param int $color
     *
     * @throws \Magento\Framework\Exception\LocalizedException
     */
    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);

        // TODO: should test whether this works if there is no url rewrite
        $product->setRequestPath(sprintf('%s#%d=%d', $product->getRequestPath(), $attribute->getId(), $color));
    }
}

模型/ProductDataMerger.php

<?php
namespace Antti\ConfigurableProductSplitter\Model;

use Magento\Catalog\Api\Data\ProductInterface;
use Magento\Framework\EntityManager\EventManager;

class ProductDataMerger
{
    /**
     * @var EventManager
     */
    private $eventManager;

    /**
     * @param EventManager $eventManager
     */
    public function __construct(
        EventManager $eventManager
    ) {
        $this->eventManager = $eventManager;
    }

    /**
     * @param ProductInterface $product
     * @param ProductInterface $parentProduct
     *
     * @return ProductInterface
     */
    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;
    }

    /**
     * @param ProductInterface $product
     * @param ProductInterface $childProduct
     */
    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'));
            }
        }
    }
}

模型/ProductCollectionSplitter.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
{
    /**
     * @var \Magento\Catalog\Model\Layer
     */
    private $catalogLayer;

    /**
     * @var ProductDataMerger
     */
    private $productDataMerger;

    /**
     * ProductCollectionSplitter constructor.
     *
     * @param Resolver $layerResolver
     * @param ProductDataMerger $productDataMerger
     */
    public function __construct(
        Resolver $layerResolver,
        ProductDataMerger $productDataMerger
    ) {
        $this->catalogLayer = $layerResolver->get();
        $this->productDataMerger = $productDataMerger;
    }

    /**
     * @param \Magento\Framework\Data\Collection $collection
     *
     * @return $this
     * @throws \Magento\Framework\Exception\LocalizedException
     */
    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) {
                /** @var \Magento\ConfigurableProduct\Model\ResourceModel\Product\Type\Configurable\Product\Collection $childProducts */
                $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;
    }

    /**
     * @return string|null
     * @throws \Magento\Framework\Exception\LocalizedException
     */
    private function getCurrentColorFilterValue()
    {
        /** @var \Magento\Catalog\Model\Layer\Filter\Item $filter */
        foreach ($this->catalogLayer->getState()->getFilters() as $filter) {
            if($filter->getFilter()->getAttributeModel()->getName() == 'color') {
                return $filter->getValueString();
            }
        }

        return null;
    }
}

已知问题:

  • 由于在加载后修改集合项,集合计数将是 无效,这可能会导致其他地方出现问题。
  • 此外,集合中的产品 ID 将无效,因为可配置项目的 ID 被简单产品的 ID 替换。
  • 如果将在其他地方再次加载集合,则不会拆分可配置产品。
  • 产品每页限制器不再起作用。
  • 产品列表中的产品数量无效。
  • Klevu 等第三方搜索模块可能无法正常工作
  • 其他第 3 方模块的实施可能存在问题。
  • 产品列表中的产品库存数据、评论等已损坏(尽管在前端可能很容易修复)。
  • 不确定在没有 url 重写的情况下是否可以实现(不过应该很容易修复)。
  • 其他我可能不知道的问题。

【讨论】:

  • 已知问题非常严重......我认为这不是一个很好的解决方案,它会影响许多内置功能,例如过滤、计数和分页
【解决方案3】:

一种方法是将尺寸和颜色作为目录号的一部分(或您用于产品的任何唯一标识号)

假设您有一个有 2 种颜色和 3 种尺寸的小部件,它的目录号是“qwe123”。您将在系统中输入以下 2 项以及适当的图像。我假设您已经有了处理尺寸的方法。

qwe123-红色
qwe123-蓝色

这样做不需要额外的编程,但是如果您想链接到产品页面上提供的其他颜色,那么您必须解析目录号的第一部分并搜索匹配的。

【讨论】:

  • 我无法更改 SKU,因为它将是商品的 EAN(从库存管理导入)。当我将单个产品添加到类别时,它不会链接到它的主(可配置)产品,而是链接到它自己的产品详细信息页面。
  • 我刚刚注意到你标记了这个我一无所知的“Magento”。所以我认为我不会有太大帮助。对不起,我以为你只是在写 php。
【解决方案4】:

为了将简单产品重定向到可配置的父产品,您可以为Magento\Catalog\Model\Product::getProductUrl()创建一个Plugin (Interceptor),用于更改简单产品的URL:

if ($product->getTypeId() === 'simple') {
    /*Get the configurable parent product URL and assign it to a simple product.*/
}

要在可配置产品中预选简单产品,简单产品的地址应如下所示:

/mona-pullover-hoodlie.html#143=167&amp;93=53

在哪里

/mona-pullover-hoodlie.html - 可配置的产品 URL,

14393 - 属性 ID,

167, 53 - 选项 ID。

属性ID和选项ID可以使用Magento\ConfigurableProduct\Model\Product\Type\Configurable::getConfigurableAttributesAsArray($product)函数获取。


我在 Magento Marketplace 上创建了一个 VCT Simple Product URL 模块来解决这个问题。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2017-10-01
    • 1970-01-01
    • 2015-11-25
    • 1970-01-01
    • 1970-01-01
    • 2013-01-29
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多