| @@ -104,14 +104,12 @@ | ||
| 104 | 104 | if ($needsToRemoveClassName) { |
| 105 | 105 | $block = $this->removeTargetedClassAttribute($block); |
| 106 | 106 | $block = $this->removeClassAttributeFromAttrs($block); |
| 107 | 107 | // In some cases the block might become unformatted. |
| 108 | - foreach ($this->classesToTarget as $cls) { | |
| 109 | - $block['innerHTML'] = str_replace($cls, '', $block['innerHTML']); | |
| 110 | - $block['innerContent'] = array_map(function ($item) use ($cls) { | |
| 111 | - return !is_null($item) ? str_replace($cls, '', $item) : null; | |
| 112 | - }, ($block['innerContent'] ?? [])); | |
| 113 | - } | |
| 108 | + $block['innerHTML'] = $this->stripClassTokens($block['innerHTML']); | |
| 109 | + $block['innerContent'] = array_map(function ($item) { | |
| 110 | + return !is_null($item) ? $this->stripClassTokens($item) : null; | |
| 111 | + }, ($block['innerContent'] ?? [])); | |
| 114 | 112 | } |
| 115 | 113 | |
| 116 | 114 | return $block; |
| 117 | 115 | } |
| @@ -142,14 +140,10 @@ | ||
| 142 | 140 | $html = new \WP_HTML_Tag_Processor($htmlContent); |
| 143 | 141 | $html->next_tag('img'); |
| 144 | 142 | $src = $html->get_attribute('src'); |
| 145 | 143 | |
| 146 | - return $src && preg_match( | |
| 147 | - '(' . implode('|', array_map('preg_quote', ImageUploader::$imagesDomains, ['/'])) . ')i', | |
| 148 | - $src | |
| 149 | - ) | |
| 150 | - ? $src | |
| 151 | - : ''; | |
| 144 | + // Feeds a server-side fetch, so a path-matched domain would let any host through. | |
| 145 | + return ($src && ImageUploader::isAllowedImageHost($src)) ? $src : ''; | |
| 152 | 146 | } |
| 153 | 147 | |
| 154 | 148 | /** |
| 155 | 149 | * Update the content of the block to remove the targeted class attribute. |
| @@ -187,8 +181,35 @@ | ||
| 187 | 181 | return $content; |
| 188 | 182 | } |
| 189 | 183 | |
| 190 | 184 | /** |
| 185 | + * Build a pattern matching the class only where it stands as a whole token. | |
| 186 | + * | |
| 187 | + * @param string $targetedClass The class name to match. | |
| 188 | + * @return string | |
| 189 | + */ | |
| 190 | + protected function classTokenPattern($targetedClass) | |
| 191 | + { | |
| 192 | + // Uploaded filenames embed the class name (ext-imported-*.jpg); a bare substring match eats the src. | |
| 193 | + return '/(?<=[\s"\'])' . preg_quote($targetedClass, '/') . '(?=[\s"\'])/'; | |
| 194 | + } | |
| 195 | + | |
| 196 | + /** | |
| 197 | + * Remove the targeted classes from html the tag processor left untouched. | |
| 198 | + * | |
| 199 | + * @param string $content The html content. | |
| 200 | + * @return string | |
| 201 | + */ | |
| 202 | + protected function stripClassTokens($content) | |
| 203 | + { | |
| 204 | + foreach ($this->classesToTarget as $targetedClass) { | |
| 205 | + $content = preg_replace($this->classTokenPattern($targetedClass), '', $content); | |
| 206 | + } | |
| 207 | + | |
| 208 | + return $content; | |
| 209 | + } | |
| 210 | + | |
| 211 | + /** | |
| 191 | 212 | * Remove the targeted class from the className attrs. |
| 192 | 213 | * |
| 193 | 214 | * @param array $block The block. |
| 194 | 215 | * @return array The parsed block after updates. |
| @@ -256,14 +277,13 @@ | ||
| 256 | 277 | * @return boolean |
| 257 | 278 | */ |
| 258 | 279 | protected function hasTargetedClassName(array $block) |
| 259 | 280 | { |
| 260 | - if ( | |
| 261 | - array_reduce($this->classesToTarget, function (bool $carry, string $targetClass) use ($block) { | |
| 262 | - return $carry || (strpos(($block['innerHTML'] ?? ''), $targetClass) !== false); | |
| 263 | - }, false) | |
| 264 | - ) { | |
| 265 | - return true; | |
| 281 | + $innerHTML = ($block['innerHTML'] ?? ''); | |
| 282 | + foreach ($this->classesToTarget as $targetedClass) { | |
| 283 | + if (preg_match($this->classTokenPattern($targetedClass), $innerHTML)) { | |
| 284 | + return true; | |
| 285 | + } | |
| 266 | 286 | } |
| 267 | 287 | |
| 268 | 288 | $classList = is_array(($block['attrs']['className'] ?? null)) |
| 269 | 289 | ? $block['attrs']['className'] |