Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
42f7734
added tests - that will fail
sreichel Dec 7, 2025
06966f7
fix
sreichel Dec 7, 2025
acabadc
Update cypress/e2e/openmage/frontend/catalog/category.cy.js
sreichel Dec 7, 2025
74b55a4
Update cypress/e2e/openmage/frontend/catalog/product.cy.js
sreichel Dec 7, 2025
046fa8c
Update cypress/support/e2e.js
sreichel Dec 7, 2025
30c4f90
typo
sreichel Dec 7, 2025
3b309b7
Update app/code/core/Mage/ConfigurableSwatches/Helper/Mediafallback.php
sreichel Dec 7, 2025
4896d8b
typo
sreichel Dec 7, 2025
0fca36e
comment
sreichel Dec 7, 2025
bf78448
docblocks
sreichel Dec 9, 2025
418399b
revert changes
sreichel Dec 9, 2025
a04ce4b
sort collection
sreichel Dec 9, 2025
6e02e3d
template
sreichel Dec 9, 2025
51ccb38
normalize and keep orig value
sreichel Dec 9, 2025
172db87
sort by label
sreichel Dec 9, 2025
8e8b770
updated test
sreichel Dec 9, 2025
6d3670f
Merge branch 'main' into fix/5132
sreichel Dec 9, 2025
2d5978d
fix
sreichel Dec 9, 2025
bce653a
typo
sreichel Dec 9, 2025
51214db
phpcsfixer
sreichel Dec 9, 2025
37ec404
typo
sreichel Dec 9, 2025
41b6e93
test
sreichel Dec 9, 2025
5985deb
fix
sreichel Dec 9, 2025
294da98
Apply suggestions from code review
sreichel Dec 9, 2025
81f7ae6
escape
sreichel Dec 9, 2025
2bf9315
Merge remote-tracking branch 'origin/fix/5132' into fix/5132
sreichel Dec 9, 2025
731bd8e
escape
sreichel Dec 9, 2025
94fb4a1
revert
sreichel Dec 9, 2025
eb0eb47
Merge branch 'main' into fix/5132
sreichel Dec 10, 2025
177081c
Merge branch 'main' into fix/5132
sreichel Dec 10, 2025
bd4baef
copilot-instructions.md
sreichel Dec 10, 2025
6590fc2
escape
sreichel Dec 10, 2025
35d061d
type hints
sreichel Dec 10, 2025
18ab3f0
missing space
sreichel Dec 10, 2025
5c03939
escape
sreichel Dec 10, 2025
8a22330
minor
sreichel Dec 10, 2025
c4e46c7
fix
sreichel Dec 10, 2025
2679dd5
Merge branch 'main' into fix/5132
addison74 Dec 14, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .github/copilot-instructions.md
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ This project aims to provide a stable and secure version of Magento 1.x, with on
- Update comments to reflect changes in code.
- Update tests to cover new functionality and changes in code.
- Update copyright notices in new files.
- Do not add return types in docblocks if type hints are used.

## UI guidelines

Expand Down
8 changes: 8 additions & 0 deletions app/code/core/Mage/ConfigurableSwatches/Helper/Data.php
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,14 @@ public static function normalizeKey($key)
return trim(strtolower($key));
}

/**
* Wraps a key in a Normalized object that normalizes to lowercase but preserves original value
*/
public static function normalizeKeyToObject(?string $key): Mage_ConfigurableSwatches_Model_String_Normalized
{
return new Mage_ConfigurableSwatches_Model_String_Normalized($key);
}

