Skip to content

Commit 292f17d

Browse files
committed
Fix problem with encoding of css entities when post with block level custom css is edited by user without unfiltered_html
1 parent 869776e commit 292f17d

1 file changed

Lines changed: 45 additions & 0 deletions

File tree

src/wp-includes/blocks.php

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2077,6 +2077,17 @@ function _filter_block_content_callback( $matches ) {
20772077
function filter_block_kses( $block, $allowed_html, $allowed_protocols = array() ) {
20782078
$block['attrs'] = filter_block_kses_value( $block['attrs'], $allowed_html, $allowed_protocols, $block );
20792079

2080+
// Per-block custom CSS (attrs.style.css) may contain & and > as valid
2081+
// CSS selectors. wp_kses() entity-encodes these because it treats the
2082+
// value as HTML. Decode them after KSES has already stripped any
2083+
// dangerous HTML tags, so the CSS round-trips correctly through
2084+
// serialize_block_attributes().
2085+
if ( isset( $block['attrs']['style']['css'] ) ) {
2086+
$block['attrs']['style']['css'] = undo_block_custom_css_kses_entities(
2087+
$block['attrs']['style']['css']
2088+
);
2089+
}
2090+
20802091
if ( is_array( $block['innerBlocks'] ) ) {
20812092
foreach ( $block['innerBlocks'] as $i => $inner_block ) {
20822093
$block['innerBlocks'][ $i ] = filter_block_kses( $inner_block, $allowed_html, $allowed_protocols );
@@ -2124,6 +2135,40 @@ function filter_block_kses_value( $value, $allowed_html, $allowed_protocols = ar
21242135
return $value;
21252136
}
21262137

2138+
/**
2139+
* Decodes HTML entities in per-block custom CSS that were incorrectly
2140+
* introduced by wp_kses() during the block KSES filtering pipeline.
2141+
*
2142+
* Per-block custom CSS (stored in attrs.style.css) may contain & and >
2143+
* as valid CSS selectors (nesting and child combinator). When wp_kses()
2144+
* processes this CSS string as if it were HTML, it entity-encodes these
2145+
* characters (&, >). If the block is then re-serialized via
2146+
* serialize_block_attributes(), the entity's ampersand is escaped again
2147+
* (\u0026amp;), producing a double-encoded value that corrupts the CSS
2148+
* on subsequent editor loads.
2149+
*
2150+
* This reverses only the specific named entities that wp_kses() may
2151+
* introduce, intentionally narrower than wp_specialchars_decode() to
2152+
* avoid decoding numeric/hex references that KSES intentionally preserved.
2153+
*
2154+
* @since 6.9.0
2155+
*
2156+
* @param string $value Per-block custom CSS string potentially containing
2157+
* KSES-introduced entities.
2158+
* @return string CSS string with KSES-introduced entities decoded.
2159+
*/
2160+
function undo_block_custom_css_kses_entities( $value ) {
2161+
if ( ! is_string( $value ) || false === strpos( $value, '&' ) ) {
2162+
return $value;
2163+
}
2164+
2165+
return str_replace(
2166+
array( '&', '>', '"', ''' ),
2167+
array( '&', '>', '"', "'" ),
2168+
$value
2169+
);
2170+
}
2171+
21272172
/**
21282173
* Sanitizes the value of the Template Part block's `tagName` attribute.
21292174
*

0 commit comments

Comments
 (0)