Skip to content

Commit e1e2ca2

Browse files
committed
MC-15022: HTML Content type does not render self closing html tags on storefront
Generate decoded outer html map for replacement at end of processing
1 parent f75dcdb commit e1e2ca2

10 files changed

+71
-41
lines changed

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

Lines changed: 31 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ public function afterFilter(\Magento\Framework\Filter\Template $subject, string
6363
// Process any HTML content types, they need to be decoded on the front-end
6464
if (strpos($result, 'data-content-type="html"') !== false) {
6565
$document = $this->getDomDocument($result);
66-
$this->decodeHtmlContentTypes($document);
66+
$this->convertEncodedHtmlContentTypesToPlaceholders($document, $uniqueNodeNameToDecodedOuterHtmlMap);
6767
}
6868

6969
// If a document was retrieved we've modified the output so need to retrieve it from within the document
@@ -75,7 +75,17 @@ public function afterFilter(\Magento\Framework\Filter\Template $subject, string
7575
$matches
7676
);
7777

78-
return !empty($matches) ? $matches[1] : $result;
78+
if (!empty($matches)) {
79+
$docHtml = $matches[1];
80+
81+
if (isset($uniqueNodeNameToDecodedOuterHtmlMap)) {
82+
foreach ($uniqueNodeNameToDecodedOuterHtmlMap as $uniqueNodeName => $decodedOuterHtml) {
83+
$docHtml = str_replace("<$uniqueNodeName></$uniqueNodeName>", $decodedOuterHtml, $docHtml);
84+
}
85+
}
86+
87+
$result = $docHtml;
88+
}
7989
}
8090

8191
return $result;
@@ -129,55 +139,43 @@ function ($errorNumber, $errorString) {
129139
}
130140