/**
* Get list of attributes that should use swatches
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,8 +65,7 @@ public function attachConfigurableProductChildrenPricesMapping(array $products,
['product' => $product],
);
$configurablePrice = $product->getConfigurablePrice();
$cofigurableSwatchesHelper = Mage::helper('configurableswatches');
$result[$cofigurableSwatchesHelper::normalizeKey($attributePrice['store_label'])] = [
$result[Mage_ConfigurableSwatches_Helper_Data::normalizeKey($attributePrice['store_label'])] = [
'price' => $configurablePrice,
'oldPrice' => $this->_getHelper()->prepareOldPrice(
$product,
Expand Down
16 changes: 9 additions & 7 deletions app/code/core/Mage/ConfigurableSwatches/Helper/Mediafallback.php
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ public function attachProductChildrenAttributeMapping(array $parentProducts, $st

// normalize to all lower case before we start using them
$optionLabels = array_map(function ($value) {
return array_map(Mage_ConfigurableSwatches_Helper_Data::normalizeKey(...), $value);
return array_map(Mage_ConfigurableSwatches_Helper_Data::normalizeKeyToObject(...), $value);
}, $optionLabels);

foreach ($parentProducts as $parentProduct) {
Expand Down Expand Up @@ -109,7 +109,8 @@ public function attachProductChildrenAttributeMapping(array $parentProducts, $st
}

// using default value as key unless store-specific label is present
$optionLabel = $optionLabels[$optionId][$storeId] ?? $optionLabels[$optionId][0];
$optionLabelObject = $optionLabels[$optionId][$storeId] ?? $optionLabels[$optionId][0];
$optionLabel = (string) $optionLabelObject;

// initialize arrays if not present
if (!isset($mapping[$optionLabel])) {
Expand All @@ -119,7 +120,7 @@ public function attachProductChildrenAttributeMapping(array $parentProducts, $st
}

$mapping[$optionLabel]['product_ids'][] = $childProduct->getId();
$mapping[$optionLabel]['label'] = $optionLabel;
$mapping[$optionLabel]['label'] = $optionLabelObject;
$mapping[$optionLabel]['default_label'] = $optionLabels[$optionId][0];
$mapping[$optionLabel]['labels'] = $optionLabels[$optionId];

Expand Down Expand Up @@ -184,10 +185,11 @@ public function getConfigurableImagesFallbackArray(
// load images from the configurable product for swapping
if (is_array($mapping)) {
foreach ($mapping as $map) {
$mapLabel = (string) $map['label'];
$imagePath = null;

//search by store-specific label and then default label if nothing is found
$imageKey = array_search($map['label'], $imageHaystack);
$imageKey = array_search($mapLabel, $imageHaystack);
if ($imageKey === false) {
$imageKey = array_search($map['default_label'], $imageHaystack);
}
Expand All @@ -197,7 +199,7 @@ public function getConfigurableImagesFallbackArray(
$imagePath = $mediaGallery['images'][$imageKey]['file'];
}

$imagesByLabel[$map['label']] = [
$imagesByLabel[$mapLabel] = [
'configurable_product' => [
Mage_ConfigurableSwatches_Helper_Productimg::MEDIA_IMAGE_TYPE_SMALL => null,
Mage_ConfigurableSwatches_Helper_Productimg::MEDIA_IMAGE_TYPE_BASE => null,
Expand All @@ -206,11 +208,11 @@ public function getConfigurableImagesFallbackArray(
];

if ($imagePath) {
$imagesByLabel[$map['label']]['configurable_product']
$imagesByLabel[$mapLabel]['configurable_product']
[Mage_ConfigurableSwatches_Helper_Productimg::MEDIA_IMAGE_TYPE_SMALL]
= $this->_resizeProductImage($product, 'small_image', $keepFrame, $imagePath);

$imagesByLabel[$map['label']]['configurable_product']
$imagesByLabel[$mapLabel]['configurable_product']
[Mage_ConfigurableSwatches_Helper_Productimg::MEDIA_IMAGE_TYPE_BASE]
= $this->_resizeProductImage($product, 'image', $keepFrame, $imagePath);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,9 @@ protected function _getOptionLabels()
->where(
'labels.store_id IN (?)',
[Mage_Catalog_Model_Abstract::DEFAULT_STORE_ID, $this->getStoreId()],
);
)
->order('options.sort_order ASC')
->order('labels.value ASC');

$resultSet = $this->getConnection()->query($select);
$labels = [];
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
<?php

declare(strict_types=1);

/**
* @copyright For copyright and license information, read the COPYING.txt file.
* @link /COPYING.txt
* @license Open Software License (OSL 3.0)
* @package Mage_ConfigurableSwatches
*/

/**
* Wrapper to modify a string value with a method to get the original string value
*
* @package Mage_ConfigurableSwatches
*/
class Mage_ConfigurableSwatches_Model_String_Normalized implements Stringable

Check warning on line 17 in app/code/core/Mage/ConfigurableSwatches/Model/String/Normalized.php

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Rename class "Mage_ConfigurableSwatches_Model_String_Normalized" to match the regular expression ^[A-Z][a-zA-Z0-9]*$.

