Skip to content

Commit 85d3143

Browse files
Merge branch '2.4-develop' into PR_2025_06_25_muntianu
2 parents faa16c5 + 7bdafaa commit 85d3143

File tree

233 files changed

+27054
-1084
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

233 files changed

+27054
-1084
lines changed

app/bootstrap.php

Lines changed: 0 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -50,17 +50,6 @@
5050
$mask = file_exists($umaskFile) ? octdec(file_get_contents($umaskFile)) : 002;
5151
umask($mask);
5252

53-
if (empty($_SERVER['ENABLE_IIS_REWRITES']) || ($_SERVER['ENABLE_IIS_REWRITES'] != 1)) {
54-
/*
55-
* Unset headers used by IIS URL rewrites.
56-
*/
57-
unset($_SERVER['HTTP_X_REWRITE_URL']);
58-
unset($_SERVER['HTTP_X_ORIGINAL_URL']);
59-
unset($_SERVER['IIS_WasUrlRewritten']);
60-
unset($_SERVER['UNENCODED_URL']);
61-
unset($_SERVER['ORIG_PATH_INFO']);
62-
}
63-
6453
if (
6554
(!empty($_SERVER['MAGE_PROFILER']) || file_exists(BP . '/var/profiler.flag'))
6655
&& isset($_SERVER['HTTP_ACCEPT'])
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
<?php
2+
/**
3+
* Copyright 2025 Adobe
4+
* All Rights Reserved.
5+
*/
6+
declare(strict_types=1);
7+
8+
namespace Magento\Catalog\Model\Plugin\SpecialPricePluginForREST;
9+
10+
use Magento\Catalog\Model\Product\Price\SpecialPriceStorage;
11+
use Magento\Store\Model\StoreManagerInterface;
12+
13+
/**
14+
* Special price storage Plugin to handle website scope issue at the frontend (only for REST API calls)
15+
* @SuppressWarnings(PHPMD.CouplingBetweenObjects)
16+
*/
17+
class SpecialPriceStoragePlugin
18+
{
19+
/**
20+
* Constructor
21+
*
22+
* @param StoreManagerInterface $storeManager
23+
*/
24+
public function __construct(
25+
private StoreManagerInterface $storeManager
26+
) {
27+
}
28+
29+
/**
30+
* Around update plugin for REST api fix
31+
*
32+
* @param SpecialPriceStorage $subject
33+
* @param callable $proceed
34+
* @param array $prices
35+
* @SuppressWarnings(PHPMD.UnusedFormalParameter)
36+
*/
37+
public function aroundUpdate(SpecialPriceStorage $subject, callable $proceed, array $prices)
38+
{
39+
$prices = $this->applyWebsitePrices($prices);
40+
return $proceed($prices);
41+
}
42+
43+
/**
44+
* Function to get website id from current store id and then find all stores and apply prices to them
45+
*
46+
* @param array $formattedPrices
47+
*/
48+
private function applyWebsitePrices(array $formattedPrices): array
49+
{
50+
$newPrices = [];
51+
52+
foreach ($formattedPrices as $price) {
53+
// Add the original price first
54+
$newPrices[] = $price;
55+
56+
if ($price->getStoreId() == \Magento\Store\Model\Store::DEFAULT_STORE_ID) {
57+
continue;
58+
}
59+
60+
$store = $this->storeManager->getStore($price->getStoreId());
61+
$website = $store->getWebsite();
62+
$storeIds = $website->getStoreIds();
63+
64+
// Unset origin store view to avoid duplication
65+
unset($storeIds[$price->getStoreId()]);
66+
67+
foreach ($storeIds as $storeId) {
68+
/** @var \Magento\Catalog\Model\Product\Price\SpecialPrice $cloned */
69+
$cloned = clone $price;
70+
$cloned->setStoreId((int) $storeId);
71+
$newPrices[] = $cloned;
72+
}
73+
}
74+
75+
return $newPrices;
76+
}
77+
}

app/code/Magento/Catalog/Model/ResourceModel/Url.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -412,7 +412,7 @@ protected function _getCategories($categoryIds, $storeId = null, $path = null)
412412
if (!is_array($categoryIds)) {
413413
$categoryIds = [$categoryIds];
414414
}
415-
$isActiveExpr = $connection->getCheckSql('c.value_id > 0', 'c.value', 'c.value');
415+
$isActiveExpr = $connection->getCheckSql('c.value_id IS NOT NULL', 'c.value', 'd.value');
416416
$select = $connection->select()->from(
417417
['main_table' => $this->getTable('catalog_category_entity')],
418418
[
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
<?php
2+
/**
3+
* Copyright 2025 Adobe
4+
* All Rights Reserved.
5+
*/
6+
declare(strict_types=1);
7+
8+
namespace Magento\Catalog\Plugin;
9+
10+
use Magento\Catalog\Api\CategoryManagementInterface;
11+
use Magento\Catalog\Api\Data\CategoryTreeInterface;
12+
13+
/**
14+
* Performance optimizer plugin for CategoryManagement
15+
*/
16+
class CategoryManagementPerformanceOptimizer
17+
{
18+
private const DEFAULT_MAX_DEPTH = 3; // Limit depth to prevent timeouts
19+
20+
/**
21+
* Optimize getTree method with depth limits to prevent timeouts
22+
*
23+
* @param CategoryManagementInterface $subject
24+
* @param int|null $rootCategoryId
25+
* @param int|null $depth
26+
* @return array
27+
* @SuppressWarnings(PHPMD.UnusedFormalParameter)
28+
*/
29+
public function beforeGetTree(
30+
CategoryManagementInterface $subject,
31+
$rootCategoryId = null,
32+
$depth = null
33+
): array {
34+
// Limit depth to prevent performance issues
35+
$depth = $depth ?? self::DEFAULT_MAX_DEPTH;
36+
return [$rootCategoryId, $depth];
37+
}
38+
}

app/code/Magento/Catalog/Test/Mftf/Test/AdminChangeContentOfWysiwygEditorForDisabledByDefaultTest.xml

Lines changed: 275 additions & 0 deletions
Large diffs are not rendered by default.

app/code/Magento/Catalog/etc/db_schema.xml

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -285,6 +285,12 @@
285285
<index referenceId="CATALOG_CATEGORY_ENTITY_PATH" indexType="btree">
286286
<column name="path"/>
287287
</index>
288+
<!-- Performance optimization index for efficient tree traversal -->
289+
<index referenceId="CATALOG_CATEGORY_ENTITY_PARENT_ID_LEVEL_POSITION" indexType="btree">
290+
<column name="parent_id"/>
291+
<column name="level"/>
292+
<column name="position"/>
293+
</index>
288294
</table>
289295
<table name="catalog_category_entity_datetime" resource="default" engine="innodb"
290296
comment="Catalog Category Datetime Attribute Backend Table">
@@ -401,6 +407,11 @@
401407
<index referenceId="CATALOG_CATEGORY_ENTITY_INT_STORE_ID" indexType="btree">
402408
<column name="store_id"/>
403409
</index>
410+
<!-- Performance optimization index for is_active attribute filtering -->
411+
<index referenceId="CATALOG_CATEGORY_ENTITY_INT_STORE_ID_VALUE" indexType="btree">
412+
<column name="store_id"/>
413+
<column name="value"/>
414+
</index>
404415
</table>
405416
<table name="catalog_category_entity_text" resource="default" engine="innodb"
406417
comment="Catalog Category Text Attribute Backend Table">
@@ -506,6 +517,12 @@
506517
<index referenceId="CATALOG_CATEGORY_PRODUCT_PRODUCT_ID" indexType="btree">
507518
<column name="product_id"/>
508519
</index>
520+
<!-- Performance optimization index for product count queries -->
521+
<index referenceId="CATALOG_CATEGORY_PRODUCT_CATEGORY_ID_PRODUCT_ID_POSITION" indexType="btree">
522+
<column name="category_id"/>
523+
<column name="product_id"/>
524+
<column name="position"/>
525+
</index>
509526
</table>
510527
<table name="catalog_category_product_index" resource="default" engine="innodb"
511528
comment="Catalog Category Product Index">

app/code/Magento/Catalog/etc/db_schema_whitelist.json

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -157,7 +157,8 @@
157157
},
158158
"index": {
159159
"CATALOG_CATEGORY_ENTITY_LEVEL": true,
160-
"CATALOG_CATEGORY_ENTITY_PATH": true
160+
"CATALOG_CATEGORY_ENTITY_PATH": true,
161+
"CATALOG_CATEGORY_ENTITY_PARENT_ID_LEVEL_POSITION": true
161162
},
162163
"constraint": {
163164
"PRIMARY": true
@@ -216,7 +217,8 @@
216217
"index": {
217218
"CATALOG_CATEGORY_ENTITY_INT_ENTITY_ID": true,
218219
"CATALOG_CATEGORY_ENTITY_INT_ATTRIBUTE_ID": true,
219-
"CATALOG_CATEGORY_ENTITY_INT_STORE_ID": true
220+
"CATALOG_CATEGORY_ENTITY_INT_STORE_ID": true,
221+
"CATALOG_CATEGORY_ENTITY_INT_STORE_ID_VALUE": true
220222
},
221223
"constraint": {
222224
"PRIMARY": true,
@@ -276,7 +278,8 @@
276278
"position": true
277279
},
278280
"index": {
279-
"CATALOG_CATEGORY_PRODUCT_PRODUCT_ID": true
281+
"CATALOG_CATEGORY_PRODUCT_PRODUCT_ID": true,
282+
"CATALOG_CATEGORY_PRODUCT_CATEGORY_ID_PRODUCT_ID_POSITION": true
280283
},
281284
"constraint": {
282285
"PRIMARY": true,

app/code/Magento/Catalog/etc/webapi_rest/di.xml

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,4 +47,13 @@
4747
<type name="Magento\Catalog\Model\CategoryRepository">
4848
<plugin name="format_category_url_key_rest_api" type="Magento\Catalog\Plugin\Model\CategoryRepositoryPlugin" />
4949
</type>
50+
<type name="Magento\Catalog\Model\Product\Price\SpecialPriceStorage">
51+
<plugin name="vendor_special_price_rest_plugin"
52+
type="Magento\Catalog\Model\Plugin\SpecialPricePluginForREST\SpecialPriceStoragePlugin" />
53+
</type>
54+
<!-- Essential performance optimizations for category tree operations -->
55+
<type name="Magento\Catalog\Api\CategoryManagementInterface">
56+
<plugin name="categoryManagementPerformanceOptimizer"
57+
type="Magento\Catalog\Plugin\CategoryManagementPerformanceOptimizer" />
58+
</type>
5059
</config>

app/code/Magento/Catalog/view/adminhtml/web/js/product-gallery.js

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -355,6 +355,14 @@ define([
355355
imageData.isRemoved = true;
356356
$imageContainer.addClass('removed').hide().find('.is-removed').val(1);
357357

358+
// Reset all image role/type selections to 'no_selection' value
359+
// For each role (like base image, small image, etc.), clears both
360+
// the UI select element and the internal types data structure
361+
$.each(this.options.types, $.proxy(function (index, type) {
362+
this.element.find('.image-' + type.code).val('no_selection');
363+
this.options.types[index].value = 'no_selection';
364+
}, this));
365+
358366
this._contentUpdated();
359367
},
360368

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,27 @@
11
<?php
22
/**
3-
* Copyright 2014 Adobe
3+
* Copyright 2011 Adobe
44
* All Rights Reserved.
55
*/
66

77
/** @var $block \Magento\Catalog\Block\Product\View */
8+
/** @var $escaper \Magento\Framework\Escaper */
9+
10+
$product = $block->getProduct();
811
?>
912

1013
<meta property="og:type" content="product" />
1114
<meta property="og:title"
12-
content="<?= $block->escapeHtmlAttr($block->stripTags($block->getProduct()->getName())) ?>" />
15+
content="<?= $escaper->escapeHtmlAttr($block->stripTags($product->getName())) ?>" />
1316
<meta property="og:image"
14-
content="<?= $block->escapeUrl($block->getImage($block->getProduct(), 'product_base_image')->getImageUrl()) ?>" />
17+
content="<?= $escaper->escapeUrl($block->getImage($product, 'product_base_image')->getImageUrl()) ?>" />
1518
<meta property="og:description"
16-
content="<?= $block->escapeHtmlAttr($block->stripTags($block->getProduct()->getShortDescription())) ?>" />
17-
<meta property="og:url" content="<?= $block->escapeUrl($block->getProduct()->getProductUrl()) ?>" />
18-
<?php if ($priceAmount = $block->getProduct()
19+
content="<?= $escaper->escapeHtmlAttr($block->stripTags($product->getShortDescription())) ?>" />
20+
<meta property="og:url" content="<?= $escaper->escapeUrl($product->getProductUrl()) ?>" />
21+
<?php if ($product->getCanShowPrice() !== false && $priceAmount = $product
1922
->getPriceInfo()
2023
->getPrice(\Magento\Catalog\Pricing\Price\FinalPrice::PRICE_CODE)
2124
->getAmount()):?>
22-
<meta property="product:price:amount" content="<?= $block->escapeHtmlAttr($priceAmount) ?>"/>
25+
<meta property="product:price:amount" content="<?= $escaper->escapeHtmlAttr($priceAmount) ?>"/>
2326
<?= $block->getChildHtml('meta.currency') ?>
2427
<?php endif;?>

0 commit comments

Comments
 (0)