phpmagentomagento-1.9configurable-productbootswatch

Magento1.9.3.3 Configurable Product Swatch bug


We just upgraded our site from Magento 1.9.1.1 to Magento 1.9.3.3.

Unfortunately, our site is broken, so I have investigated the issue. The error notification are as follow.


Fatal error: Uncaught Error: Call to undefined method 

Mage_ConfigurableSwatches_Helper_Mediafallback::attachProductChildrenAttributeMapping() in /var/www/html/source/app/code/core/Mage/ConfigurableSwatches/Model/Observer.php:59 Stack trace: #0 /var/www/html/source/app/code/core/Mage/Core/Model/App.php(1358): Mage_ConfigurableSwatches_Model_Observer-productListCollectionLoadAfter(Object(Varien_Event_Observer)) #1 /var/www/html/source/app/code/core/Mage/Core/Model/App.php(1337): Mage_Core_Model_App-_callObserverMethod(Object(Mage_ConfigurableSwatches_Model_Observer), 'productListColl...', Object(Varien_Event_Observer)) #2 /var/www/html/source/app/Mage.php(448): Mage_Core_Model_App-dispatchEvent('catalog_block_p...', Array) #3 /var/www/html/source/app/code/core/Mage/Catalog/Block/Product/List.php(160): Mage::dispatchEvent('catalog_block_p...', Array) #4 /var/www/html/source/app/code/core/Mage/Core/Block/Abstract.php(922): Mage_Catalog_Block_Product_Li in /var/www/html/source/app/code/core/Mage/ConfigurableSwatches/Model/Observer.php on line 59


That code block is as follow.

public function productListCollectionLoadAfter(Varien_Event_Observer $observer)
{
    if (!Mage::helper('configurableswatches')->isEnabled()) { // check if functionality disabled
        return; // exit without loading swatch functionality
    }

    /* @var $mediaHelper Mage_ConfigurableSwatches_Helper_Mediafallback */
    $mediaHelper = Mage::helper('configurableswatches/mediafallback');

    /** @var $priceHelper Mage_ConfigurableSwatches_Helper_List_Price */
    $priceHelper = Mage::helper('configurableswatches/list_price');

    /* @var $collection Mage_Catalog_Model_Resource_Product_Collection */
    $collection = $observer->getCollection();

    if ($collection
        instanceof Mage_ConfigurableSwatches_Model_Resource_Catalog_Product_Type_Configurable_Product_Collection) {
        // avoid recursion
        return;
    }

    $products = $collection->getItems();

    $mediaHelper->attachChildrenProducts($products, $collection->getStoreId());

    $mediaHelper->attachProductChildrenAttributeMapping($products, $collection->getStoreId());

    if ($priceHelper->isEnabled()) {
        $priceHelper->attachConfigurableProductChildrenPricesMapping($products, $collection->getStoreId());
    }

    $mediaHelper->attachGallerySetToCollection($products, $collection->getStoreId());

    /* @var $product Mage_Catalog_Model_Product */
    foreach ($products as $product) {
        $mediaHelper->groupMediaGalleryImages($product);
        Mage::helper('configurableswatches/productimg')
            ->indexProductImages($product, $product->getListSwatchAttrValues());
    }

}

The old block (Magento1.9.1.0) is follow.

public function productListCollectionLoadAfter(Varien_Event_Observer $observer)
{
    if (!Mage::helper('configurableswatches')->isEnabled()) { // check if functionality disabled
        return; // exit without loading swatch functionality
    }

    /* @var $helper Mage_ConfigurableSwatches_Helper_Mediafallback */
    $helper = Mage::helper('configurableswatches/mediafallback');

    /* @var $collection Mage_Catalog_Model_Resource_Product_Collection */
    $collection = $observer->getCollection();

    if ($collection
        instanceof Mage_ConfigurableSwatches_Model_Resource_Catalog_Product_Type_Configurable_Product_Collection) {
        // avoid recursion
        return;
    }

    $products = $collection->getItems();

    $helper->attachChildrenProducts($products, $collection->getStoreId());

    $helper->attachConfigurableProductChildrenAttributeMapping($products, $collection->getStoreId());

    $helper->attachGallerySetToCollection($products, $collection->getStoreId());

    /* @var $product Mage_Catalog_Model_Product */
    foreach ($products as $product) {
        $helper->groupMediaGalleryImages($product);
        Mage::helper('configurableswatches/productimg')
            ->indexProductImages($product, $product->getListSwatchAttrValues());
    }

}

To fix the site broken issue, I disabled the color swatch setting on System/Catalog/Configurable Swatches/General Settings.

Then, our site was retrieved. But, of course, color swatch functions didn't work anymore.

To ensure whether this issue is core bug or not, I installed raw Magento 1.9.3.3 on local server. But, the same issue.

Is there any solution?


