You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Existing block level custom CSS in a post breaks when the post is edited by user without unfiltered_html #76472
Everything works as expected unless a user without unfiltered_html edits a page/post with existing block-level custom CSS that includes nested selectors, eg.
color: green;
&p {color: blue}
In these cases, entities like & are encoded and the CSS breaks in the editor and the frontend.
There, @sirreal pointed out that for 7.0 this needs to be fixed in GB by:
Encoding the CSS stored in the serialised attributes as base64, with a prefix to indicate this is the case, eg. data:text/css;base64 OR
Deleting the attribute if a user without unfiltered_html tries to edit/save the post - with a warning to them that this is going to happen
Step-by-step reproduction instructions
Create a test user with the Author role (no unfiltered_html capability)
Create a new post as an admin user
Add a Group block with a nested Paragraph block
Open the block's Advanced panel → Additional CSS textarea
Enter: color: blue; & p { color: red; }
Save the post
Log in as a user without unfiltered_html, eg. author and edit the paragraph, eg. make part of string italic. Note you will not see the custom CSS input box when logged in as this user. Just edit the existing paragraph in the post content and save.
Save again and then log back in as an admin user and CSS shows color: blue; & .child { color: red; } and styles do not show correctly in editor or frontend.
Screenshots, screen recording, code snippet
No response
Environment info
No response
Please confirm that you have searched existing issues in the repo.
Yes
Please confirm that you have tested with all plugins deactivated except Gutenberg.
Yes
Please confirm which theme type you used for testing.
To be honest, neither option seems clean to me. Stripping appears consistent with the current permissions, but it silently destroys content that the user didn't touch. Encoding + storing will create a permanent backwards compat burden.
I was playing with encoding that is coupled to the custom CSS controller in #76480, but that doesn't cover posts saved before our fix, and, more importantly, passive saves where the CSS attribute is just carried along.
So I think we need to think about which other paths content can be saved, e.g., wp-cli, REST calls, insert post, even edits to the code in the block editor.
So far I'm looking at pre_kses to check and perform base64 encoding, but I'm not sure about it or the migration path to core.
That said, I'm worried we're getting close to the approach that sounded dodgy in the first place (doing it all in wp_pre_kses_block_attributes).
What do you think? I have a few other things to take care of for 7.0 this week and have a meetup next week, so I'm a bit patchy.
While we're talking about wp_insert_post_data, another idea I had was to let KSES run, strip the tags and whatever, and then repair the damage in wp_insert_post_data using something similar to Glen's first approach (reverses the specific HTML entity encodings KSES applies to CSS string values).
If I'm seeing things right, wp_insert_post_data fires after wp_kses_post in wp_insert_post, and covers all save paths.
I'm not suggesting this as a Gutenberg fix - i know it doesn't address declarations like content: "<text>" and so on - but a local plugin fix to tide Glen/folks over until the CSS quagmire is traversed.
This was another crazy idea, and feel free to flame it and shut it down.
Activity
ramonjd commentedon Mar 13, 2026
I tried that here #76167
But that doesn't solve the multisite issue, right?
To be honest, neither option seems clean to me. Stripping appears consistent with the current permissions, but it silently destroys content that the user didn't touch. Encoding + storing will create a permanent backwards compat burden.
YOLO PR for encoding in #76480
🤔
glendaviesnz commentedon Mar 15, 2026
Yeah, I think we need to be resigned to the fact that we can't run this on multisite until 7.1, when 🤞 there will be some way of sanitizing the CSS.
ramonjd commentedon Mar 16, 2026
@glendaviesnz I was thinking about your use case.
I was playing with encoding that is coupled to the custom CSS controller in #76480, but that doesn't cover posts saved before our fix, and, more importantly, passive saves where the CSS attribute is just carried along.
So I think we need to think about which other paths content can be saved, e.g., wp-cli, REST calls, insert post, even edits to the code in the block editor.
So far I'm looking at
pre_ksesto check and perform base64 encoding, but I'm not sure about it or the migration path to core.That said, I'm worried we're getting close to the approach that sounded dodgy in the first place (doing it all in
wp_pre_kses_block_attributes).What do you think? I have a few other things to take care of for 7.0 this week and have a meetup next week, so I'm a bit patchy.
While we're talking about
wp_insert_post_data, another idea I had was to let KSES run, strip the tags and whatever, and then repair the damage inwp_insert_post_datausing something similar to Glen's first approach (reverses the specific HTML entity encodings KSES applies to CSS string values).If I'm seeing things right,
wp_insert_post_datafires afterwp_kses_postin wp_insert_post, and covers all save paths.I'm not suggesting this as a Gutenberg fix - i know it doesn't address declarations like
content: "<text>"and so on - but a local plugin fix to tide Glen/folks over until the CSS quagmire is traversed.This was another crazy idea, and feel free to flame it and shut it down.
ramonjd commentedon Mar 16, 2026
Another thought I had is how much data we're storing.
color: redgoes into the database asdata:text/css;base64,Y29sb3I6IHJlZA==.For simple CSS it's not a trivial size increase. Is there a limit to how much custom CSS a user can add?
t-hamano commentedon Apr 27, 2026
Can we close this? It seems to have been fixed in the core. https://core.trac.wordpress.org/ticket/64771
sirreal commentedon Apr 27, 2026
Yes, I think this was fixed in Gutenberg by #76650.
There are potential follow-ups to improve the experience, but the issue described should be fixed.