@@ -63,7 +63,7 @@ public function afterFilter(\Magento\Framework\Filter\Template $subject, string
63
63
// Process any HTML content types, they need to be decoded on the front-end
64
64
if (strpos ($ result , 'data-content-type="html" ' ) !== false ) {
65
65
$ document = $ this ->getDomDocument ($ result );
66
- $ this ->decodeHtmlContentTypes ($ document );
66
+ $ this ->convertEncodedHtmlContentTypesToPlaceholders ($ document, $ uniqueNodeNameToDecodedOuterHtmlMap );
67
67
}
68
68
69
69
// 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
75
75
$ matches
76
76
);
77
77
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
+ }
79
89
}
80
90
81
91
return $ result ;
@@ -129,55 +139,43 @@ function ($errorNumber, $errorString) {
129
139
}
130
140
131
141
/**
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
133
143
*
134
144
* @param \DOMDocument $document
145
+ * @param array $uniqueNodeNameToDecodedOuterHtmlMap
135
146
*/
136
- private function decodeHtmlContentTypes (\DOMDocument $ document ): void
137
- {
147
+ private function convertEncodedHtmlContentTypesToPlaceholders (
148
+ \DOMDocument $ document ,
149
+ &$ uniqueNodeNameToDecodedOuterHtmlMap = []
150
+ ): void {
138
151
$ xpath = new \DOMXPath ($ document );
139
152
153
+ $ uniqueNodeNameToDecodedOuterHtmlMap = [];
154
+
140
155
/** @var $htmlContentTypeNodes \DOMNode[] */
141
156
$ 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
142
160
foreach ($ htmlContentTypeNodes as $ htmlContentTypeNode ) {
143
- // Store a decoded attribute on the element so we don't double decode
144
161
$ htmlContentTypeNode ->setAttribute ('data-decoded ' , 'true ' );
162
+ }
145
163
164
+ foreach ($ htmlContentTypeNodes as $ htmlContentTypeNode ) {
146
165
// if nothing exists inside the node, continue
147
166
if (!strlen (trim ($ htmlContentTypeNode ->nodeValue ))) {
148
167
continue ;
149
168
}
150
169
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 );
164
172
165
- $ import = $ fragDoc -> getElementsByTagName ( ' body ' )-> item ( 0 );
173
+ $ uniqueNodeName = ' a ' . md5 ( uniqid ( '' , true ) );
166
174
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 );
178
177
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 ;
181
179
}
182
180
}
183
181
0 commit comments