Solution

  • To solve this issue, we checked the whole custom modules.

    app\code\local\Mage\ConfigurableSwatches\Helper\Mediafallback.php
    

    The old developer created this custom module so that new Magento version's Mediafallback.php didn't work. This is the correct original core php file.

    app\code\core\Mage\ConfigurableSwatches\Helper\Mediafallback.php

    public function attachProductChildrenAttributeMapping(array $parentProducts, $storeId, $onlyListAttributes = false)
    {
        /** @var  $listSwatchAttr Mage_Eav_Model_Attribute */
        $listSwatchAttr = Mage::helper('configurableswatches/productlist')->getSwatchAttribute();
        $swatchAttributeIds = array();
        if (!$onlyListAttributes) {
            $swatchAttributeIds = Mage::helper('configurableswatches')->getSwatchAttributeIds();
        }
        if ($listSwatchAttr->getId()) {
            $swatchAttributeIds[] = $listSwatchAttr->getId();
        }
        if (empty($swatchAttributeIds)) {
            return;
        }
    
        $parentProductIds = array();
        /* @var $parentProduct Mage_Catalog_Model_Product */
        foreach ($parentProducts as $parentProduct) {
            $parentProductIds[] = $parentProduct->getId();
        }
    
        $configAttributes = Mage::getResourceModel('configurableswatches/catalog_product_attribute_super_collection')
            ->addParentProductsFilter($parentProductIds)
            ->attachEavAttributes()
            ->addFieldToFilter('eav_attributes.attribute_id', array('in' => $swatchAttributeIds))
            ->setStoreId($storeId)
        ;
    
        $optionLabels = array();
        foreach ($configAttributes as $attribute) {
            $optionLabels += $attribute->getOptionLabels();
        }
    
        // normalize to all lower case before we start using them
        $optionLabels = array_map(function ($value) {
            return array_map('Mage_ConfigurableSwatches_Helper_Data::normalizeKey', $value);
        }, $optionLabels);
    
        foreach ($parentProducts as $parentProduct) {
            $mapping = array();
            $listSwatchValues = array();
            $listSwatchStockValues = array();
    
            /* @var $attribute Mage_Catalog_Model_Product_Type_Configurable_Attribute */
            foreach ($configAttributes as $attribute) {
                /* @var $childProduct Mage_Catalog_Model_Product */
                if (!is_array($parentProduct->getChildrenProducts())) {
                    continue;
                }
    
                foreach ($parentProduct->getChildrenProducts() as $childProduct) {
    
                    // product has no value for attribute or not available, we can't process it
                    $isInStock = $childProduct->getStockItem()->getIsInStock();
                    if (!$childProduct->hasData($attribute->getAttributeCode())
                        || (!$isInStock && !Mage::helper('cataloginventory')->isShowOutOfStock())) {
                        continue;
                    }
                    $optionId = $childProduct->getData($attribute->getAttributeCode());
    
                    // if we don't have a default label, skip it
                    if (!isset($optionLabels[$optionId][0])) {
                        continue;
                    }
    
                    // using default value as key unless store-specific label is present
                    $optionLabel = $optionLabels[$optionId][0];
                    if (isset($optionLabels[$optionId][$storeId])) {
                        $optionLabel = $optionLabels[$optionId][$storeId];
                    }
    
                    // initialize arrays if not present
                    if (!isset($mapping[$optionLabel])) {
                        $mapping[$optionLabel] = array(
                            'product_ids' => array(),
                        );
                    }
                    $mapping[$optionLabel]['product_ids'][] = $childProduct->getId();
                    $mapping[$optionLabel]['label'] = $optionLabel;
                    $mapping[$optionLabel]['default_label'] = $optionLabels[$optionId][0];
                    $mapping[$optionLabel]['labels'] = $optionLabels[$optionId];
    
                    if ($attribute->getAttributeId() == $listSwatchAttr->getAttributeId()
                        && !in_array($mapping[$optionLabel]['label'], $listSwatchValues)
                    ) {
                        $listSwatchValues[$optionId]      = $mapping[$optionLabel]['label'];
                        $listSwatchStockValues[$optionId] = $isInStock;
                    }
                } // end looping child products
            } // end looping attributes
    
    
            foreach ($mapping as $key => $value) {
                $mapping[$key]['product_ids'] = array_unique($mapping[$key]['product_ids']);
            }
    
            if (count($listSwatchValues)) {
                $listSwatchValues = array_replace(array_intersect_key($optionLabels, $listSwatchValues),
                    $listSwatchValues);
            }
            $parentProduct->setChildAttributeLabelMapping($mapping)
                ->setListSwatchAttrValues($listSwatchValues)
                ->setListSwatchAttrStockValues($listSwatchStockValues);
        } // end looping parent products
    }
    

    Also, these articles maybe help our solution.

    https://magento.stackexchange.com/questions/45948/how-to-use-magento-1-9-1-0-configurable-swatches-in-default-package-theme-or-a https://magento.stackexchange.com/questions/142404/configurable-swatches-not-working-after-1-9-3-upgrade