131141
/**
132-
* Decode the contents of any HTML content types for the storefront
142+
* Convert encoded HTML content types to placeholders and generate decoded outer html map for future replacement
133143
*
134144
* @param \DOMDocument $document
145+
* @param array $uniqueNodeNameToDecodedOuterHtmlMap
135146
*/
136-
private function decodeHtmlContentTypes(\DOMDocument $document): void
137-
{
147+
private function convertEncodedHtmlContentTypesToPlaceholders(
148+
\DOMDocument $document,
149+
&$uniqueNodeNameToDecodedOuterHtmlMap = []
150+
): void {
138151
$xpath = new \DOMXPath($document);
139152

153+
$uniqueNodeNameToDecodedOuterHtmlMap = [];
154+
140155
/** @var $htmlContentTypeNodes \DOMNode[] */
141156
$htmlContentTypeNodes = $xpath->query('//*[@data-content-type="html" and not(@data-decoded="true")]');
157+
158+
// Preliminarily set decoded attribute on all encoded html content types so we don't double decode;
159+
// this needs to be done in a separate loop as contents will change throughout the subsequent loop
142160
foreach ($htmlContentTypeNodes as $htmlContentTypeNode) {
143-
// Store a decoded attribute on the element so we don't double decode
144161
$htmlContentTypeNode->setAttribute('data-decoded', 'true');
162+
}
145163

164+
foreach ($htmlContentTypeNodes as $htmlContentTypeNode) {
146165
// if nothing exists inside the node, continue
147166
if (!strlen(trim($htmlContentTypeNode->nodeValue))) {
148167
continue;
149168
}
150169

151-
// clone node and empty node value to prevent side-effects of modifying iterables in loop
152-
$clonedHtmlContentTypeNode = clone $htmlContentTypeNode;
153-
$clonedHtmlContentTypeNode->nodeValue = '';
154-
155-
foreach ($htmlContentTypeNode->childNodes as $childNode) {
156-
// if child node is not text node type, it does not need to be decoded; just append to cloned html node
157-
if ($childNode->nodeType !== XML_TEXT_NODE) {
158-
$clonedHtmlContentTypeNode->appendChild($childNode);
159-
continue;
160-
}
161-
162-
// Load node value into dom document in an attempt to decode any encoded html within
163-
$fragDoc = $this->createDomDocument($childNode->nodeValue);
170+
$preDecodedOuterHtml = $document->saveHTML($htmlContentTypeNode);
171+
$decodedOuterHtml = html_entity_decode($preDecodedOuterHtml);
164172

165-
$import = $fragDoc->getElementsByTagName('body')->item(0);
173+
$uniqueNodeName = 'a' . md5(uniqid('', true));
166174

167-
// Loop through decoded child nodes and import into the original document
168-
foreach ($import->childNodes as $importedChildNode) {
169-
$importedNode = $document->importNode($importedChildNode, true);
170-
171-
try {
172-
$clonedHtmlContentTypeNode->appendChild($importedNode);
173-
} catch (\Exception $e) {
174-
$this->logger->critical($e);
175-
}
176-
}
177-
}
175+
$uniqueNode = new \DOMElement($uniqueNodeName);
176+
$htmlContentTypeNode->parentNode->replaceChild($uniqueNode, $htmlContentTypeNode);
178177

179-
// replace original html content type node with cloned node we've been performing decoding operating on
180-
$htmlContentTypeNode->parentNode->replaceChild($clonedHtmlContentTypeNode, $htmlContentTypeNode);
178+
$uniqueNodeNameToDecodedOuterHtmlMap[$uniqueNodeName] = $decodedOuterHtml;
181179
}
182180
}
183181

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
<div data-content-type="html" data-appearance="default" data-element="main" style="border-style: none; border-width: 1px; border-radius: 0px; margin: 0px; padding: 0px;" data-decoded="true"><div id="fb-root"></div>
2+
<script async defer src="https://connect.facebook.net/en_US/sdk.js#xfbml=1&version=v3.2&appId=1&autoLogAppEvents=1"></script>
3+
4+
<div class="fb-page" data-href="https://www.facebook.com/facebook" data-tabs="timeline" data-small-header="false"
5+
data-adapt-container-width="true" data-hide-cover="false" data-show-facepile="true"><blockquote
6+
cite="https://www.facebook.com/facebook" class="fb-xfbml-parse-ignore"><a
7+
href="https://www.facebook.com/facebook">Facebook</a></blockquote></div>
8+
</div>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
<div data-content-type="html" data-appearance="default" data-element="main"
2+
style="border-style: none; border-width: 1px; border-radius: 0px; margin: 0px; padding: 0px;">&lt;div id="fb-root"&gt;&lt;/div&gt;
3+
&lt;script async defer src="https://connect.facebook.net/en_US/sdk.js#xfbml=1&amp;version=v3.2&amp;appId=1&amp;autoLogAppEvents=1"&gt;&lt;/script&gt;
4+
5+
&lt;div class="fb-page" data-href="https://www.facebook.com/facebook" data-tabs="timeline" data-small-header="false"
6+
data-adapt-container-width="true" data-hide-cover="false" data-show-facepile="true"&gt;&lt;blockquote
7+
cite="https://www.facebook.com/facebook" class="fb-xfbml-parse-ignore"&gt;&lt;a
8+
href="https://www.facebook.com/facebook"&gt;Facebook&lt;/a&gt;&lt;/blockquote&gt;&lt;/div&gt;
9+
</div>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
<div data-content-type="html" data-decoded="true">
2+
3 < 4 > 2
3+
</div>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
<div data-content-type="html">
2+
3 &lt; 4 &gt; 2
3+
</div>
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
<div data-content-type="html" data-decoded="true">
2-
<img src="http://example.com"><iframe width="560" height="315" src="https://www.youtube.com/embed/owsfdh4gxyc" frameborder="0" allowfullscreen></iframe>
2+
<img src="http://example.com">
3+
<iframe width="560" height="315" src="https://www.youtube.com/embed/owsfdh4gxyc" frameborder="0" allowfullscreen></iframe>
34
</div>
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
<div data-content-type="html" data-decoded="true">
2-
<img src="http://example.com"><iframe width="560" height="315" src="https://www.youtube.com/embed/owsfdh4gxyc" frameborder="0" allowfullscreen></iframe>
2+
<img src="http://example.com">
3+
<iframe width="560" height="315" src="https://www.youtube.com/embed/owsfdh4gxyc" frameborder="0" allowfullscreen></iframe>
34
<div data-content-type="html" data-decoded="true">
4-
<img src="http://example.com"><iframe width="560" height="315" src="https://www.youtube.com/embed/owsfdh4gxyc" frameborder="0" allowfullscreen></iframe>
5-
</div></div>
5+
<img src="http://example.com">
6+
<iframe width="560" height="315" src="https://www.youtube.com/embed/owsfdh4gxyc" frameborder="0" allowfullscreen></iframe>
7+
</div>
8+
</div>
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
11
<div data-content-type="html" data-decoded="true">
2-
<img src="http://example.com"><iframe width="560" height="315" src="https://www.youtube.com/embed/owsfdh4gxyc" frameborder="0" allowfullscreen></iframe>
2+
<img src="http://example.com">
3+
<iframe width="560" height="315" src="https://www.youtube.com/embed/owsfdh4gxyc" frameborder="0" allowfullscreen></iframe>
34
<div>
4-
<img src="http://example.com/block"></div></div>
5+
<img src="http://example.com/block">
6+
</div>
7+
</div>
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
<div data-content-type="html" data-decoded="true">
2-
<img src="http://example.com"><iframe width="560" height="315" src="https://www.youtube.com/embed/owsfdh4gxyc" frameborder="0" allowfullscreen></iframe>
2+
<img src="http://example.com">
3+
<iframe width="560" height="315" src="https://www.youtube.com/embed/owsfdh4gxyc" frameborder="0" allowfullscreen></iframe>
34
Hello world
45
</div>
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
<div data-content-type="text">
22
Hello there
33
<div data-content-type="html" data-decoded="true">
4-
<img src="http://example.com"><iframe width="560" height="315" src="https://www.youtube.com/embed/owsfdh4gxyc" frameborder="0" allowfullscreen></iframe>
4+
<img src="http://example.com">
5+
<iframe width="560" height="315" src="https://www.youtube.com/embed/owsfdh4gxyc" frameborder="0" allowfullscreen></iframe>
56
</div>
67
</div>

0 commit comments

Comments
 (0)