23

We have implemented the new inbuilt Swatches feature in our latest new site build When we enable the swatches on category pages the page load time goes from 2 seconds to 38 + seconds.

I was wondering if anyone else had had this issue and if so could give us an indication of any possible solutions?

We have tried EE 1.14.1 and CE 1.9.1 with 36 configurable products with swatches applied on the standard rwd theme and no other modules active.

This issue can't be resolved by caching as every time a user searches or filters a category the page grinds to a halt again.

  • I cannot reproduce this. Please give us some more direction on the type of plugins installed, theme etc. Please follow the Magento debugging process by disabling your theme, disabling local modules and re-try. – philwinkle Feb 13 '15 at 19:29
  • The attributes we are using are colour swatches and sizes no more than 8 per item and in most cases no more than 4. This is being run on a blank magento CE 1.9.1 installation with sample data loaded and 10 configurable products with the custom swatches added. Its definitely associated with the swatches as the more we add the slower the site gets. Please note that caching is turned off to test this as users can filter the search and we cant have a crazy load time each time a user tweaks their search. Thanks for your time :) – Dave Bevington Feb 16 '15 at 9:01
22

Right. I detect problem on Mage_ConfigurableSwatches_Helper_Mediafallback::attachConfigurableProductChildrenAttributeMapping function.

I make some changes on it. This increase performance.

Try:

  1. Copy /app/code/core/Mage/ConfigurableSwatches/Helper/Mediafallback.php to /app/code/local/Mage/ConfigurableSwatches/Helper/Mediafallback.php.

  2. On /app/code/local/Mage/ConfigurableSwatches/Helper/Mediafallback.php file move this code (ll.88-91)

     // 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);
    

    up to before the foreach loop.

This is the changed method:

 /**
 * Set child_attribute_label_mapping on products with attribute label -> product mapping
 * Depends on following product data:
 * - product must have children products attached
 *
 * @param array $parentProducts
 * @param $storeId
 * @return void
 */
public function attachConfigurableProductChildrenAttributeMapping(array $parentProducts, $storeId)
{
    $listSwatchAttr = Mage::helper('configurableswatches/productlist')->getSwatchAttribute();

    $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()
        ->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();

        /* @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, we can't process it
                if (!$childProduct->hasData($attribute->getAttributeCode())) {
                    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'];
                }
            } // end looping child products
        } // end looping attributes


        foreach ($mapping as $key => $value) {
            $mapping[$key]['product_ids'] = array_unique($mapping[$key]['product_ids']);
        }

        $parentProduct->setChildAttributeLabelMapping($mapping)
            ->setListSwatchAttrValues($listSwatchValues);
    } // end looping parent products
}
  • I was having the same problem with swatches enabled on the list pages and this helped speed things up considerably, so thanks! – Marlon Creative Jun 4 '15 at 17:33
  • I found the same problem. resolving it took the page load from 2.5 minutes to 7 seconds. – Andrew Kett Jun 19 '15 at 6:14
  • These swatches really slow down the categories especially when you have a lot of confugurable products. The solution of Андрей М. cut down the loading from 10 to 3 seconds on a category full with configurable products! Thank you! – user1895954 Aug 11 '15 at 9:48
  • +1! Thanks for sharing this. We are using a lot of configurable with several options each and just couldn't use color swatches anymore... – Marc Feb 22 '16 at 11:39
  • +1! Absolutely brilliant answer, loading time changed from 28 seconds to 3 seconds! Thank you!! – K.I Feb 6 at 11:19
4

Additional way to improve performance configurable swatches when you have a lot of attribute options.

For example if you have 2000 options and show 36 products in catalog list, in this case method Mage_ConfigurableSwatches_Model_Resource_Catalog_Product_Attribute_Super_Collection::_loadOptionLabels() will join to each super_attributes option labels and you will get 2000 * 36 = 72000 rows.

I have rewritten this method and it loads only 2000 rows instead 72000

<?php
/**
 * Load attribute option labels for current store and default (fallback)
 *
 * @return $this
 */
protected function _loadOptionLabels()
{
    if ($this->count()) {
        $labels = $this->_getOptionLabels();
        foreach ($this->getItems() as $item) {
            $item->setOptionLabels($labels);
        }
    }
    return $this;
}

/**
 * Get Option Labels
 *
 * @return array
 */
protected function _getOptionLabels()
{
    $attributeIds = $this->_getAttributeIds();

    $select = $this->getConnection()->select();
    $select->from(array('options' => $this->getTable('eav/attribute_option')))
        ->join(
            array('labels' => $this->getTable('eav/attribute_option_value')),
            'labels.option_id = options.option_id',
            array(
                'label' => 'labels.value',
                'store_id' => 'labels.store_id',
            )
        )
        ->where('options.attribute_id IN (?)', $attributeIds)
        ->where(
            'labels.store_id IN (?)',
            array(Mage_Catalog_Model_Abstract::DEFAULT_STORE_ID, $this->getStoreId())
        );

    $resultSet = $this->getConnection()->query($select);
    $labels = array();
    while ($option = $resultSet->fetch()) {
        $labels[$option['option_id']][$option['store_id']] = $option['label'];
    }
    return $labels;
}

/**
 * Get Attribute IDs
 *
 * @return array
 */
protected function _getAttributeIds()
{
    $attributeIds = array();
    foreach ($this->getItems() as $item) {
        $attributeIds[] = $item->getAttributeId();
    }
    $attributeIds = array_unique($attributeIds);

    return $attributeIds;
}

protected by Community Sep 8 '15 at 9:04

Thank you for your interest in this question. Because it has attracted low-quality or spam answers that had to be removed, posting an answer now requires 10 reputation on this site (the association bonus does not count).

Would you like to answer one of these unanswered questions instead?

Not the answer you're looking for? Browse other questions tagged or ask your own question.