From 26a51db1329e068d5bb3854ceb9c9217c69b3981 Mon Sep 17 00:00:00 2001 From: Aki Hamano Date: Thu, 12 Mar 2026 17:20:39 +0900 Subject: [PATCH 1/7] Icons Regstry: improveme SVG sanitizer --- .../class-gutenberg-icons-registry-7-1.php | 605 ++++++++++++++++++ ...lass-gutenberg-icons-registry-7-1-test.php | 110 ++++ 2 files changed, 715 insertions(+) create mode 100644 phpunit/experimental/class-gutenberg-icons-registry-7-1-test.php diff --git a/lib/compat/wordpress-7.1/class-gutenberg-icons-registry-7-1.php b/lib/compat/wordpress-7.1/class-gutenberg-icons-registry-7-1.php index e827056064e7b1..f4aaa8c2717e00 100644 --- a/lib/compat/wordpress-7.1/class-gutenberg-icons-registry-7-1.php +++ b/lib/compat/wordpress-7.1/class-gutenberg-icons-registry-7-1.php @@ -50,6 +50,611 @@ protected function __construct() { } } + /** + * Sanitizes the icon SVG content. + * + * Uses WP_HTML_Processor to extract the SVG element in its entirety before + * applying wp_kses. This avoids issues where HTML tags like

inside the + * content would terminate the SVG element when parsed as HTML, and ensures + * proper handling of SVG structure including self-closing tags. + * + * @param string $icon_content The icon SVG content to sanitize. + * @return string The sanitized icon SVG content. + */ + protected function sanitize_icon_content( $icon_content ) { + // Core attributes applicable to most elements. + $core_attributes = array( + 'id' => true, + 'class' => true, + 'style' => true, + ); + + // ARIA and accessibility attributes. + $aria_attributes = array( + 'aria-hidden' => true, + 'aria-label' => true, + 'aria-labelledby' => true, + 'aria-describedby' => true, + 'role' => true, + 'focusable' => true, + 'tabindex' => true, + ); + + // Presentation attributes for graphics elements (shapes, text, use, image). + $presentation_attributes = array( + 'fill' => true, + 'fill-opacity' => true, + 'fill-rule' => true, + 'stroke' => true, + 'stroke-width' => true, + 'stroke-linecap' => true, + 'stroke-linejoin' => true, + 'stroke-miterlimit' => true, + 'stroke-dasharray' => true, + 'stroke-dashoffset' => true, + 'stroke-opacity' => true, + 'opacity' => true, + 'transform' => true, + 'clip-path' => true, + 'clip-rule' => true, + 'mask' => true, + 'filter' => true, + 'visibility' => true, + 'display' => true, + 'color' => true, + 'color-interpolation' => true, + 'color-rendering' => true, + 'vector-effect' => true, + 'paint-order' => true, + ); + + // Marker attributes (only for shape elements). + $marker_attributes = array( + 'marker-start' => true, + 'marker-mid' => true, + 'marker-end' => true, + ); + + // Container attributes for grouping elements. + $container_attributes = array( + 'transform' => true, + 'clip-path' => true, + 'mask' => true, + 'filter' => true, + 'visibility' => true, + 'display' => true, + 'opacity' => true, + ); + + /* + * Allowed tags for wp_kses(). WP_HTML_Processor::normalize() with + * constraints (similar structure to this array) is proposed to improve + * HTML/SVG sanitization in the future. + * + * @see https://github.com/dmsnell/wordpress-develop/pull/20 + */ + $allowed_tags = array( + // Root SVG element. + 'svg' => array_merge( + $core_attributes, + $aria_attributes, + $presentation_attributes, + array( + 'xmlns' => true, + 'xmlns:xlink' => true, + 'width' => true, + 'height' => true, + 'viewbox' => true, + 'preserveaspectratio' => true, + 'x' => true, + 'y' => true, + ) + ), + // Basic shape elements (with markers). + 'path' => array_merge( + $core_attributes, + $aria_attributes, + $presentation_attributes, + $marker_attributes, + array( + 'd' => true, + 'pathLength' => true, + ) + ), + 'circle' => array_merge( + $core_attributes, + $aria_attributes, + $presentation_attributes, + $marker_attributes, + array( + 'cx' => true, + 'cy' => true, + 'r' => true, + ) + ), + 'ellipse' => array_merge( + $core_attributes, + $aria_attributes, + $presentation_attributes, + $marker_attributes, + array( + 'cx' => true, + 'cy' => true, + 'rx' => true, + 'ry' => true, + ) + ), + 'line' => array_merge( + $core_attributes, + $aria_attributes, + $presentation_attributes, + $marker_attributes, + array( + 'x1' => true, + 'x2' => true, + 'y1' => true, + 'y2' => true, + ) + ), + 'polygon' => array_merge( + $core_attributes, + $aria_attributes, + $presentation_attributes, + $marker_attributes, + array( + 'points' => true, + ) + ), + 'polyline' => array_merge( + $core_attributes, + $aria_attributes, + $presentation_attributes, + $marker_attributes, + array( + 'points' => true, + ) + ), + 'rect' => array_merge( + $core_attributes, + $aria_attributes, + $presentation_attributes, + $marker_attributes, + array( + 'x' => true, + 'y' => true, + 'width' => true, + 'height' => true, + 'rx' => true, + 'ry' => true, + ) + ), + // Grouping and structural elements. + 'g' => array_merge( + $core_attributes, + $aria_attributes, + $container_attributes + ), + 'defs' => $core_attributes, + 'symbol' => array_merge( + $core_attributes, + $aria_attributes, + $container_attributes, + array( + 'viewBox' => true, + 'preserveAspectRatio' => true, + 'x' => true, + 'y' => true, + 'width' => true, + 'height' => true, + ) + ), + 'use' => array_merge( + $core_attributes, + $aria_attributes, + $presentation_attributes, + array( + 'href' => true, + 'xlink:href' => true, + 'x' => true, + 'y' => true, + 'width' => true, + 'height' => true, + ) + ), + 'clipPath' => array_merge( + $core_attributes, + array( + 'clipPathUnits' => true, + 'transform' => true, + ) + ), + 'mask' => array_merge( + $core_attributes, + array( + 'x' => true, + 'y' => true, + 'width' => true, + 'height' => true, + 'maskUnits' => true, + 'maskContentUnits' => true, + ) + ), + // Gradient elements. + 'linearGradient' => array_merge( + $core_attributes, + array( + 'x1' => true, + 'x2' => true, + 'y1' => true, + 'y2' => true, + 'gradientUnits' => true, + 'gradientTransform' => true, + 'spreadMethod' => true, + 'href' => true, + 'xlink:href' => true, + ) + ), + 'radialGradient' => array_merge( + $core_attributes, + array( + 'cx' => true, + 'cy' => true, + 'r' => true, + 'fx' => true, + 'fy' => true, + 'fr' => true, + 'gradientUnits' => true, + 'gradientTransform' => true, + 'spreadMethod' => true, + 'href' => true, + 'xlink:href' => true, + ) + ), + 'stop' => array_merge( + $core_attributes, + array( + 'offset' => true, + 'stop-color' => true, + 'stop-opacity' => true, + ) + ), + // Pattern element. + 'pattern' => array_merge( + $core_attributes, + array( + 'x' => true, + 'y' => true, + 'width' => true, + 'height' => true, + 'patternUnits' => true, + 'patternContentUnits' => true, + 'patternTransform' => true, + 'viewBox' => true, + 'preserveAspectRatio' => true, + 'href' => true, + 'xlink:href' => true, + ) + ), + // Filter elements. + 'filter' => array_merge( + $core_attributes, + array( + 'x' => true, + 'y' => true, + 'width' => true, + 'height' => true, + 'filterUnits' => true, + 'primitiveUnits' => true, + ) + ), + 'feBlend' => array( + 'in' => true, + 'in2' => true, + 'mode' => true, + 'result' => true, + ), + 'feColorMatrix' => array( + 'in' => true, + 'type' => true, + 'values' => true, + 'result' => true, + ), + 'feComponentTransfer' => array( + 'in' => true, + 'result' => true, + ), + 'feComposite' => array( + 'in' => true, + 'in2' => true, + 'operator' => true, + 'k1' => true, + 'k2' => true, + 'k3' => true, + 'k4' => true, + 'result' => true, + ), + 'feConvolveMatrix' => array( + 'in' => true, + 'order' => true, + 'kernelMatrix' => true, + 'divisor' => true, + 'bias' => true, + 'targetX' => true, + 'targetY' => true, + 'edgeMode' => true, + 'preserveAlpha' => true, + 'result' => true, + ), + 'feDiffuseLighting' => array( + 'in' => true, + 'surfaceScale' => true, + 'diffuseConstant' => true, + 'result' => true, + ), + 'feDisplacementMap' => array( + 'in' => true, + 'in2' => true, + 'scale' => true, + 'xChannelSelector' => true, + 'yChannelSelector' => true, + 'result' => true, + ), + 'feDistantLight' => array( + 'azimuth' => true, + 'elevation' => true, + ), + 'feFlood' => array( + 'flood-color' => true, + 'flood-opacity' => true, + 'result' => true, + ), + 'feGaussianBlur' => array( + 'in' => true, + 'stdDeviation' => true, + 'edgeMode' => true, + 'result' => true, + ), + 'feImage' => array( + 'href' => true, + 'xlink:href' => true, + 'preserveAspectRatio' => true, + 'result' => true, + ), + 'feMerge' => array( + 'result' => true, + ), + 'feMergeNode' => array( + 'in' => true, + ), + 'feMorphology' => array( + 'in' => true, + 'operator' => true, + 'radius' => true, + 'result' => true, + ), + 'feOffset' => array( + 'in' => true, + 'dx' => true, + 'dy' => true, + 'result' => true, + ), + 'fePointLight' => array( + 'x' => true, + 'y' => true, + 'z' => true, + ), + 'feSpecularLighting' => array( + 'in' => true, + 'surfaceScale' => true, + 'specularConstant' => true, + 'specularExponent' => true, + 'result' => true, + ), + 'feSpotLight' => array( + 'x' => true, + 'y' => true, + 'z' => true, + 'pointsAtX' => true, + 'pointsAtY' => true, + 'pointsAtZ' => true, + 'specularExponent' => true, + 'limitingConeAngle' => true, + ), + 'feTile' => array( + 'in' => true, + 'result' => true, + ), + 'feTurbulence' => array( + 'baseFrequency' => true, + 'numOctaves' => true, + 'seed' => true, + 'stitchTiles' => true, + 'type' => true, + 'result' => true, + ), + 'feFuncA' => array( + 'type' => true, + 'tableValues' => true, + 'slope' => true, + 'intercept' => true, + 'amplitude' => true, + 'exponent' => true, + 'offset' => true, + ), + 'feFuncB' => array( + 'type' => true, + 'tableValues' => true, + 'slope' => true, + 'intercept' => true, + 'amplitude' => true, + 'exponent' => true, + 'offset' => true, + ), + 'feFuncG' => array( + 'type' => true, + 'tableValues' => true, + 'slope' => true, + 'intercept' => true, + 'amplitude' => true, + 'exponent' => true, + 'offset' => true, + ), + 'feFuncR' => array( + 'type' => true, + 'tableValues' => true, + 'slope' => true, + 'intercept' => true, + 'amplitude' => true, + 'exponent' => true, + 'offset' => true, + ), + // Text elements. + 'text' => array_merge( + $core_attributes, + $aria_attributes, + $presentation_attributes, + array( + 'x' => true, + 'y' => true, + 'dx' => true, + 'dy' => true, + 'rotate' => true, + 'textLength' => true, + 'lengthAdjust' => true, + 'text-anchor' => true, + 'font-family' => true, + 'font-size' => true, + 'font-weight' => true, + 'font-style' => true, + 'font-variant' => true, + 'text-decoration' => true, + 'writing-mode' => true, + 'letter-spacing' => true, + 'word-spacing' => true, + 'dominant-baseline' => true, + 'alignment-baseline' => true, + 'baseline-shift' => true, + ) + ), + 'tspan' => array_merge( + $core_attributes, + $aria_attributes, + $presentation_attributes, + array( + 'x' => true, + 'y' => true, + 'dx' => true, + 'dy' => true, + 'rotate' => true, + 'textLength' => true, + 'lengthAdjust' => true, + 'text-anchor' => true, + 'font-family' => true, + 'font-size' => true, + 'font-weight' => true, + 'font-style' => true, + 'text-decoration' => true, + ) + ), + 'textPath' => array_merge( + $core_attributes, + $aria_attributes, + $presentation_attributes, + array( + 'href' => true, + 'xlink:href' => true, + 'startOffset' => true, + 'method' => true, + 'spacing' => true, + 'text-anchor' => true, + ) + ), + // Descriptive elements. + 'title' => array(), + 'desc' => array(), + 'metadata' => array(), + // Image element. + 'image' => array_merge( + $core_attributes, + $aria_attributes, + $presentation_attributes, + array( + 'x' => true, + 'y' => true, + 'width' => true, + 'height' => true, + 'href' => true, + 'xlink:href' => true, + 'preserveAspectRatio' => true, + ) + ), + // Marker element. + 'marker' => array_merge( + $core_attributes, + array( + 'markerUnits' => true, + 'refX' => true, + 'refY' => true, + 'markerWidth' => true, + 'markerHeight' => true, + 'orient' => true, + 'preserveAspectRatio' => true, + 'viewBox' => true, + ) + ), + // Animation elements. + 'animate' => array_merge( + $core_attributes, + array( + 'attributeName' => true, + 'from' => true, + 'to' => true, + 'dur' => true, + 'repeatCount' => true, + 'begin' => true, + 'end' => true, + 'values' => true, + 'keyTimes' => true, + 'keySplines' => true, + 'calcMode' => true, + 'additive' => true, + 'accumulate' => true, + ) + ), + 'animateTransform' => array_merge( + $core_attributes, + array( + 'attributeName' => true, + 'type' => true, + 'from' => true, + 'to' => true, + 'dur' => true, + 'repeatCount' => true, + 'begin' => true, + 'end' => true, + 'values' => true, + 'keyTimes' => true, + 'keySplines' => true, + 'calcMode' => true, + 'additive' => true, + 'accumulate' => true, + ) + ), + ); + + $processor = WP_HTML_Processor::create_fragment( $icon_content ); + if ( ! $processor || ! $processor->next_token() || 'SVG' !== $processor->get_tag() ) { + return ''; + } + + $svg = $processor->serialize_token(); + $depth = $processor->get_current_depth(); + while ( $processor->next_token() && $processor->get_current_depth() >= $depth ) { + $svg .= $processor->serialize_token(); + } + return wp_kses( $svg, $allowed_tags ); + } + /** * Modified to also search in icon labels */ diff --git a/phpunit/experimental/class-gutenberg-icons-registry-7-1-test.php b/phpunit/experimental/class-gutenberg-icons-registry-7-1-test.php new file mode 100644 index 00000000000000..f596a268d29b44 --- /dev/null +++ b/phpunit/experimental/class-gutenberg-icons-registry-7-1-test.php @@ -0,0 +1,110 @@ +registry = Gutenberg_Icons_Registry_7_1::get_instance(); + } + + /** + * Invokes the Gutenberg_Icons_Registry_7_1::register method on the registry instance. + * + * @param string $icon_name Icon name including namespace. + * @param array $icon_properties Icon properties (label, content, filePath). + * @return bool True if the icon was registered successfully. + */ + private function register( $icon_name, $icon_properties ) { + $method = new ReflectionMethod( $this->registry, 'register' ); + $method->setAccessible( true ); + return $method->invoke( $this->registry, $icon_name, $icon_properties ); + } + + /** + * Invokes the Gutenberg_Icons_Registry_7_1::sanitize_icon_content method on the registry instance. + * + * @param string $icon_content The icon SVG content to sanitize. + * @return string The sanitized icon SVG content. + */ + private function sanitize_icon_content( $icon_content ) { + $method = new ReflectionMethod( $this->registry, 'sanitize_icon_content' ); + $method->setAccessible( true ); + return $method->invoke( $this->registry, $icon_content ); + } + + /** + * @dataProvider data_sanitize_icon_content + * @covers Gutenberg_Icons_Registry_7_1::sanitize_icon_content + * + * @param string $input The icon content to sanitize. + * @param string $expected The expected sanitized output. + */ + public function test_sanitize_icon_content( $input, $expected ) { + $sanitized = $this->sanitize_icon_content( $input ); + $this->assertSame( $expected, $sanitized ); + } + + /** + * Data provider for test_sanitize_icon_content. + * + * @return array[] Array of arrays with input and expected sanitized output. + */ + public function data_sanitize_icon_content() { + return array( + 'strips script tags' => array( + '', + 'alert(1)', + ), + 'strips event handlers' => array( + '', + '', + ), + 'returns empty for plain text' => array( + 'plain text without svg', + '', + ), + 'returns empty for html without svg' => array( + '

not svg

content

', + '', + ), + 'allows https in href' => array( + '', + '', + ), + 'strips javascript protocol in href' => array( + '', + '', + ), + 'preserves allowed attributes' => array( + '', + '', + ), + 'preserves allowed elements' => array( + '', + '', + ), + 'strips disallowed tags' => array( + '', + '', + ), + 'keeps svg with inner title and desc' => array( + 'Icon titleDescription', + 'Icon titleDescription', + ), + ); + } +} From 4ae7479cdb4336e55cac82cab633fbb0c41f70d0 Mon Sep 17 00:00:00 2001 From: Aki Hamano Date: Thu, 12 Mar 2026 18:48:10 +0900 Subject: [PATCH 2/7] WIP --- .../class-gutenberg-icons-registry-7-1.php | 9 ++-- ...lass-gutenberg-icons-registry-7-1-test.php | 51 +++++++++++++------ 2 files changed, 40 insertions(+), 20 deletions(-) diff --git a/lib/compat/wordpress-7.1/class-gutenberg-icons-registry-7-1.php b/lib/compat/wordpress-7.1/class-gutenberg-icons-registry-7-1.php index f4aaa8c2717e00..ac72cdee17ce05 100644 --- a/lib/compat/wordpress-7.1/class-gutenberg-icons-registry-7-1.php +++ b/lib/compat/wordpress-7.1/class-gutenberg-icons-registry-7-1.php @@ -127,9 +127,9 @@ protected function sanitize_icon_content( $icon_content ) { ); /* - * Allowed tags for wp_kses(). WP_HTML_Processor::normalize() with - * constraints (similar structure to this array) is proposed to improve - * HTML/SVG sanitization in the future. + * Allowed tags for wp_kses(). Only SVG elements are permitted; foreignObject + * and HTML tags (e.g. p, div) are intentionally excluded as they are not + * valid in icon SVG content per the SVG specification. * * @see https://github.com/dmsnell/wordpress-develop/pull/20 */ @@ -649,9 +649,10 @@ protected function sanitize_icon_content( $icon_content ) { $svg = $processor->serialize_token(); $depth = $processor->get_current_depth(); - while ( $processor->next_token() && $processor->get_current_depth() >= $depth ) { + while ( $processor->next_token() && $processor->get_current_depth() > $depth ) { $svg .= $processor->serialize_token(); } + $svg .= ''; return wp_kses( $svg, $allowed_tags ); } diff --git a/phpunit/experimental/class-gutenberg-icons-registry-7-1-test.php b/phpunit/experimental/class-gutenberg-icons-registry-7-1-test.php index f596a268d29b44..fb5c92ce58a9a5 100644 --- a/phpunit/experimental/class-gutenberg-icons-registry-7-1-test.php +++ b/phpunit/experimental/class-gutenberg-icons-registry-7-1-test.php @@ -65,43 +65,62 @@ public function test_sanitize_icon_content( $input, $expected ) { */ public function data_sanitize_icon_content() { return array( - 'strips script tags' => array( + // Correctly extracts the SVG element. + 'strips html-like tags inside svg' => array( + '

paragraph content

div content
', + '', + ), + 'strips foreignObject and html inside' => array( + '

paragraph content

', + '', + ), + 'extracts only first svg when multiple present' => array( + '', + '', + ), + + // Dangerous content is stripped. + 'strips script tags' => array( '', 'alert(1)', ), - 'strips event handlers' => array( + 'strips event handlers' => array( '', '', ), - 'returns empty for plain text' => array( + 'strips javascript protocol in href' => array( + '', + '', + ), + 'strips disallowed tags' => array( + '', + '', + ), + + // Returns empty string when input is not SVG. + 'returns empty for plain text' => array( 'plain text without svg', '', ), - 'returns empty for html without svg' => array( + 'returns empty for html without svg' => array( '
not svg

content

', '', ), - 'allows https in href' => array( + + // Valid SVG elements and attributes are preserved. + 'allows https in href' => array( '', '', ), - 'strips javascript protocol in href' => array( - '', - '', - ), - 'preserves allowed attributes' => array( + 'preserves allowed attributes' => array( '', '', ), - 'preserves allowed elements' => array( + 'preserves allowed elements' => array( '', '', ), - 'strips disallowed tags' => array( - '', - '', - ), - 'keeps svg with inner title and desc' => array( + 'keeps svg with inner title and desc' => array( 'Icon titleDescription', 'Icon titleDescription', ), From a777fff82d1f5525f67bf979454a4c6dce7aa71a Mon Sep 17 00:00:00 2001 From: Aki Hamano Date: Thu, 12 Mar 2026 20:54:32 +0900 Subject: [PATCH 3/7] Improve unit test --- .../class-gutenberg-icons-registry-7-1.php | 364 +++++++++--------- ...lass-gutenberg-icons-registry-7-1-test.php | 119 ++++-- 2 files changed, 270 insertions(+), 213 deletions(-) diff --git a/lib/compat/wordpress-7.1/class-gutenberg-icons-registry-7-1.php b/lib/compat/wordpress-7.1/class-gutenberg-icons-registry-7-1.php index ac72cdee17ce05..efc417d17eeca8 100644 --- a/lib/compat/wordpress-7.1/class-gutenberg-icons-registry-7-1.php +++ b/lib/compat/wordpress-7.1/class-gutenberg-icons-registry-7-1.php @@ -127,9 +127,9 @@ protected function sanitize_icon_content( $icon_content ) { ); /* - * Allowed tags for wp_kses(). Only SVG elements are permitted; foreignObject - * and HTML tags (e.g. p, div) are intentionally excluded as they are not - * valid in icon SVG content per the SVG specification. + * Allowed tags for wp_kses(). WP_HTML_Processor::normalize() with + * constraints (similar structure to this array) is proposed to improve + * HTML/SVG sanitization in the future. * * @see https://github.com/dmsnell/wordpress-develop/pull/20 */ @@ -158,7 +158,7 @@ protected function sanitize_icon_content( $icon_content ) { $marker_attributes, array( 'd' => true, - 'pathLength' => true, + 'pathlength' => true, ) ), 'circle' => array_merge( @@ -240,8 +240,8 @@ protected function sanitize_icon_content( $icon_content ) { $aria_attributes, $container_attributes, array( - 'viewBox' => true, - 'preserveAspectRatio' => true, + 'viewbox' => true, + 'preserveaspectratio' => true, 'x' => true, 'y' => true, 'width' => true, @@ -261,40 +261,40 @@ protected function sanitize_icon_content( $icon_content ) { 'height' => true, ) ), - 'clipPath' => array_merge( + 'clippath' => array_merge( $core_attributes, array( - 'clipPathUnits' => true, + 'clippathunits' => true, 'transform' => true, ) ), 'mask' => array_merge( $core_attributes, array( - 'x' => true, - 'y' => true, - 'width' => true, - 'height' => true, - 'maskUnits' => true, - 'maskContentUnits' => true, + 'x' => true, + 'y' => true, + 'width' => true, + 'height' => true, + 'maskunits' => true, + 'maskcontentunits' => true, ) ), // Gradient elements. - 'linearGradient' => array_merge( + 'lineargradient' => array_merge( $core_attributes, array( 'x1' => true, 'x2' => true, 'y1' => true, 'y2' => true, - 'gradientUnits' => true, - 'gradientTransform' => true, - 'spreadMethod' => true, + 'gradientunits' => true, + 'gradienttransform' => true, + 'spreadmethod' => true, 'href' => true, 'xlink:href' => true, ) ), - 'radialGradient' => array_merge( + 'radialgradient' => array_merge( $core_attributes, array( 'cx' => true, @@ -303,9 +303,9 @@ protected function sanitize_icon_content( $icon_content ) { 'fx' => true, 'fy' => true, 'fr' => true, - 'gradientUnits' => true, - 'gradientTransform' => true, - 'spreadMethod' => true, + 'gradientunits' => true, + 'gradienttransform' => true, + 'spreadmethod' => true, 'href' => true, 'xlink:href' => true, ) @@ -322,48 +322,48 @@ protected function sanitize_icon_content( $icon_content ) { 'pattern' => array_merge( $core_attributes, array( - 'x' => true, - 'y' => true, - 'width' => true, - 'height' => true, - 'patternUnits' => true, - 'patternContentUnits' => true, - 'patternTransform' => true, - 'viewBox' => true, - 'preserveAspectRatio' => true, - 'href' => true, - 'xlink:href' => true, + 'x' => true, + 'y' => true, + 'width' => true, + 'height' => true, + 'patternunits' => true, + 'patterncontentunits' => true, + 'patterntransform' => true, + 'viewbox' => true, + 'preserveaspectratio' => true, + 'href' => true, + 'xlink:href' => true, ) ), // Filter elements. 'filter' => array_merge( $core_attributes, array( - 'x' => true, - 'y' => true, - 'width' => true, - 'height' => true, - 'filterUnits' => true, - 'primitiveUnits' => true, + 'x' => true, + 'y' => true, + 'width' => true, + 'height' => true, + 'filterunits' => true, + 'primitiveunits' => true, ) ), - 'feBlend' => array( + 'feblend' => array( 'in' => true, 'in2' => true, 'mode' => true, 'result' => true, ), - 'feColorMatrix' => array( + 'fecolormatrix' => array( 'in' => true, 'type' => true, 'values' => true, 'result' => true, ), - 'feComponentTransfer' => array( + 'fecomponenttransfer' => array( 'in' => true, 'result' => true, ), - 'feComposite' => array( + 'fecomposite' => array( 'in' => true, 'in2' => true, 'operator' => true, @@ -373,135 +373,135 @@ protected function sanitize_icon_content( $icon_content ) { 'k4' => true, 'result' => true, ), - 'feConvolveMatrix' => array( - 'in' => true, - 'order' => true, - 'kernelMatrix' => true, - 'divisor' => true, - 'bias' => true, - 'targetX' => true, - 'targetY' => true, - 'edgeMode' => true, - 'preserveAlpha' => true, - 'result' => true, - ), - 'feDiffuseLighting' => array( - 'in' => true, - 'surfaceScale' => true, - 'diffuseConstant' => true, - 'result' => true, - ), - 'feDisplacementMap' => array( + 'feconvolvematrix' => array( + 'in' => true, + 'order' => true, + 'kernelmatrix' => true, + 'divisor' => true, + 'bias' => true, + 'targetx' => true, + 'targety' => true, + 'edgemode' => true, + 'preservealpha' => true, + 'result' => true, + ), + 'fediffuselighting' => array( 'in' => true, - 'in2' => true, - 'scale' => true, - 'xChannelSelector' => true, - 'yChannelSelector' => true, + 'surfacescale' => true, + 'diffuseconstant' => true, 'result' => true, ), - 'feDistantLight' => array( + 'fedisplacementmap' => array( + 'in' => true, + 'in2' => true, + 'scale' => true, + 'xchannelselector' => true, + 'ychannelselector' => true, + 'result' => true, + ), + 'fedistantlight' => array( 'azimuth' => true, 'elevation' => true, ), - 'feFlood' => array( + 'feflood' => array( 'flood-color' => true, 'flood-opacity' => true, 'result' => true, ), - 'feGaussianBlur' => array( - 'in' => true, - 'stdDeviation' => true, - 'edgeMode' => true, - 'result' => true, + 'fegaussianblur' => array( + 'in' => true, + 'stddeviation' => true, + 'edgemode' => true, + 'result' => true, ), - 'feImage' => array( - 'href' => true, - 'xlink:href' => true, - 'preserveAspectRatio' => true, - 'result' => true, + 'feimage' => array( + 'href' => true, + 'xlink:href' => true, + 'preserveaspectratio' => true, + 'result' => true, ), - 'feMerge' => array( + 'femerge' => array( 'result' => true, ), - 'feMergeNode' => array( + 'femergenode' => array( 'in' => true, ), - 'feMorphology' => array( + 'femorphology' => array( 'in' => true, 'operator' => true, 'radius' => true, 'result' => true, ), - 'feOffset' => array( + 'feoffset' => array( 'in' => true, 'dx' => true, 'dy' => true, 'result' => true, ), - 'fePointLight' => array( + 'fepointlight' => array( 'x' => true, 'y' => true, 'z' => true, ), - 'feSpecularLighting' => array( - 'in' => true, - 'surfaceScale' => true, - 'specularConstant' => true, - 'specularExponent' => true, - 'result' => true, - ), - 'feSpotLight' => array( - 'x' => true, - 'y' => true, - 'z' => true, - 'pointsAtX' => true, - 'pointsAtY' => true, - 'pointsAtZ' => true, - 'specularExponent' => true, - 'limitingConeAngle' => true, - ), - 'feTile' => array( + 'fespecularlighting' => array( + 'in' => true, + 'surfacescale' => true, + 'specularconstant' => true, + 'specularexponent' => true, + 'result' => true, + ), + 'fespotlight' => array( + 'x' => true, + 'y' => true, + 'z' => true, + 'pointsatx' => true, + 'pointsaty' => true, + 'pointsatz' => true, + 'specularexponent' => true, + 'limitingconeangle' => true, + ), + 'fetile' => array( 'in' => true, 'result' => true, ), - 'feTurbulence' => array( - 'baseFrequency' => true, - 'numOctaves' => true, + 'feturbulence' => array( + 'basefrequency' => true, + 'numoctaves' => true, 'seed' => true, - 'stitchTiles' => true, + 'stitchtiles' => true, 'type' => true, 'result' => true, ), - 'feFuncA' => array( - 'type' => true, - 'tableValues' => true, - 'slope' => true, - 'intercept' => true, - 'amplitude' => true, - 'exponent' => true, - 'offset' => true, + 'fefunca' => array( + 'type' => true, + 'tablevalues' => true, + 'slope' => true, + 'intercept' => true, + 'amplitude' => true, + 'exponent' => true, + 'offset' => true, ), - 'feFuncB' => array( + 'fefuncb' => array( 'type' => true, - 'tableValues' => true, + 'tablevalues' => true, 'slope' => true, 'intercept' => true, 'amplitude' => true, 'exponent' => true, 'offset' => true, ), - 'feFuncG' => array( + 'fefuncg' => array( 'type' => true, - 'tableValues' => true, + 'tablevalues' => true, 'slope' => true, 'intercept' => true, 'amplitude' => true, 'exponent' => true, 'offset' => true, ), - 'feFuncR' => array( + 'fefuncr' => array( 'type' => true, - 'tableValues' => true, + 'tablevalues' => true, 'slope' => true, 'intercept' => true, 'amplitude' => true, @@ -514,26 +514,26 @@ protected function sanitize_icon_content( $icon_content ) { $aria_attributes, $presentation_attributes, array( - 'x' => true, - 'y' => true, - 'dx' => true, - 'dy' => true, - 'rotate' => true, - 'textLength' => true, - 'lengthAdjust' => true, - 'text-anchor' => true, - 'font-family' => true, - 'font-size' => true, - 'font-weight' => true, - 'font-style' => true, - 'font-variant' => true, - 'text-decoration' => true, - 'writing-mode' => true, + 'x' => true, + 'y' => true, + 'dx' => true, + 'dy' => true, + 'rotate' => true, + 'textlength' => true, + 'lengthadjust' => true, + 'text-anchor' => true, + 'font-family' => true, + 'font-size' => true, + 'font-weight' => true, + 'font-style' => true, + 'font-variant' => true, + 'text-decoration' => true, + 'writing-mode' => true, 'letter-spacing' => true, - 'word-spacing' => true, - 'dominant-baseline' => true, - 'alignment-baseline' => true, - 'baseline-shift' => true, + 'word-spacing' => true, + 'dominant-baseline' => true, + 'alignment-baseline' => true, + 'baseline-shift' => true, ) ), 'tspan' => array_merge( @@ -546,8 +546,8 @@ protected function sanitize_icon_content( $icon_content ) { 'dx' => true, 'dy' => true, 'rotate' => true, - 'textLength' => true, - 'lengthAdjust' => true, + 'textlength' => true, + 'lengthadjust' => true, 'text-anchor' => true, 'font-family' => true, 'font-size' => true, @@ -556,17 +556,17 @@ protected function sanitize_icon_content( $icon_content ) { 'text-decoration' => true, ) ), - 'textPath' => array_merge( + 'textpath' => array_merge( $core_attributes, $aria_attributes, $presentation_attributes, array( - 'href' => true, - 'xlink:href' => true, - 'startOffset' => true, - 'method' => true, - 'spacing' => true, - 'text-anchor' => true, + 'href' => true, + 'xlink:href' => true, + 'startoffset' => true, + 'method' => true, + 'spacing' => true, + 'text-anchor' => true, ) ), // Descriptive elements. @@ -579,65 +579,65 @@ protected function sanitize_icon_content( $icon_content ) { $aria_attributes, $presentation_attributes, array( - 'x' => true, - 'y' => true, - 'width' => true, - 'height' => true, - 'href' => true, - 'xlink:href' => true, - 'preserveAspectRatio' => true, + 'x' => true, + 'y' => true, + 'width' => true, + 'height' => true, + 'href' => true, + 'xlink:href' => true, + 'preserveaspectratio' => true, ) ), // Marker element. 'marker' => array_merge( $core_attributes, array( - 'markerUnits' => true, - 'refX' => true, - 'refY' => true, - 'markerWidth' => true, - 'markerHeight' => true, + 'markerunits' => true, + 'refx' => true, + 'refy' => true, + 'markerwidth' => true, + 'markerheight' => true, 'orient' => true, - 'preserveAspectRatio' => true, - 'viewBox' => true, + 'preserveaspectratio' => true, + 'viewbox' => true, ) ), // Animation elements. 'animate' => array_merge( $core_attributes, array( - 'attributeName' => true, + 'attributename' => true, 'from' => true, 'to' => true, 'dur' => true, - 'repeatCount' => true, + 'repeatcount' => true, 'begin' => true, 'end' => true, 'values' => true, - 'keyTimes' => true, - 'keySplines' => true, - 'calcMode' => true, + 'keytimes' => true, + 'keysplines' => true, + 'calcmode' => true, 'additive' => true, 'accumulate' => true, ) ), - 'animateTransform' => array_merge( + 'animatetransform' => array_merge( $core_attributes, array( - 'attributeName' => true, - 'type' => true, - 'from' => true, - 'to' => true, - 'dur' => true, - 'repeatCount' => true, - 'begin' => true, - 'end' => true, - 'values' => true, - 'keyTimes' => true, - 'keySplines' => true, - 'calcMode' => true, - 'additive' => true, - 'accumulate' => true, + 'attributename' => true, + 'type' => true, + 'from' => true, + 'to' => true, + 'dur' => true, + 'repeatcount' => true, + 'begin' => true, + 'end' => true, + 'values' => true, + 'keytimes' => true, + 'keysplines' => true, + 'calcmode' => true, + 'additive' => true, + 'accumulate' => true, ) ), ); @@ -649,7 +649,7 @@ protected function sanitize_icon_content( $icon_content ) { $svg = $processor->serialize_token(); $depth = $processor->get_current_depth(); - while ( $processor->next_token() && $processor->get_current_depth() > $depth ) { + while ( $processor->next_token() && $processor->get_current_depth() >= $depth ) { $svg .= $processor->serialize_token(); } $svg .= ''; diff --git a/phpunit/experimental/class-gutenberg-icons-registry-7-1-test.php b/phpunit/experimental/class-gutenberg-icons-registry-7-1-test.php index fb5c92ce58a9a5..9a5f2de962d807 100644 --- a/phpunit/experimental/class-gutenberg-icons-registry-7-1-test.php +++ b/phpunit/experimental/class-gutenberg-icons-registry-7-1-test.php @@ -65,64 +65,121 @@ public function test_sanitize_icon_content( $input, $expected ) { */ public function data_sanitize_icon_content() { return array( - // Correctly extracts the SVG element. - 'strips html-like tags inside svg' => array( + 'extracts only first svg when multiple present' => array( + '', + '', + ), + 'returns empty svg when html-like tags present' => array( '

paragraph content

div content
', '', ), - 'strips foreignObject and html inside' => array( - '

paragraph content

', + 'strips namespace attributes' => array( + '', '', ), - 'extracts only first svg when multiple present' => array( - '', - '', - ), - // Dangerous content is stripped. - 'strips script tags' => array( + // Dangerous content is stripped (wp_kses). + 'strips foreignObject but keeps text content' => array( + '

paragraph content

', + 'paragraph contentalert(1)', + ), + 'strips script tags' => array( '', 'alert(1)', ), - 'strips event handlers' => array( + 'strips event handlers' => array( '', '', ), - 'strips javascript protocol in href' => array( + 'strips javascript protocol in href' => array( '', '', ), - 'strips disallowed tags' => array( + 'strips data protocol in href' => array( + '', + '', + ), + 'strips disallowed tags' => array( '', '', ), // Returns empty string when input is not SVG. - 'returns empty for plain text' => array( + 'returns empty for empty string' => array( + '', + '', + ), + 'returns empty for whitespace only' => array( + " \n\t ", + '', + ), + 'returns empty for plain text' => array( 'plain text without svg', '', ), - 'returns empty for html without svg' => array( + 'returns empty for html without svg' => array( '
not svg

content

', '', ), + 'returns empty when svg is not first element' => array( + '

before

', + '', + ), - // Valid SVG elements and attributes are preserved. - 'allows https in href' => array( - '', - '', - ), - 'preserves allowed attributes' => array( - '', - '', - ), - 'preserves allowed elements' => array( - '', - '', - ), - 'keeps svg with inner title and desc' => array( - 'Icon titleDescription', - 'Icon titleDescription', + // Root SVG element. + 'preserves root svg element' => array( + '', + '', + ), + // Basic shape elements. + 'preserves basic shape elements' => array( + '', + '', + ), + // Grouping and structural elements. + 'preserves grouping and structural elements' => array( + '', + '', + ), + // Gradient elements. + 'preserves gradient elements' => array( + '', + '', + ), + // Pattern element. + 'preserves pattern element' => array( + '', + '', + ), + // Filter elements. + 'preserves filter elements' => array( + '', + '', + ), + // Text elements. + 'preserves text elements' => array( + 'ABpath', + 'ABpath', + ), + // Descriptive elements. + 'preserves descriptive elements' => array( + 'Icon titleDescription', + 'Icon titleDescription', + ), + // Image element. + 'preserves image element' => array( + '', + '', + ), + // Marker element. + 'preserves marker element' => array( + '', + '', + ), + // Animation elements. + 'preserves animation elements' => array( + '', + '', ), ); } From 2bd0b84f0050aec79828edb0426b2022874b4465 Mon Sep 17 00:00:00 2001 From: Aki Hamano Date: Thu, 12 Mar 2026 21:36:19 +0900 Subject: [PATCH 4/7] Format --- .../class-gutenberg-icons-registry-7-1.php | 232 +++++++++--------- ...lass-gutenberg-icons-registry-7-1-test.php | 2 +- 2 files changed, 117 insertions(+), 117 deletions(-) diff --git a/lib/compat/wordpress-7.1/class-gutenberg-icons-registry-7-1.php b/lib/compat/wordpress-7.1/class-gutenberg-icons-registry-7-1.php index efc417d17eeca8..3235f2ba3e2805 100644 --- a/lib/compat/wordpress-7.1/class-gutenberg-icons-registry-7-1.php +++ b/lib/compat/wordpress-7.1/class-gutenberg-icons-registry-7-1.php @@ -271,12 +271,12 @@ protected function sanitize_icon_content( $icon_content ) { 'mask' => array_merge( $core_attributes, array( - 'x' => true, - 'y' => true, - 'width' => true, - 'height' => true, - 'maskunits' => true, - 'maskcontentunits' => true, + 'x' => true, + 'y' => true, + 'width' => true, + 'height' => true, + 'maskunits' => true, + 'maskcontentunits' => true, ) ), // Gradient elements. @@ -322,29 +322,29 @@ protected function sanitize_icon_content( $icon_content ) { 'pattern' => array_merge( $core_attributes, array( - 'x' => true, - 'y' => true, - 'width' => true, - 'height' => true, - 'patternunits' => true, - 'patterncontentunits' => true, - 'patterntransform' => true, - 'viewbox' => true, - 'preserveaspectratio' => true, - 'href' => true, - 'xlink:href' => true, + 'x' => true, + 'y' => true, + 'width' => true, + 'height' => true, + 'patternunits' => true, + 'patterncontentunits' => true, + 'patterntransform' => true, + 'viewbox' => true, + 'preserveaspectratio' => true, + 'href' => true, + 'xlink:href' => true, ) ), // Filter elements. 'filter' => array_merge( $core_attributes, array( - 'x' => true, - 'y' => true, - 'width' => true, - 'height' => true, - 'filterunits' => true, - 'primitiveunits' => true, + 'x' => true, + 'y' => true, + 'width' => true, + 'height' => true, + 'filterunits' => true, + 'primitiveunits' => true, ) ), 'feblend' => array( @@ -374,30 +374,30 @@ protected function sanitize_icon_content( $icon_content ) { 'result' => true, ), 'feconvolvematrix' => array( - 'in' => true, - 'order' => true, - 'kernelmatrix' => true, - 'divisor' => true, - 'bias' => true, - 'targetx' => true, - 'targety' => true, - 'edgemode' => true, - 'preservealpha' => true, - 'result' => true, + 'in' => true, + 'order' => true, + 'kernelmatrix' => true, + 'divisor' => true, + 'bias' => true, + 'targetx' => true, + 'targety' => true, + 'edgemode' => true, + 'preservealpha' => true, + 'result' => true, ), 'fediffuselighting' => array( - 'in' => true, - 'surfacescale' => true, - 'diffuseconstant' => true, - 'result' => true, + 'in' => true, + 'surfacescale' => true, + 'diffuseconstant' => true, + 'result' => true, ), 'fedisplacementmap' => array( - 'in' => true, - 'in2' => true, - 'scale' => true, - 'xchannelselector' => true, - 'ychannelselector' => true, - 'result' => true, + 'in' => true, + 'in2' => true, + 'scale' => true, + 'xchannelselector' => true, + 'ychannelselector' => true, + 'result' => true, ), 'fedistantlight' => array( 'azimuth' => true, @@ -409,16 +409,16 @@ protected function sanitize_icon_content( $icon_content ) { 'result' => true, ), 'fegaussianblur' => array( - 'in' => true, - 'stddeviation' => true, - 'edgemode' => true, - 'result' => true, + 'in' => true, + 'stddeviation' => true, + 'edgemode' => true, + 'result' => true, ), 'feimage' => array( - 'href' => true, - 'xlink:href' => true, - 'preserveaspectratio' => true, - 'result' => true, + 'href' => true, + 'xlink:href' => true, + 'preserveaspectratio' => true, + 'result' => true, ), 'femerge' => array( 'result' => true, @@ -444,21 +444,21 @@ protected function sanitize_icon_content( $icon_content ) { 'z' => true, ), 'fespecularlighting' => array( - 'in' => true, - 'surfacescale' => true, - 'specularconstant' => true, - 'specularexponent' => true, - 'result' => true, + 'in' => true, + 'surfacescale' => true, + 'specularconstant' => true, + 'specularexponent' => true, + 'result' => true, ), 'fespotlight' => array( - 'x' => true, - 'y' => true, - 'z' => true, - 'pointsatx' => true, - 'pointsaty' => true, - 'pointsatz' => true, - 'specularexponent' => true, - 'limitingconeangle' => true, + 'x' => true, + 'y' => true, + 'z' => true, + 'pointsatx' => true, + 'pointsaty' => true, + 'pointsatz' => true, + 'specularexponent' => true, + 'limitingconeangle' => true, ), 'fetile' => array( 'in' => true, @@ -473,13 +473,13 @@ protected function sanitize_icon_content( $icon_content ) { 'result' => true, ), 'fefunca' => array( - 'type' => true, - 'tablevalues' => true, - 'slope' => true, - 'intercept' => true, - 'amplitude' => true, - 'exponent' => true, - 'offset' => true, + 'type' => true, + 'tablevalues' => true, + 'slope' => true, + 'intercept' => true, + 'amplitude' => true, + 'exponent' => true, + 'offset' => true, ), 'fefuncb' => array( 'type' => true, @@ -514,26 +514,26 @@ protected function sanitize_icon_content( $icon_content ) { $aria_attributes, $presentation_attributes, array( - 'x' => true, - 'y' => true, - 'dx' => true, - 'dy' => true, - 'rotate' => true, - 'textlength' => true, - 'lengthadjust' => true, - 'text-anchor' => true, - 'font-family' => true, - 'font-size' => true, - 'font-weight' => true, - 'font-style' => true, - 'font-variant' => true, - 'text-decoration' => true, - 'writing-mode' => true, + 'x' => true, + 'y' => true, + 'dx' => true, + 'dy' => true, + 'rotate' => true, + 'textlength' => true, + 'lengthadjust' => true, + 'text-anchor' => true, + 'font-family' => true, + 'font-size' => true, + 'font-weight' => true, + 'font-style' => true, + 'font-variant' => true, + 'text-decoration' => true, + 'writing-mode' => true, 'letter-spacing' => true, - 'word-spacing' => true, - 'dominant-baseline' => true, - 'alignment-baseline' => true, - 'baseline-shift' => true, + 'word-spacing' => true, + 'dominant-baseline' => true, + 'alignment-baseline' => true, + 'baseline-shift' => true, ) ), 'tspan' => array_merge( @@ -561,12 +561,12 @@ protected function sanitize_icon_content( $icon_content ) { $aria_attributes, $presentation_attributes, array( - 'href' => true, - 'xlink:href' => true, - 'startoffset' => true, - 'method' => true, - 'spacing' => true, - 'text-anchor' => true, + 'href' => true, + 'xlink:href' => true, + 'startoffset' => true, + 'method' => true, + 'spacing' => true, + 'text-anchor' => true, ) ), // Descriptive elements. @@ -579,13 +579,13 @@ protected function sanitize_icon_content( $icon_content ) { $aria_attributes, $presentation_attributes, array( - 'x' => true, - 'y' => true, - 'width' => true, - 'height' => true, - 'href' => true, - 'xlink:href' => true, - 'preserveaspectratio' => true, + 'x' => true, + 'y' => true, + 'width' => true, + 'height' => true, + 'href' => true, + 'xlink:href' => true, + 'preserveaspectratio' => true, ) ), // Marker element. @@ -625,19 +625,19 @@ protected function sanitize_icon_content( $icon_content ) { $core_attributes, array( 'attributename' => true, - 'type' => true, - 'from' => true, - 'to' => true, - 'dur' => true, - 'repeatcount' => true, - 'begin' => true, - 'end' => true, - 'values' => true, - 'keytimes' => true, - 'keysplines' => true, - 'calcmode' => true, - 'additive' => true, - 'accumulate' => true, + 'type' => true, + 'from' => true, + 'to' => true, + 'dur' => true, + 'repeatcount' => true, + 'begin' => true, + 'end' => true, + 'values' => true, + 'keytimes' => true, + 'keysplines' => true, + 'calcmode' => true, + 'additive' => true, + 'accumulate' => true, ) ), ); diff --git a/phpunit/experimental/class-gutenberg-icons-registry-7-1-test.php b/phpunit/experimental/class-gutenberg-icons-registry-7-1-test.php index 9a5f2de962d807..054313a8d0dd34 100644 --- a/phpunit/experimental/class-gutenberg-icons-registry-7-1-test.php +++ b/phpunit/experimental/class-gutenberg-icons-registry-7-1-test.php @@ -73,7 +73,7 @@ public function data_sanitize_icon_content() { '

paragraph content

div content
', '', ), - 'strips namespace attributes' => array( + 'strips namespace attributes' => array( '', '', ), From 3dc5e281e8a3e84e0d680f4120fdb647bbb8b5ba Mon Sep 17 00:00:00 2001 From: Aki Hamano Date: Thu, 12 Mar 2026 21:40:52 +0900 Subject: [PATCH 5/7] Add missing elements --- .../class-gutenberg-icons-registry-7-1.php | 59 +++++++++++++++++++ ...lass-gutenberg-icons-registry-7-1-test.php | 16 ++++- 2 files changed, 73 insertions(+), 2 deletions(-) diff --git a/lib/compat/wordpress-7.1/class-gutenberg-icons-registry-7-1.php b/lib/compat/wordpress-7.1/class-gutenberg-icons-registry-7-1.php index 3235f2ba3e2805..48a4ccb6abd9ad 100644 --- a/lib/compat/wordpress-7.1/class-gutenberg-icons-registry-7-1.php +++ b/lib/compat/wordpress-7.1/class-gutenberg-icons-registry-7-1.php @@ -235,6 +235,15 @@ protected function sanitize_icon_content( $icon_content ) { $container_attributes ), 'defs' => $core_attributes, + 'view' => array_merge( + $core_attributes, + array( + 'viewbox' => true, + 'preserveaspectratio' => true, + 'zoomandpan' => true, + 'viewtarget' => true, + ) + ), 'symbol' => array_merge( $core_attributes, $aria_attributes, @@ -261,6 +270,25 @@ protected function sanitize_icon_content( $icon_content ) { 'height' => true, ) ), + 'switch' => array_merge( + $core_attributes, + $aria_attributes, + $container_attributes + ), + // Linking element. + 'a' => array_merge( + $core_attributes, + $aria_attributes, + $presentation_attributes, + $container_attributes, + array( + 'href' => true, + 'xlink:href' => true, + 'target' => true, + 'rel' => true, + 'type' => true, + ) + ), 'clippath' => array_merge( $core_attributes, array( @@ -621,6 +649,26 @@ protected function sanitize_icon_content( $icon_content ) { 'accumulate' => true, ) ), + 'animatemotion' => array_merge( + $core_attributes, + array( + 'path' => true, + 'keypoints' => true, + 'rotate' => true, + 'keytimes' => true, + 'keysplines' => true, + 'calcmode' => true, + 'from' => true, + 'to' => true, + 'values' => true, + 'dur' => true, + 'repeatcount' => true, + 'begin' => true, + 'end' => true, + 'additive' => true, + 'accumulate' => true, + ) + ), 'animatetransform' => array_merge( $core_attributes, array( @@ -640,6 +688,17 @@ protected function sanitize_icon_content( $icon_content ) { 'accumulate' => true, ) ), + 'set' => array_merge( + $core_attributes, + array( + 'attributename' => true, + 'to' => true, + 'begin' => true, + 'dur' => true, + 'end' => true, + 'repeatcount' => true, + ) + ), ); $processor = WP_HTML_Processor::create_fragment( $icon_content ); diff --git a/phpunit/experimental/class-gutenberg-icons-registry-7-1-test.php b/phpunit/experimental/class-gutenberg-icons-registry-7-1-test.php index 054313a8d0dd34..caa4fbbcec3f7d 100644 --- a/phpunit/experimental/class-gutenberg-icons-registry-7-1-test.php +++ b/phpunit/experimental/class-gutenberg-icons-registry-7-1-test.php @@ -141,6 +141,18 @@ public function data_sanitize_icon_content() { '', '', ), + 'preserves switch element' => array( + '', + '', + ), + 'preserves view element' => array( + '', + '', + ), + 'preserves linking element' => array( + '', + '', + ), // Gradient elements. 'preserves gradient elements' => array( '', @@ -178,8 +190,8 @@ public function data_sanitize_icon_content() { ), // Animation elements. 'preserves animation elements' => array( - '', - '', + '', + '', ), ); } From 8708824e531aaea39c982501a2ec2df30becee1e Mon Sep 17 00:00:00 2001 From: Aki Hamano Date: Thu, 12 Mar 2026 21:49:38 +0900 Subject: [PATCH 6/7] Remove redundant def element --- ...lass-gutenberg-icons-registry-7-1-test.php | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/phpunit/experimental/class-gutenberg-icons-registry-7-1-test.php b/phpunit/experimental/class-gutenberg-icons-registry-7-1-test.php index caa4fbbcec3f7d..66b21bf7dc53fe 100644 --- a/phpunit/experimental/class-gutenberg-icons-registry-7-1-test.php +++ b/phpunit/experimental/class-gutenberg-icons-registry-7-1-test.php @@ -146,8 +146,8 @@ public function data_sanitize_icon_content() { '', ), 'preserves view element' => array( - '', - '', + '', + '', ), 'preserves linking element' => array( '', @@ -155,23 +155,23 @@ public function data_sanitize_icon_content() { ), // Gradient elements. 'preserves gradient elements' => array( - '', - '', + '', + '', ), // Pattern element. 'preserves pattern element' => array( - '', - '', + '', + '', ), // Filter elements. 'preserves filter elements' => array( - '', - '', + '', + '', ), // Text elements. 'preserves text elements' => array( - 'ABpath', - 'ABpath', + 'ABpath', + 'ABpath', ), // Descriptive elements. 'preserves descriptive elements' => array( From 5c36d1fd5c359cb30ec6f27237d13302b54b1bff Mon Sep 17 00:00:00 2001 From: Aki Hamano Date: Thu, 12 Mar 2026 21:50:41 +0900 Subject: [PATCH 7/7] Add temporary backport changelog --- backport-changelog/7.1/TODO.md | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 backport-changelog/7.1/TODO.md diff --git a/backport-changelog/7.1/TODO.md b/backport-changelog/7.1/TODO.md new file mode 100644 index 00000000000000..bd6ca721e6248b --- /dev/null +++ b/backport-changelog/7.1/TODO.md @@ -0,0 +1,3 @@ +https://github.com/WordPress/wordpress-develop/pull/TODO + +* https://github.com/WordPress/gutenberg/pull/75550