PluginProbe
FluentCart A New Era of eCommerce – Faster, Lighter, and Simpler / 1.7.1
FluentCart A New Era of eCommerce – Faster, Lighter, and Simpler v1.7.1
1.7.1 1.7.0 1.6.6 1.6.5 1.6.4 1.6.3 1.6.2 1.6.1 1.6.0 1.5.4 1.5.5 1.5.3 1.5.2 1.5.1 1.5.0 1.4.2 1.4.1 1.4.0 1.3.28 1.3.27 1.3.26 1.3.25 1.3.23 1.3.22 1.3.21 All 51 releases
← All changes | app/Services/Libs/Emogrifier/Emogrifier.php +32 -25 1.3.21 → 1.7.1 View file →
@@ -5,49 +5,56 @@
5 5 class Emogrifier
6 6 {
7 7 private $html = '';
8 8
9 - private $disableInvisibleNode = false;
10 -
11 9 public function __construct($html)
12 10 {
13 11 $this->html = (string) $html;
14 12 }
15 13
16 - public function disableInvisibleNodeRemoval()
14 + public function emogrify()
17 15 {
18 - $this->disableInvisibleNode = true;
19 - return $this;
16 + if (!class_exists('\FluentEmogrifier\Vendor\TijsVerkoyen\CssToInlineStyles\CssToInlineStyles')) {
17 + require_once __DIR__ . '/scoped-vendor/autoload.php';
18 + }
19 +
20 + return $this->handleTijsVerkoyen();
20 21 }
21 22
22 - public function emogrify()
23 + private function handleTijsVerkoyen()
23 24 {
24 - // check if php version is less than 8.1
25 - if (version_compare(phpversion(), '8.1', '<')) {
26 - return $this->handleLegacy();
25 + $css = '';
26 + $html = $this->html;
27 +
28 + if (preg_match_all('/<style[^>]*>(.*?)<\/style>/si', $html, $matches)) {
29 + $css = implode("\n", $matches[1]);
30 + $html = preg_replace('/<style[^>]*>.*?<\/style>/si', '', $html);
27 31 }
28 32
29 - if (!class_exists('\FluentEmogrifier\Vendor\Pelago\Emogrifier\CssInliner')) {
30 - require_once __DIR__ . '/scoped-vendor/autoload.php';
33 + // Preserve @media queries — TijsVerkoyen strips them during CSS processing
34 + // but email clients like Apple Mail and Gmail support them for responsive layouts.
35 + // Regex handles both spaced (@media screen) and minified (@media(max-width:600px)) forms.
36 + $mediaBlocks = '';
37 + if (preg_match_all('/@media\s*[^{]*\{(?:[^{}]*\{[^{}]*\})*[^{}]*\}/s', $css, $mediaMatches)) {
38 + $mediaBlocks = implode("\n", $mediaMatches[0]);
31 39 }
32 40
33 - if (!class_exists('\FluentEmogrifier\Vendor\Pelago\Emogrifier\CssInliner')) {
34 - return $this->handleLegacy();
35 - }
41 + $inliner = new \FluentEmogrifier\Vendor\TijsVerkoyen\CssToInlineStyles\CssToInlineStyles();
42 + $result = $inliner->convert($html, $css);
36 43
37 - // check if css inlines is available or not
38 - return \FluentEmogrifier\Vendor\Pelago\Emogrifier\CssInliner::fromHtml($this->html)
39 - ->inlineCss()
40 - ->render();
41 - }
44 + // Re-inject @media blocks for responsive email support
45 + if ($mediaBlocks) {
46 + $styleTag = '<style type="text/css">' . $mediaBlocks . '</style>';
42 47
43 - private function handleLegacy()
44 - {
45 - $emogrifier = new EmogrifierPhp7($this->html);
46 - if ($this->disableInvisibleNode) {
47 - $emogrifier->disableInvisibleNodeRemoval();
48 + if (stripos($result, '</head>') !== false) {
49 + $result = str_ireplace('</head>', $styleTag . '</head>', $result);
50 + } elseif (stripos($result, '<body') !== false) {
51 + $result = preg_replace('/<body/i', $styleTag . '<body', $result, 1);
52 + } else {
53 + $result = $styleTag . $result;
54 + }
48 55 }
49 56
50 - return $emogrifier->emogrify();
57 + return $result;
51 58 }
52 59
53 60 }