Question

I upgraded my site from EE 1.14.1.0 to 1.14.3.10 and now when I navigate to a configurable product that uses a drop down (not swatches) to change the image, the image does not change.

I have looked at the solutions in these exchanges, but none of them solved my issue:

Configurable products: product image not updating after selecting attribute in dropdown

^ This solution while it technically solves my problem, it doesn't keep the options in a dropdown, but switches them to swatches. We want the options to remain in a dropdown.

https://stackoverflow.com/questions/41845427/typeerror-product-configurableswatches-is-not-a-constructor-in-magento-1-9-3

^ This solution solves a JS error I also got, but doesn't fix the images switching part.

--

As soon as I navigate to the page, these errors are generated in system.log:

ERR (3): Warning: array_merge_recursive() expects at least 1 parameter, 0 given  in /app/code/core/Mage/ConfigurableSwatches/Helper/Productimg.php on line 336
ERR (3): Warning: array_unique() expects parameter 1 to be array, null given  in /app/code/core/Mage/ConfigurableSwatches/Helper/Productimg.php on line 337
ERR (3): Warning: array_map(): Argument #2 should be an array  in /app/code/core/Mage/ConfigurableSwatches/Helper/Productimg.php on line 340
ERR (3): Warning: array_merge(): Argument #1 is not an array  in /app/code/core/Mage/ConfigurableSwatches/Helper/Productimg.php on line 340
ERR (3): Warning: in_array() expects parameter 2 to be array, null given  in /app/code/core/Mage/ConfigurableSwatches/Helper/Productimg.php on line 345

Could this be what is causing the issue? If so, what might a solution be?

This was not an issue prior to updating. I have a support ticket out with Magento, but they are taking their sweet time (since November), so I thought I would see if anyone has any solutions.

--

Update 3/12

Magento sent me a patch that resolved the errors in system.log, but I am still unable to swap images based on the option selected in the dropdown.

In app/code/core/Mage/ConfigurableSwatches/Helper/Productimg.php update the filterImageInGallery function as follows:

public function filterImageInGallery($product, $image)
{
    if (!Mage::helper('configurableswatches')->isEnabled()) {
        return true;
    }

    if (!isset($this->_productImageFilters[$product->getId()])
        && $childAttributeLabelMapping = $product->getChildAttributeLabelMapping()
    ) {
        $mapping = call_user_func_array("array_merge_recursive", $childAttributeLabelMapping);
        $filters = array_unique($mapping['labels']);
        $filters = array_merge($filters, array_map(function ($label) {
            return $label . Mage_ConfigurableSwatches_Helper_Productimg::SWATCH_LABEL_SUFFIX;
        }, $filters));
        $this->_productImageFilters[$product->getId()] = $filters;

        return !in_array(Mage_ConfigurableSwatches_Helper_Data::normalizeKey($image->getLabel()),
            $this->_productImageFilters[$product->getId()]);
    }

    return true;
}
Was it helpful?

Solution

After getting a response from Magento that was "this is not part of native functionality" and thus it was "likely customized", I poked around some more on my own. What I've discovered is that for EE 1.14.3.10 this is a true statement, but for EE 1.14.1.0 it is not. I tested with a vanilla install of 1.14.1.0 and was able to switch the images using a dropdown without any customizations/extensions.

I ended up creating a new extension to override some of the configurable swatches functionality.

The files I copied from the vanilla 1.14.1.0 install into my new extension in 1.14.3.10 were:

/app/code/core/Mage/ConfigurableSwatches/Block/Catalog/Media/Js/Abstract.php
/app/code/core/Mage/ConfigurableSwatches/Helper/Mediafallback.php
/app/code/core/Mage/ConfigurableSwatches/Model/Observer.php

In my theme there were a couple of JS files that also had to be addressed:

/skin/frontend/[theme]/default/js/app.js

