Skip to content

Commit 8d27320

Browse files
committed
MC-15022: HTML Content type does not render self closing html tags on storefront
Use DOMDocument constructor for fragment loading/parsing
1 parent 0eedb70 commit 8d27320

17 files changed

+163
-15
lines changed

app/code/Magento/PageBuilder/Plugin/Filter/TemplatePlugin.php

Lines changed: 38 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -129,30 +129,53 @@ function ($errorNumber, $errorString) {
129129
}
130130

131131
/**
132-
* Decode the contents of any HTML content types for the store front
132+
* Decode the contents of any HTML content types for the storefront
133133
*
134134
* @param \DOMDocument $document
135135
*/
136136
private function decodeHtmlContentTypes(\DOMDocument $document): void
137137
{
138138
$xpath = new \DOMXPath($document);
139-
$nodes = $xpath->query('//*[@data-content-type="html" and not(@data-decoded="true")]');
140-
foreach ($nodes as $node) {
141-
if (strlen(trim($node->nodeValue)) > 0) {
142-
/* @var \DOMElement $node */
143-
$fragment = $document->createDocumentFragment();
144-
$fragment->appendXML($node->nodeValue);
145-
// Store a decoded attribute on the element so we don't double decode
146-
$node->setAttribute("data-decoded", "true");
147-
$node->nodeValue = "";
148139

149-
// If the HTML code in the content type is invalid it may throw
150-
try {
151-
$node->appendChild($fragment);
152-
} catch (\Exception $e) {
153-
$this->logger->critical($e);
140+
/** @var $htmlContentTypeNodes \DOMNode[] */
141+
$htmlContentTypeNodes = $xpath->query('//*[@data-content-type="html" and not(@data-decoded="true")]');
142+
foreach ($htmlContentTypeNodes as $htmlContentTypeNode) {
143+
// Store a decoded attribute on the element so we don't double decode
144+
$htmlContentTypeNode->setAttribute('data-decoded', 'true');
145+
146+
if (!strlen(trim($htmlContentTypeNode->nodeValue))) {
147+
continue;
148+
}
149+
150+
$clonedHtmlContentTypeNode = clone $htmlContentTypeNode;
151+
$clonedHtmlContentTypeNode->nodeValue = '';
152+
153+
foreach ($htmlContentTypeNode->childNodes as $childNode) {
154+
if ($childNode->nodeType !== XML_TEXT_NODE) {
155+
$clonedHtmlContentTypeNode->appendChild($childNode);
156+
continue;
157+
}
158+
159+
$fragDoc = new \DOMDocument();
160+
$result = $fragDoc->loadHTML('<fragment>' . $childNode->nodeValue . '</fragment>');
161+
162+
if (!$result) {
163+
continue;
164+
}
165+
166+
$import = $fragDoc->getElementsByTagName('fragment')->item(0);
167+
foreach ($import->childNodes as $importedChildNode) {
168+
$importedNode = $document->importNode($importedChildNode, true);
169+
170+
try {
171+
$clonedHtmlContentTypeNode->appendChild($importedNode);
172+
} catch (\Exception $e) {
173+
$this->logger->critical($e);
174+
}
154175
}
155176
}
177+
178+
$htmlContentTypeNode->parentNode->replaceChild($clonedHtmlContentTypeNode, $htmlContentTypeNode);
156179
}
157180
}
158181

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
<div data-content-type="html">
2+
&lt;img src=&quot;http://example.com&quot;&gt;
3+
&lt;iframe width=&quot;560&quot; height=&quot;315&quot; src=&quot;https://www.youtube.com/embed/owsfdh4gxyc&quot; frameborder=&quot;0&quot; allowfullscreen&gt;&lt;/iframe&gt;
4+
</div>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
<div>
2+
<img src="http://example.com/block">
3+
</div>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Hello world
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
<?php
2+
/**
3+
* Copyright © Magento, Inc. All rights reserved.
4+
* See COPYING.txt for license details.
5+
*/
6+
7+
declare(strict_types=1);
8+
9+
namespace Magento\PageBuilder\Plugin\Filter;
10+
11+
use Magento\Widget\Model\Template\Filter as TemplateFilter;
12+
use Magento\TestFramework\Helper\Bootstrap;
13+
14+
/**
15+
* @magentoAppArea frontend
16+
*/
17+
class TemplatePluginTest extends \PHPUnit\Framework\TestCase
18+
{
19+
/**
20+
* @var \Magento\Framework\ObjectManagerInterface
21+
*/
22+
private $objectManager;
23+
24+
/**
25+
* @var TemplateFilter
26+
*/
27+
private $templateFilter;
28+
29+
protected function setUp()
30+
{
31+
$this->objectManager = Bootstrap::getObjectManager();
32+
$this->templateFilter = $this->objectManager->get(TemplateFilter::class);
33+
}
34+
35+
/**
36+
* @param string $preFiltered
37+
* @param string $postFiltered
38+
* @param string $preFilteredBasename
39+
* @dataProvider filterDataProvider
40+
*/
41+
public function testFiltering(string $preFiltered, string $postFiltered, string $preFilteredBasename)
42+
{
43+
$this->assertEquals(
44+
$postFiltered,
45+
$this->templateFilter->filter($preFiltered),
46+
"Failed asserting that two strings are equal after filtering $preFilteredBasename"
47+
);
48+
}
49+
50+
/**
51+
* @return array
52+
*/
53+
public function filterDataProvider(): array
54+
{
55+
$preFilteredFiles = glob(__DIR__ . '/../../_files/template_plugin/*pre_filter*');
56+
57+
$dataProviderArgs = [];
58+
59+
foreach ($preFilteredFiles as $preFilteredFile) {
60+
$preFilteredBasename = basename($preFilteredFile);
61+
$postFilteredFile = pathinfo($preFilteredFile, PATHINFO_DIRNAME) . '/' . str_replace(
62+
'pre_filter',
63+
'post_filter',
64+
$preFilteredBasename
65+
);
66+
67+
$dataProviderArgs[] = [
68+
file_get_contents($preFilteredFile),
69+
file_get_contents($postFilteredFile),
70+
$preFilteredBasename
71+
];
72+
}
73+
74+
return $dataProviderArgs;
75+
}
76+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
<div data-content-type="html" data-decoded="true">&amp;<img src="http://example.com"><iframe width="560" height="315" src="https://www.youtube.com/embed/owsfdh4gxyc" frameborder="0" allowfullscreen></iframe></div>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
<div data-content-type="html" data-decoded="true">&amp;<img src="http://example.com"><iframe width="560" height="315" src="https://www.youtube.com/embed/owsfdh4gxyc" frameborder="0" allowfullscreen></iframe></div>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
<div data-content-type="html" data-decoded="true"><img src="http://example.com"><iframe width="560" height="315" src="https://www.youtube.com/embed/owsfdh4gxyc" frameborder="0" allowfullscreen></iframe>
2+
</div>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
<div data-content-type="html">
2+
&lt;img src=&quot;http://example.com&quot;&gt;
3+
&lt;iframe width=&quot;560&quot; height=&quot;315&quot; src=&quot;https://www.youtube.com/embed/owsfdh4gxyc&quot; frameborder=&quot;0&quot; allowfullscreen&gt;&lt;/iframe&gt;
4+
</div>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
<div data-content-type="html" data-decoded="true"><img src="http://example.com"><iframe width="560" height="315" src="https://www.youtube.com/embed/owsfdh4gxyc" frameborder="0" allowfullscreen></iframe>
2+
<div data-content-type="html" data-decoded="true"><img src="http://example.com"><iframe width="560" height="315" src="https://www.youtube.com/embed/owsfdh4gxyc" frameborder="0" allowfullscreen></iframe>
3+
</div></div>

0 commit comments

Comments
 (0)