See more on https://sonarcloud.io/project/issues?id=OpenMage_magento-lts&issues=AZsFmxhtYGrH4_knPQOf&open=AZsFmxhtYGrH4_knPQOf&pullRequest=5133
{
/**
* The original, non-normalized string value.
*/
protected ?string $originalValue;

public function __construct(?string $originalValue)
{
$this->originalValue = $originalValue;
}

/**
* Get normalized string value
*/
public function __toString(): string
{
return Mage_ConfigurableSwatches_Helper_Data::normalizeKey($this->originalValue);
}

/**
* Get non-normalized original value
*/
public function getOriginalValue(): ?string
{
return $this->originalValue;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,10 @@

/** @var Mage_Core_Block_Template $this */

/** @var Mage_Catalog_Model_Product $_product */
$_product = $this->getProduct();

/** @var Mage_ConfigurableSwatches_Model_String_Normalized[] $_attrValues */
if (Mage::helper('configurableswatches')->isEnabled() && $_product && $_product->getId()
&& ($_attrValues = $_product->getListSwatchAttrValues()) && count($_attrValues) > 0):
$_attrStockValues = $_product->getListSwatchAttrStockValues();
Expand All @@ -25,31 +27,47 @@
<?php foreach ($_attrValues as $_optionValue => $_optionLabel): ?>
<?php
$_optionCode = Mage::helper('configurableswatches')->getHyphenatedString($_optionLabel);
$_swatchUrl = Mage::helper('configurableswatches/productimg')->getSwatchUrl($_product, $_optionLabel, $_swatchInnerWidth, $_swatchInnerHeight, $_swatchType);
$_swatchUrl = Mage::helper('configurableswatches/productimg')->getSwatchUrl(
$_product,
$_optionLabel,
$_swatchInnerWidth,
$_swatchInnerHeight,
$_swatchType
);

$_label = $this->escapeHtml($_optionLabel->getOriginalValue());
$_hasImage = !empty($_swatchUrl);
$_liClasses = [];
$_liClass = '';
$_aClass = 'swatch-link swatch-link-' . $_swatchAttribute->getId();
if ($_hasImage) {
if ($_swatchType == 'media') {
$_liClasses[] = 'is-media';
}
$_liClass .= $_swatchType == 'media' ? ' is-media' : '';
$_aClass .= ' has-image';
} elseif (strlen($_optionLabel) > 3) {
$_liClasses[] = 'wide-swatch';
} elseif (strlen($_label) > 3) {
$_liClass .= ' wide-swatch';
}
if (Mage::helper('configurableswatches/productlist')->swatchMatchesFilter($_optionValue)) {
$_liClasses[] = 'filter-match';
$_liClass .= ' filter-match';
}
$_liClass = (!empty($_liClasses)) ? ' ' . implode(' ', $_liClasses) : '';
?>
<li class="option-<?php echo $_optionCode; ?><?php echo $_liClass; ?>" data-product-id="<?php echo $_product->getId() ?>" data-option-label="<?php echo $_optionLabel ?>">
<a href="javascript:void(0)" name="<?php echo $_optionCode; ?>" class="<?php echo $_aClass ?>" title="<?php echo $_optionLabel; ?>"
style="height: <?php echo $_swatchOuterHeight ?>px; <?php if (!$_hasImage): ?>min-<?php endif ?>width: <?php echo $_swatchOuterWidth ?>px;">
<span class="swatch-label" style="height: <?php echo $_swatchInnerHeight ?>px; <?php if (!$_hasImage): ?>min-<?php endif ?>width: <?php echo $_swatchInnerWidth ?>px; line-height: <?php echo $_swatchInnerHeight ?>px;">
<li class="option-<?php echo $_optionCode ?><?php echo $_liClass ?>"
data-product-id="<?php echo $_product->getId() ?>"
data-option-label="<?php echo $_optionLabel ?>">
<a href="javascript:void(0)"
name="<?php echo $_optionCode ?>"
class="<?php echo $_aClass ?>"
title="<?php echo $_label ?>"
style="height: <?php echo $_swatchOuterHeight ?>px;
<?php if (!$_hasImage): ?>min-<?php endif ?>width: <?php echo $_swatchOuterWidth ?>px;">

Check warning on line 60 in app/design/frontend/rwd/default/template/configurableswatches/catalog/product/list/swatches.phtml

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Remove this deprecated "name" attribute.

See more on https://sonarcloud.io/project/issues?id=OpenMage_magento-lts&issues=AZsA0a70Rwmy363BMl0y&open=AZsA0a70Rwmy363BMl0y&pullRequest=5133
<span class="swatch-label"
style="height: <?php echo $_swatchInnerHeight ?>px;
<?php if (!$_hasImage): ?>min-<?php endif ?>width: <?php echo $_swatchInnerWidth ?>px; line-height: <?php echo $_swatchInnerHeight ?>px;">
<?php if ($_hasImage): ?>
<img src="<?php echo $_swatchUrl; ?>" alt="<?php echo $_optionLabel; ?>" width="<?php echo $_swatchInnerWidth ?>" height="<?php echo $_swatchInnerHeight ?>" />
<img src="<?php echo $_swatchUrl ?>"
alt="<?php echo $_label ?>"
width="<?php echo $_swatchInnerWidth ?>"
height="<?php echo $_swatchInnerHeight ?>" />
<?php else: ?>
<?php echo $_optionLabel; ?>
<?php echo $_label ?>
<?php endif ?>
</span>
<?php if (isset($_attrStockValues[$_optionValue]) && !$_attrStockValues[$_optionValue]): ?>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@ $_swatchOuterHeight = $this->getSwatchOuterHeight();

$_attr = $_attribute->getProductAttribute();
$_attrCode = $_attr->getAttributeCode();
/** @var string $_id */
$_id = $_attribute->getAttributeId();

$_swatchArray = $_config->attributes->$_id;
Expand All @@ -41,25 +40,44 @@ $_swatchArray = $_config->attributes->$_id;
<?php foreach ($_swatchArray->options as $_option): ?>
<?php
$_optionCode = Mage::helper('configurableswatches')->getHyphenatedString($_option->label);
$_swatchUrl = Mage::helper('configurableswatches/productimg')->getSwatchUrl($_product, $_option->label, $_swatchInnerWidth, $_swatchInnerHeight, $_swatchType);
$_swatchUrl = Mage::helper('configurableswatches/productimg')->getSwatchUrl(
$_product,
$_option->label,
$_swatchInnerWidth,
$_swatchInnerHeight,
$_swatchType
);

$_label = $this->escapeHtml($_option->label);
$_hasImage = !empty($_swatchUrl);
$_liClass = '';
$_aClass = 'swatch-link swatch-link-' . $_attribute->getAttributeId();
if ($_hasImage) {
$_liClass .= $_swatchType == 'media' ? ' is-media' : '';
$_aClass .= ' has-image';
} elseif (strlen($_option->label) > 3) {
} elseif (strlen($_label) > 3) {
$_liClass .= ' wide-swatch';
}
?>
<li class="option-<?php echo $_optionCode; ?><?php echo $_liClass; ?>" id="option<?php echo $_option->id; ?>">
<a href="javascript:void(0)" name="<?php echo $_optionCode; ?>" id="swatch<?php echo $_option->id; ?>" class="<?php echo $_aClass ?>" title="<?php echo $_option->label; ?>"
style="height: <?php echo $_swatchOuterHeight ?>px; <?php if (!$_hasImage): ?>min-<?php endif ?>width: <?php echo $_swatchOuterWidth ?>px;">
<span class="swatch-label" style="height: <?php echo $_swatchInnerHeight ?>px; <?php if (!$_hasImage): ?>min-<?php endif ?>width: <?php echo $_swatchInnerWidth ?>px; line-height: <?php echo $_swatchInnerHeight ?>px;">
<li class="option-<?php echo $_optionCode ?><?php echo $_liClass ?>"
id="option<?php echo $_option->id ?>">
<a href="javascript:void(0)"
name="<?php echo $_optionCode ?>"
id="swatch<?php echo $_option->id ?>"
class="<?php echo $_aClass ?>"
title="<?php echo $_label ?>"
style="height: <?php echo $_swatchOuterHeight ?>px;
<?php if (!$_hasImage): ?>min-<?php endif ?>width: <?php echo $_swatchOuterWidth ?>px;">
<span class="swatch-label"
style="height: <?php echo $_swatchInnerHeight ?>px;
<?php if (!$_hasImage): ?>min-<?php endif ?>width: <?php echo $_swatchInnerWidth ?>px; line-height: <?php echo $_swatchInnerHeight ?>px;">
<?php if ($_hasImage): ?>
<img src="<?php echo $_swatchUrl; ?>" alt="<?php echo $_option->label; ?>" width="<?php echo $_swatchInnerWidth ?>" height="<?php echo $_swatchInnerHeight ?>" />
<img src="<?php echo $_swatchUrl ?>"
alt="<?php echo $_label ?>"
width="<?php echo $_swatchInnerWidth ?>"
height="<?php echo $_swatchInnerHeight ?>" />
<?php else: ?>
<?php echo $_option->label; ?>
<?php echo $_label ?>
<?php endif ?>
</span>
<span class="x">X</span>
Expand Down
23 changes: 23 additions & 0 deletions cypress/e2e/openmage/frontend/catalog/category.cy.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
const test = cy.openmage.test.frontend.catalog.category.config;

describe('Check catalog category page', () => {
beforeEach('Go to page', () => {
cy.visit(test.url);
});

it('tests swatch: color', () => {
const options = 'ul.configurable-swatch-color';
const swatchLink = 'li a.swatch-link';
const colors = ['Charcoal', 'Khaki', 'Red', 'Royal Blue'];
const images = ['msj006t', 'msj006c-khaki', 'msj006c-red', 'msj006c-royal-blue'];

cy.get(options).eq(0).find(swatchLink).should('have.length', 4);

cy.get(options).eq(0).find(swatchLink).each((swatch, index) => {
cy.wrap(swatch).invoke('attr', 'title').should('eq', colors[index]);
cy.wrap(swatch).click();
cy.get('img.product-collection-image-404').should('have.attr', 'src').should('include', images[index]);
cy.wait(500);
});
});
})
36 changes: 36 additions & 0 deletions cypress/e2e/openmage/frontend/catalog/product.cy.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
const test = cy.openmage.test.frontend.catalog.product.config;

describe('Check catalog product page', () => {
beforeEach('Go to page', () => {
cy.visit(test.url);
});

it('tests swatch: color', () => {
const options = 'ul#configurable_swatch_color';
const swatchLink = 'li a.swatch-link';
const colors = ['Charcoal', 'Khaki', 'Red', 'Royal Blue'];
const images = ['msj006t_4', 'msj006c-khaki', 'msj006c-red', 'msj006c-royal-blue'];

cy.get(options).eq(0).find(swatchLink).should('have.length', 4);

cy.get(options).eq(0).find(swatchLink).each((swatch, index) => {
cy.wrap(swatch).invoke('attr', 'title').should('eq', colors[index]);
cy.wrap(swatch).click();
cy.get('img.gallery-image.visible').should('have.attr', 'src').should('include', images[index]);
cy.wait(500);
});
});

it('tests swatch: size', () => {
const options = 'ul#configurable_swatch_size';
const swatchLink = 'li a.swatch-link';
const sizes = ['XS', 'S', 'M', 'L', 'XL'];

cy.get(options).eq(0).find(swatchLink).should('have.length', 5);

cy.get(options).eq(0).find(swatchLink).each((swatch, index) => {
cy.get(options).eq(0).contains(sizes[index]).should('exist');
cy.wrap(swatch).invoke('attr', 'title').should('eq', sizes[index]);
});
});
})
2 changes: 2 additions & 0 deletions cypress/support/e2e.js
Original file line number Diff line number Diff line change
Expand Up @@ -61,5 +61,7 @@ import './openmage/backend/system/notification'
import './openmage/backend/system/store'
import './openmage/backend/system/variable'

import './openmage/frontend/catalog/category'
import './openmage/frontend/catalog/product'
import './openmage/frontend/customer/account'
import './openmage/frontend/homepage/newsletter'
3 changes: 3 additions & 0 deletions cypress/support/openmage/_utils/test.js
Original file line number Diff line number Diff line change
Expand Up @@ -302,6 +302,9 @@ cy.openmage.test.backend.system.variable = {};
* @type {{}}
*/
cy.openmage.test.frontend = {};
cy.openmage.test.frontend.catalog = {};
cy.openmage.test.frontend.catalog.category = {};
cy.openmage.test.frontend.catalog.product = {};
cy.openmage.test.frontend.customer = {};
cy.openmage.test.frontend.customer.account = {};
cy.openmage.test.frontend.homepage = {
Expand Down
5 changes: 5 additions & 0 deletions cypress/support/openmage/frontend/catalog/category.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
const test = cy.openmage.test.frontend.catalog.category;

test.config = {
url: cy.openmage.test.frontend.homepage._url + 'men/shirts.html'
}
5 changes: 5 additions & 0 deletions cypress/support/openmage/frontend/catalog/product.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
const test = cy.openmage.test.frontend.catalog.product;

test.config = {
url: cy.openmage.test.frontend.homepage._url + 'men/shirts/plaid-cotton-shirt-476.html'
}
Loading