var ProductMediaManager = {
IMAGE_ZOOM_THRESHOLD: 20,
imageWrapper: null,

destroyZoom: function() {
    $j('.zoomContainer').remove();
    $j('.ds-product-image-gallery .gallery-image').removeData('elevateZoom');
},

createZoom: function(image) { [no changes] },

swapImage: function(targetImage) {
    ProductMediaManager.destroyZoom();

    var imageGallery = $j('.ds-product-image-gallery');

    imageGallery.slick('slickGoTo', targetImage);
},

wireThumbnails: function() {
    //trigger image change event on thumbnail click
    $j('.ds-product-image-thumbs .thumb-link').click( function(e) {
        e.preventDefault();
        var target = $j(this).data('imageIndex');
        ProductMediaManager.swapImage(target);
        $j("li.selected").removeClass("selected");
        $j(this).parent("li").addClass("selected");
    })

    $j('.ds-product-image-gallery').on( 'afterChange', function(e, slick, currentSlide) {
        var slide = $j(this).find('.gallery-image').eq(currentSlide);
        ProductMediaManager.createZoom(slide);
    });
},

initZoom: function() {
    [no changes]
},

init: function() { [no changes] }

};

/skin/frontend/dayspring/default/js/configurableswatches/product-media.js

getCompatibleProductImages: function(productFallback, selectedLabels) {
    //find compatible products
    var compatibleProducts = [];
    var compatibleProductSets = [];
    selectedLabels.each(function(selectedLabel) {
        if(typeof(productFallback['option_labels']) != 'undefined') {
            if (!productFallback['option_labels'][selectedLabel]) {
                return;
            }

            var optionProducts = productFallback['option_labels'][selectedLabel]['products'];
            compatibleProductSets.push(optionProducts);

            //optimistically push all products
            optionProducts.each(function (productId) {
                compatibleProducts.push(productId);
            });
        }
    });

    //intersect compatible products
    compatibleProductSets.each(function(productSet) {
        compatibleProducts = ConfigurableMediaImages.arrayIntersect(compatibleProducts, productSet);
    });

    return compatibleProducts;
},


getSwatchImage: function(productId, optionLabel, selectedLabels) {
    var fallback = ConfigurableMediaImages.productImages[productId];
    if(!fallback) {
        return null;
    }

    //first, try to get label-matching image on config product for this option's label
    if(typeof(fallback['option_labels']) != 'undefined') {
        var currentLabelImage = fallback['option_labels'][optionLabel];
        if (currentLabelImage && fallback['option_labels'][optionLabel]['configurable_product'][ConfigurableMediaImages.imageType]) {
            //found label image on configurable product
            return fallback['option_labels'][optionLabel]['configurable_product'][ConfigurableMediaImages.imageType];
        }
    }

    var compatibleProducts = ConfigurableMediaImages.getCompatibleProductImages(fallback, selectedLabels);

    if(compatibleProducts.length == 0) { //no compatible products
        return null; //bail
    }

    //second, get any product which is compatible with currently selected option(s)
    $j.each(fallback['option_labels'], function(key, value) {
        var image = value['configurable_product'][ConfigurableMediaImages.imageType];
        var products = value['products'];

        if(image) { //configurable product has image in the first place
            //if intersection between compatible products and this label's products, we found a match
            var isCompatibleProduct = ConfigurableMediaImages.arrayIntersect(products, compatibleProducts).length > 0;
            if(isCompatibleProduct) {
                return image;
            }
        }
    });

    //third, get image off of child product which is compatible
    var childSwatchImage = null;
    var childProductImages = fallback[ConfigurableMediaImages.imageType];
    compatibleProducts.each(function(productId) {
        if(childProductImages[productId] && ConfigurableMediaImages.isValidImage(childProductImages[productId])) {
            childSwatchImage = childProductImages[productId];
            return false; //break "loop"
        }
    });
    if (childSwatchImage) {
        return childSwatchImage;
    }

    //fourth, get base image off parent product
    if (childProductImages[productId] && ConfigurableMediaImages.isValidImage(childProductImages[productId])) {
        return childProductImages[productId];
    }

    //no fallback image found
    return null;
},

After creating this extension, I am now able to switch images by selecting an option from a dropdown.

Licensed under: CC-BY-SA with attribution
Not affiliated with magento.stackexchange
scroll top