5

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

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

解决方案

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

  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。您可以添加#attributecode1=value1&attributecode2=value2到 url 以预选属性选择框。我只有这部分又快又脏,我很确定有人可以做得更好。

预选示例:

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

4

4 回答 4

2

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

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

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

黑客攻击越少越好。这是我的意见。

于 2010-05-18T12:23:27.303 回答
1

如果其他人需要在 Magento 2 中执行此操作,请删除此线程。

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

注册.php

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

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

等/模块.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>

等/前端/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>

观察者/目录块ProductCollectionBeforeToHtmlObserver.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 重写的情况下工作(虽然应该很容易修复)。
  • 其他我可能不知道的问题。
于 2019-10-28T12:53:27.063 回答
0

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

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

qwe123-红色
qwe123-蓝色

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

于 2010-05-17T07:16:32.787 回答
0

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

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

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

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

在哪里

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

143, 93- 属性 ID,

167, 53- 选项 ID。

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


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

于 2021-12-02T21:11:33.237 回答