Configurable Product Dropdown Image Switch
-
21-02-2021 - |
سؤال
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.
^ 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;
}
المحلول
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.