1

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;
}
0

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.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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