Skip to content

Commit 115e212

Browse files
allilevinewoocommercebot
authored andcommitted
Mirror package @woocommerce/email-editor-config from WooCommerce
Upstream-Ref: woocommerce/woocommerce@50ae0ef
1 parent 1d0b5f5 commit 115e212

File tree

5 files changed

+40
-2
lines changed

5 files changed

+40
-2
lines changed

changelog.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,10 @@
22

33
This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
44

5+
## [2.8.1](https://github.com/woocommerce/email-editor/releases/tag/2.8.1) - 2026-02-20
6+
7+
- Patch - Fix unbounded static cache memory leaks in vendor-prefixed CSS inlining dependencies (emogrifier and symfony/css-selector) for long-running processes. [#63365]
8+
59
## [2.8.0](https://github.com/woocommerce/email-editor/releases/tag/2.8.0) - 2026-02-17
610

711
- Minor - Fix spacing issues in email editor product collection rendering. [#63177]

composer.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
"license": "GPL-2.0-or-later",
66
"prefer-stable": true,
77
"minimum-stability": "dev",
8-
"version": "2.8.0",
8+
"version": "2.8.1",
99
"autoload": {
1010
"classmap": [
1111
"src/",

vendor-prefixed/packages/Pelago/Emogrifier/CssInliner.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -389,6 +389,7 @@ private function clearAllCaches(): void
389389
self::CACHE_KEY_SELECTOR => [],
390390
self::CACHE_KEY_COMBINED_STYLES => [],
391391
];
392+
DeclarationBlockParser::clearCache();
392393
}
393394

394395
/**

vendor-prefixed/packages/Pelago/Emogrifier/Utilities/DeclarationBlockParser.php

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,17 @@ final class DeclarationBlockParser
1919
*/
2020
private static $cache = [];
2121

22+
/**
23+
* Clears the static declaration block cache.
24+
*
25+
* This should be called between processing separate HTML documents to prevent
26+
* unbounded memory growth in long-running processes.
27+
*/
28+
public static function clearCache(): void
29+
{
30+
self::$cache = [];
31+
}
32+
2233
/**
2334
* CSS custom properties (variables) have case-sensitive names, so their case must be preserved.
2435
* Standard CSS properties have case-insensitive names, which are converted to lowercase.

vendor-prefixed/packages/Symfony/Component/CssSelector/CssSelectorConverter.php

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,13 @@ class CssSelectorConverter
2929
private $translator;
3030
private $cache;
3131

32+
/**
33+
* Maximum number of cached items per prefix before LRU eviction kicks in.
34+
*
35+
* @var int
36+
*/
37+
public static $maxCachedItems = 200;
38+
3239
private static $xmlCache = [];
3340
private static $htmlCache = [];
3441

@@ -64,6 +71,21 @@ public function __construct(bool $html = true)
6471
*/
6572
public function toXPath(string $cssExpr, string $prefix = 'descendant-or-self::')
6673
{
67-
return $this->cache[$prefix][$cssExpr] ?? $this->cache[$prefix][$cssExpr] = $this->translator->cssToXPath($cssExpr, $prefix);
74+
if (isset($this->cache[$prefix][$cssExpr])) {
75+
// Promote to most-recently-used position.
76+
$value = $this->cache[$prefix][$cssExpr];
77+
unset($this->cache[$prefix][$cssExpr]);
78+
79+
return $this->cache[$prefix][$cssExpr] = $value;
80+
}
81+
82+
$value = $this->translator->cssToXPath($cssExpr, $prefix);
83+
84+
if (\count($this->cache[$prefix] ?? []) >= self::$maxCachedItems) {
85+
// Evict least-recently-used entry.
86+
unset($this->cache[$prefix][\array_key_first($this->cache[$prefix])]);
87+
}
88+
89+
return $this->cache[$prefix][$cssExpr] = $value;
6890
}
6991
}

0 commit comments

Comments
 (0)