Skip to content

Existing block level custom CSS in a post breaks when the post is edited by user without unfiltered_html #76472

Closed

Description

@glendaviesnz

Description

#73959 introduced block level custom CSS.

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.

See the discussion on WordPress/wordpress-develop#11104

Core trac ticket: https://core.trac.wordpress.org/ticket/64771

There, @sirreal pointed out that for 7.0 this needs to be fixed in GB by:

  1. 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
  2. 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

  1. Create a test user with the Author role (no unfiltered_html capability)
  2. Create a new post as an admin user
  3. Add a Group block with a nested Paragraph block
  4. Open the block's Advanced panel → Additional CSS textarea
  5. Enter: color: blue; & p { color: red; }
  6. Save the post
  7. 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.
  8. 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.

  • Block
  • Classic
  • Hybrid (e.g. classic with theme.json)
  • Not sure

Activity

  1. added
    CSS StylingRelated to editor and front end styles, CSS-specific issues.
    on Mar 12, 2026
  2. ramonjd commented on Mar 13, 2026

    @ramonjd
    Member

    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

    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

    🤔

  3. glendaviesnz commented on Mar 15, 2026

    @glendaviesnz
    ContributorAuthor

    But that doesn't solve the multisite issue, right?

    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.

  4. ramonjd commented on Mar 16, 2026

    @ramonjd
    Member

    @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_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.


  5. ramonjd commented on Mar 16, 2026

    @ramonjd
    Member

    Another thought I had is how much data we're storing.

    color: red goes into the database as data: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?

  6. t-hamano commented on Apr 27, 2026

    @t-hamano
    Contributor

    Can we close this? It seems to have been fixed in the core. https://core.trac.wordpress.org/ticket/64771

  7. sirreal commented on Apr 27, 2026

    @sirreal
    Member

    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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

CSS StylingRelated to editor and front end styles, CSS-specific issues.[Feature] BlocksOverall functionality of blocks[Status] In ProgressTracking issues with work in progress[Type] BugAn existing feature does not function as intended

Type

No type

Projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions