Skip to content

Block Editor: Strip per-block custom CSS on save for users without edit_css#76650

Merged
ramonjd merged 13 commits intotrunkfrom
strip-css-for-non-edit-css-users
Apr 17, 2026
Merged

Block Editor: Strip per-block custom CSS on save for users without edit_css#76650
ramonjd merged 13 commits intotrunkfrom
strip-css-for-non-edit-css-users

Conversation

@glendaviesnz
Copy link
Copy Markdown
Contributor

@glendaviesnz glendaviesnz commented Mar 18, 2026

What?

Adds server-side enforcement of the edit_css capability for per-block custom CSS (style.css block attribute). Also adds an editor warning notice for users who lack the capability when editing a post that contains blocks with custom CSS.

Why?

PR #73959 added per-block custom CSS support, but the edit_css capability check is only performed client-side (hiding the CSS panel in the editor). Any user with edit_posts can bypass this by using Code Editor or the REST API to inject style.css into block attributes, which gets rendered as arbitrary inline CSS on the frontend. This enables UI redress attacks, phishing overlays, and content defacement.

Trac ticket for backport: https://core.trac.wordpress.org/ticket/64771

How?

PHP (lib/block-supports/custom-css.php)

Adds a content_save_pre filter following the established kses pattern used for footnotes in lib/blocks.php:

  • gutenberg_strip_custom_css_from_blocks() — parses blocks, recursively walks all blocks (including innerBlocks), removes attrs.style.css, and re-serializes. Short-circuits if content has no blocks or nothing changed.
  • gutenberg_custom_css_kses_init() — hooked on init (priority 20) and set_current_user. Only activates the filter when ! current_user_can( 'edit_css' ).
  • gutenberg_custom_css_kses_init_filters() / gutenberg_custom_css_remove_filters() — add/remove the content_save_pre and content_filtered_save_pre hooks at priority 8 (before kses at 9).
  • gutenberg_custom_css_force_filtered_html_on_import_filter() — forces the filter on during imports (priority 999).

JS (packages/block-editor/src/hooks/custom-css.js)

In the CustomCSSEdit component, when canEditCSS is false and the block has style.css set, dispatches a one-time warning notice (deduplicated via fixed notice ID) informing the user that custom CSS will be removed on save.

Not covered

Existing posts with the custom CSS already saved won't be cleaned up, and that saved custom CSS will still render on the frontend. As this feature has only been out for a short time and only in the experimental plugin, there is not enough risk from this to warrant trying to clean up any existing content that may have been added by users without edit-css permissions.

Testing Instructions

1. Test as Author user (has edit_posts, no edit_css):

  • Log in as an Author
  • Open a post that contains blocks with custom CSS (added by an Admin)
  • Verify the warning banner appears at the top of the editor
  • Save the post
  • Verify style.css is stripped from all blocks in the saved content
  • Verify the CSS no longer renders on the frontend

2. Test as Admin user (has edit_css):

  • Open the same post — no warning banner should appear
  • Save — custom CSS should be preserved in block attributes
  • Frontend should still render the CSS

3. Code Editor bypass test:

  • As Author, switch to Code Editor
  • Manually type <!-- wp:paragraph {"style":{"css":"body{background:red}"}} -->
  • Save → verify the style.css attribute is stripped from saved content

4. REST API test:

  • As Author, PUT /wp-json/wp/v2/posts/<id> with a content payload containing CSS in block attributes
  • Verify CSS is stripped from the saved content

5. Existing tests:

  • Existing PHP tests in phpunit/block-supports/custom-css-test.php should still pass (they test render behaviour, not save filtering)

@github-actions
Copy link
Copy Markdown

github-actions Bot commented Mar 18, 2026

The following accounts have interacted with this PR and/or linked issues. I will continue to update these lists as activity occurs. You can also manually ask me to refresh this list by adding the props-bot label.

If you're merging code through a pull request on GitHub, copy and paste the following into the bottom of the merge commit message.

Co-authored-by: glendaviesnz <glendaviesnz@git.wordpress.org>
Co-authored-by: aaronrobertshaw <aaronrobertshaw@git.wordpress.org>
Co-authored-by: ramonjd <ramonopoly@git.wordpress.org>
Co-authored-by: dmsnell <dmsnell@git.wordpress.org>
Co-authored-by: sirreal <jonsurrell@git.wordpress.org>

To understand the WordPress project's expectations around crediting contributors, please review the Contributor Attribution page in the Core Handbook.

@glendaviesnz
Copy link
Copy Markdown
Contributor Author

@aaronrobertshaw It was decided here that for users without edit-css permissions we should strip any block level CSS when they save.

@github-actions
Copy link
Copy Markdown

github-actions Bot commented Mar 18, 2026

Size Change: +130 B (0%)

Total Size: 7.75 MB

📦 View Changed
Filename Size Change
build/scripts/block-editor/index.min.js 340 kB +130 B (+0.04%)
ℹ️ View Unchanged
Filename Size
build/modules/a11y/index.min.js 355 B
build/modules/abilities/index.min.js 42.3 kB
build/modules/block-editor/utils/fit-text-frontend.min.js 617 B
build/modules/block-library/accordion/view.min.js 595 B
build/modules/block-library/file/view.min.js 346 B
build/modules/block-library/form/view.min.js 528 B
build/modules/block-library/image/view.min.js 2.64 kB
build/modules/block-library/navigation/view.min.js 1.14 kB
build/modules/block-library/playlist/view.min.js 10.9 kB
build/modules/block-library/query/view.min.js 518 B
build/modules/block-library/search/view.min.js 498 B
build/modules/block-library/tabs/view.min.js 946 B
build/modules/boot/index.min.js 17 kB
build/modules/connectors/index.min.js 2.05 kB
build/modules/core-abilities/index.min.js 907 B
build/modules/edit-site-init/index.min.js 1.4 kB
build/modules/interactivity-router/full-page.min.js 451 B
build/modules/interactivity-router/index.min.js 11.6 kB
build/modules/interactivity/index.min.js 15.1 kB
build/modules/latex-to-mathml/index.min.js 56.5 kB
build/modules/latex-to-mathml/loader.min.js 131 B
build/modules/lazy-editor/index.min.js 13.9 kB
build/modules/route/index.min.js 25.2 kB
build/modules/vips/loader.min.js 127 B
build/modules/vips/worker.min.js 4.56 MB
build/modules/workflow/index.min.js 19.9 kB
build/scripts/a11y/index.min.js 1.06 kB
build/scripts/annotations/index.min.js 2.49 kB
build/scripts/api-fetch/index.min.js 2.83 kB
build/scripts/autop/index.min.js 2.18 kB
build/scripts/base-styles/index.min.js 98 B
build/scripts/blob/index.min.js 631 B
build/scripts/block-directory/index.min.js 8.03 kB
build/scripts/block-library/index.min.js 317 kB
build/scripts/block-serialization-default-parser/index.min.js 1.16 kB
build/scripts/block-serialization-spec-parser/index.min.js 3.08 kB
build/scripts/blocks/index.min.js 56.9 kB
build/scripts/commands/index.min.js 21 kB
build/scripts/components/index.min.js 265 kB
build/scripts/compose/index.min.js 11.1 kB
build/scripts/core-commands/index.min.js 4.31 kB
build/scripts/core-data/index.min.js 30.9 kB
build/scripts/customize-widgets/index.min.js 12.3 kB
build/scripts/data-controls/index.min.js 795 B
build/scripts/data/index.min.js 9.66 kB
build/scripts/date/index.min.js 23.6 kB
build/scripts/deprecated/index.min.js 756 B
build/scripts/dom-ready/index.min.js 476 B
build/scripts/dom/index.min.js 5 kB
build/scripts/edit-post/index.min.js 16.4 kB
build/scripts/edit-site/index.min.js 262 kB
build/scripts/edit-widgets/index.min.js 19.9 kB
build/scripts/editor/index.min.js 413 kB
build/scripts/element/index.min.js 5.17 kB
build/scripts/escape-html/index.min.js 587 B
build/scripts/format-library/index.min.js 10.7 kB
build/scripts/hooks/index.min.js 1.83 kB
build/scripts/html-entities/index.min.js 494 B
build/scripts/i18n/index.min.js 2.47 kB
build/scripts/is-shallow-equal/index.min.js 572 B
build/scripts/keyboard-shortcuts/index.min.js 1.57 kB
build/scripts/keycodes/index.min.js 1.56 kB
build/scripts/list-reusable-blocks/index.min.js 2.49 kB
build/scripts/media-utils/index.min.js 79.2 kB
build/scripts/notices/index.min.js 1.85 kB
build/scripts/nux/index.min.js 1.89 kB
build/scripts/patterns/index.min.js 7.98 kB
build/scripts/plugins/index.min.js 2.15 kB
build/scripts/preferences-persistence/index.min.js 2.15 kB
build/scripts/preferences/index.min.js 3.3 kB
build/scripts/primitives/index.min.js 1.01 kB
build/scripts/priority-queue/index.min.js 1.62 kB
build/scripts/private-apis/index.min.js 1.1 kB
build/scripts/react-i18n/index.min.js 833 B
build/scripts/redux-routine/index.min.js 3.37 kB
build/scripts/reusable-blocks/index.min.js 3.1 kB
build/scripts/rich-text/index.min.js 14 kB
build/scripts/router/index.min.js 5.96 kB
build/scripts/server-side-render/index.min.js 1.91 kB
build/scripts/shortcode/index.min.js 1.59 kB
build/scripts/style-engine/index.min.js 2.41 kB
build/scripts/sync/index.min.js 38.6 kB
build/scripts/theme/index.min.js 22 kB
build/scripts/token-list/index.min.js 739 B
build/scripts/undo-manager/index.min.js 918 B
build/scripts/upload-media/index.min.js 8.22 kB
build/scripts/url/index.min.js 3.98 kB
build/scripts/vendors/react-dom.min.js 43.3 kB
build/scripts/vendors/react-jsx-runtime.min.js 667 B
build/scripts/vendors/react.min.js 2.77 kB
build/scripts/viewport/index.min.js 1.22 kB
build/scripts/warning/index.min.js 454 B
build/scripts/widgets/index.min.js 7.8 kB
build/scripts/wordcount/index.min.js 1.04 kB
build/styles/base-styles/admin-schemes-rtl.css 1.71 kB
build/styles/base-styles/admin-schemes-rtl.min.css 775 B
build/styles/base-styles/admin-schemes.css 1.71 kB
build/styles/base-styles/admin-schemes.min.css 775 B
build/styles/block-directory/style-rtl.css 1.97 kB
build/styles/block-directory/style-rtl.min.css 1.06 kB
build/styles/block-directory/style.css 1.98 kB
build/styles/block-directory/style.min.css 1.06 kB
build/styles/block-editor/content-rtl.css 5.46 kB
build/styles/block-editor/content-rtl.min.css 4.03 kB
build/styles/block-editor/content.css 5.46 kB
build/styles/block-editor/content.min.css 4.02 kB
build/styles/block-editor/default-editor-styles-rtl.css 697 B
build/styles/block-editor/default-editor-styles-rtl.min.css 224 B
build/styles/block-editor/default-editor-styles.css 697 B
build/styles/block-editor/default-editor-styles.min.css 224 B
build/styles/block-editor/style-rtl.css 18.6 kB
build/styles/block-editor/style-rtl.min.css 15.8 kB
build/styles/block-editor/style.css 18.6 kB
build/styles/block-editor/style.min.css 15.8 kB
build/styles/block-library/accordion-heading/style-rtl.css 346 B
build/styles/block-library/accordion-heading/style-rtl.min.css 325 B
build/styles/block-library/accordion-heading/style.css 346 B
build/styles/block-library/accordion-heading/style.min.css 325 B
build/styles/block-library/accordion-item/style-rtl.css 239 B
build/styles/block-library/accordion-item/style-rtl.min.css 180 B
build/styles/block-library/accordion-item/style.css 238 B
build/styles/block-library/accordion-item/style.min.css 180 B
build/styles/block-library/accordion-panel/style-rtl.css 110 B
build/styles/block-library/accordion-panel/style-rtl.min.css 99 B
build/styles/block-library/accordion-panel/style.css 110 B
build/styles/block-library/accordion-panel/style.min.css 99 B
build/styles/block-library/accordion/style-rtl.css 69 B
build/styles/block-library/accordion/style-rtl.min.css 62 B
build/styles/block-library/accordion/style.css 69 B
build/styles/block-library/accordion/style.min.css 62 B
build/styles/block-library/archives/style-rtl.css 101 B
build/styles/block-library/archives/style-rtl.min.css 90 B
build/styles/block-library/archives/style.css 101 B
build/styles/block-library/archives/style.min.css 90 B
build/styles/block-library/audio/editor-rtl.css 166 B
build/styles/block-library/audio/editor-rtl.min.css 149 B
build/styles/block-library/audio/editor.css 166 B
build/styles/block-library/audio/editor.min.css 151 B
build/styles/block-library/audio/style-rtl.css 945 B
build/styles/block-library/audio/style-rtl.min.css 132 B
build/styles/block-library/audio/style.css 945 B
build/styles/block-library/audio/style.min.css 132 B
build/styles/block-library/audio/theme-rtl.css 967 B
build/styles/block-library/audio/theme-rtl.min.css 134 B
build/styles/block-library/audio/theme.css 967 B
build/styles/block-library/audio/theme.min.css 134 B
build/styles/block-library/avatar/editor-rtl.css 127 B
build/styles/block-library/avatar/editor-rtl.min.css 115 B
build/styles/block-library/avatar/editor.css 127 B
build/styles/block-library/avatar/editor.min.css 115 B
build/styles/block-library/avatar/style-rtl.css 117 B
build/styles/block-library/avatar/style-rtl.min.css 104 B
build/styles/block-library/avatar/style.css 117 B
build/styles/block-library/avatar/style.min.css 104 B
build/styles/block-library/breadcrumbs/style-rtl.css 233 B
build/styles/block-library/breadcrumbs/style-rtl.min.css 203 B
build/styles/block-library/breadcrumbs/style.css 233 B
build/styles/block-library/breadcrumbs/style.min.css 203 B
build/styles/block-library/button/editor-rtl.css 306 B
build/styles/block-library/button/editor-rtl.min.css 265 B
build/styles/block-library/button/editor.css 317 B
build/styles/block-library/button/editor.min.css 265 B
build/styles/block-library/button/style-rtl.css 651 B
build/styles/block-library/button/style-rtl.min.css 596 B
build/styles/block-library/button/style.css 662 B
build/styles/block-library/button/style.min.css 596 B
build/styles/block-library/buttons/editor-rtl.css 391 B
build/styles/block-library/buttons/editor-rtl.min.css 291 B
build/styles/block-library/buttons/editor.css 391 B
build/styles/block-library/buttons/editor.min.css 291 B
build/styles/block-library/buttons/style-rtl.css 452 B
build/styles/block-library/buttons/style-rtl.min.css 349 B
build/styles/block-library/buttons/style.css 453 B
build/styles/block-library/buttons/style.min.css 349 B
build/styles/block-library/calendar/style-rtl.css 271 B
build/styles/block-library/calendar/style-rtl.min.css 239 B
build/styles/block-library/calendar/style.css 271 B
build/styles/block-library/calendar/style.min.css 239 B
build/styles/block-library/categories/editor-rtl.css 171 B
build/styles/block-library/categories/editor-rtl.min.css 132 B
build/styles/block-library/categories/editor.css 170 B
build/styles/block-library/categories/editor.min.css 131 B
build/styles/block-library/categories/style-rtl.css 226 B
build/styles/block-library/categories/style-rtl.min.css 169 B
build/styles/block-library/categories/style.css 235 B
build/styles/block-library/categories/style.min.css 169 B
build/styles/block-library/classic-rtl.css 363 B
build/styles/block-library/classic-rtl.min.css 321 B
build/styles/block-library/classic.css 363 B
build/styles/block-library/classic.min.css 321 B
build/styles/block-library/code/editor-rtl.css 59 B
build/styles/block-library/code/editor-rtl.min.css 53 B
build/styles/block-library/code/editor.css 59 B
build/styles/block-library/code/editor.min.css 53 B
build/styles/block-library/code/style-rtl.css 158 B
build/styles/block-library/code/style-rtl.min.css 140 B
build/styles/block-library/code/style.css 178 B
build/styles/block-library/code/style.min.css 140 B
build/styles/block-library/code/theme-rtl.css 135 B
build/styles/block-library/code/theme-rtl.min.css 122 B
build/styles/block-library/code/theme.css 135 B
build/styles/block-library/code/theme.min.css 122 B
build/styles/block-library/columns/editor-rtl.css 119 B
build/styles/block-library/columns/editor-rtl.min.css 108 B
build/styles/block-library/columns/editor.css 119 B
build/styles/block-library/columns/editor.min.css 108 B
build/styles/block-library/columns/style-rtl.css 1.3 kB
build/styles/block-library/columns/style-rtl.min.css 421 B
build/styles/block-library/columns/style.css 1.3 kB
build/styles/block-library/columns/style.min.css 421 B
build/styles/block-library/comment-author-avatar/editor-rtl.css 136 B
build/styles/block-library/comment-author-avatar/editor-rtl.min.css 124 B
build/styles/block-library/comment-author-avatar/editor.css 136 B
build/styles/block-library/comment-author-avatar/editor.min.css 124 B
build/styles/block-library/comment-author-name/style-rtl.css 79 B
build/styles/block-library/comment-author-name/style-rtl.min.css 72 B
build/styles/block-library/comment-author-name/style.css 79 B
build/styles/block-library/comment-author-name/style.min.css 72 B
build/styles/block-library/comment-content/style-rtl.css 137 B
build/styles/block-library/comment-content/style-rtl.min.css 120 B
build/styles/block-library/comment-content/style.css 137 B
build/styles/block-library/comment-content/style.min.css 120 B
build/styles/block-library/comment-date/style-rtl.css 72 B
build/styles/block-library/comment-date/style-rtl.min.css 65 B
build/styles/block-library/comment-date/style.css 72 B
build/styles/block-library/comment-date/style.min.css 65 B
build/styles/block-library/comment-edit-link/style-rtl.css 77 B
build/styles/block-library/comment-edit-link/style-rtl.min.css 70 B
build/styles/block-library/comment-edit-link/style.css 77 B
build/styles/block-library/comment-edit-link/style.min.css 70 B
build/styles/block-library/comment-reply-link/style-rtl.css 78 B
build/styles/block-library/comment-reply-link/style-rtl.min.css 71 B
build/styles/block-library/comment-reply-link/style.css 78 B
build/styles/block-library/comment-reply-link/style.min.css 71 B
build/styles/block-library/comment-template/style-rtl.css 213 B
build/styles/block-library/comment-template/style-rtl.min.css 191 B
build/styles/block-library/comment-template/style.css 213 B
build/styles/block-library/comment-template/style.min.css 191 B
build/styles/block-library/comments-pagination-numbers/editor-rtl.css 135 B
build/styles/block-library/comments-pagination-numbers/editor-rtl.min.css 122 B
build/styles/block-library/comments-pagination-numbers/editor.css 144 B
build/styles/block-library/comments-pagination-numbers/editor.min.css 121 B
build/styles/block-library/comments-pagination/editor-rtl.css 184 B
build/styles/block-library/comments-pagination/editor-rtl.min.css 168 B
build/styles/block-library/comments-pagination/editor.css 184 B
build/styles/block-library/comments-pagination/editor.min.css 168 B
build/styles/block-library/comments-pagination/style-rtl.css 224 B
build/styles/block-library/comments-pagination/style-rtl.min.css 201 B
build/styles/block-library/comments-pagination/style.css 236 B
build/styles/block-library/comments-pagination/style.min.css 201 B
build/styles/block-library/comments-title/editor-rtl.css 83 B
build/styles/block-library/comments-title/editor-rtl.min.css 75 B
build/styles/block-library/comments-title/editor.css 83 B
build/styles/block-library/comments-title/editor.min.css 75 B
build/styles/block-library/comments/editor-rtl.css 968 B
build/styles/block-library/comments/editor-rtl.min.css 842 B
build/styles/block-library/comments/editor.css 968 B
build/styles/block-library/comments/editor.min.css 842 B
build/styles/block-library/comments/style-rtl.css 754 B
build/styles/block-library/comments/style-rtl.min.css 637 B
build/styles/block-library/comments/style.css 752 B
build/styles/block-library/comments/style.min.css 637 B
build/styles/block-library/common-rtl.css 2.48 kB
build/styles/block-library/common-rtl.min.css 1.12 kB
build/styles/block-library/common.css 2.5 kB
build/styles/block-library/common.min.css 1.12 kB
build/styles/block-library/cover/editor-rtl.css 1.05 kB
build/styles/block-library/cover/editor-rtl.min.css 631 B
build/styles/block-library/cover/editor.css 1.05 kB
build/styles/block-library/cover/editor.min.css 631 B
build/styles/block-library/cover/style-rtl.css 2.5 kB
build/styles/block-library/cover/style-rtl.min.css 1.82 kB
build/styles/block-library/cover/style.css 2.51 kB
build/styles/block-library/cover/style.min.css 1.81 kB
build/styles/block-library/details/editor-rtl.css 72 B
build/styles/block-library/details/editor-rtl.min.css 65 B
build/styles/block-library/details/editor.css 72 B
build/styles/block-library/details/editor.min.css 65 B
build/styles/block-library/details/style-rtl.css 97 B
build/styles/block-library/details/style-rtl.min.css 86 B
build/styles/block-library/details/style.css 97 B
build/styles/block-library/details/style.min.css 86 B
build/styles/block-library/editor-elements-rtl.css 117 B
build/styles/block-library/editor-elements-rtl.min.css 75 B
build/styles/block-library/editor-elements.css 117 B
build/styles/block-library/editor-elements.min.css 75 B
build/styles/block-library/editor-rtl.css 12.5 kB
build/styles/block-library/editor-rtl.min.css 10.3 kB
build/styles/block-library/editor.css 12.5 kB
build/styles/block-library/editor.min.css 10.3 kB
build/styles/block-library/elements-rtl.css 84 B
build/styles/block-library/elements-rtl.min.css 54 B
build/styles/block-library/elements.css 84 B
build/styles/block-library/elements.min.css 54 B
build/styles/block-library/embed/editor-rtl.css 391 B
build/styles/block-library/embed/editor-rtl.min.css 331 B
build/styles/block-library/embed/editor.css 390 B
build/styles/block-library/embed/editor.min.css 331 B
build/styles/block-library/embed/style-rtl.css 1.29 kB
build/styles/block-library/embed/style-rtl.min.css 448 B
build/styles/block-library/embed/style.css 1.29 kB
build/styles/block-library/embed/style.min.css 448 B
build/styles/block-library/embed/theme-rtl.css 967 B
build/styles/block-library/embed/theme-rtl.min.css 133 B
build/styles/block-library/embed/theme.css 967 B
build/styles/block-library/embed/theme.min.css 133 B
build/styles/block-library/file/editor-rtl.css 352 B
build/styles/block-library/file/editor-rtl.min.css 324 B
build/styles/block-library/file/editor.css 353 B
build/styles/block-library/file/editor.min.css 324 B
build/styles/block-library/file/style-rtl.css 318 B
build/styles/block-library/file/style-rtl.min.css 278 B
build/styles/block-library/file/style.css 331 B
build/styles/block-library/file/style.min.css 278 B
build/styles/block-library/footnotes/style-rtl.css 220 B
build/styles/block-library/footnotes/style-rtl.min.css 198 B
build/styles/block-library/footnotes/style.css 219 B
build/styles/block-library/footnotes/style.min.css 197 B
build/styles/block-library/form-input/editor-rtl.css 286 B
build/styles/block-library/form-input/editor-rtl.min.css 265 B
build/styles/block-library/form-input/editor.css 285 B
build/styles/block-library/form-input/editor.min.css 264 B
build/styles/block-library/form-input/style-rtl.css 467 B
build/styles/block-library/form-input/style-rtl.min.css 366 B
build/styles/block-library/form-input/style.css 467 B
build/styles/block-library/form-input/style.min.css 366 B
build/styles/block-library/form-submission-notification/editor-rtl.css 368 B
build/styles/block-library/form-submission-notification/editor-rtl.min.css 344 B
build/styles/block-library/form-submission-notification/editor.css 368 B
build/styles/block-library/form-submission-notification/editor.min.css 341 B
build/styles/block-library/form-submit-button/style-rtl.css 77 B
build/styles/block-library/form-submit-button/style-rtl.min.css 69 B
build/styles/block-library/form-submit-button/style.css 77 B
build/styles/block-library/form-submit-button/style.min.css 69 B
build/styles/block-library/freeform/editor-rtl.css 1.12 kB
build/styles/block-library/freeform/editor-rtl.min.css 288 B
build/styles/block-library/freeform/editor.css 1.12 kB
build/styles/block-library/freeform/editor.min.css 288 B
build/styles/block-library/gallery/editor-rtl.css 1.52 kB
build/styles/block-library/gallery/editor-rtl.min.css 615 B
build/styles/block-library/gallery/editor.css 1.52 kB
build/styles/block-library/gallery/editor.min.css 616 B
build/styles/block-library/gallery/style-rtl.css 2.84 kB
build/styles/block-library/gallery/style-rtl.min.css 1.84 kB
build/styles/block-library/gallery/style.css 2.84 kB
build/styles/block-library/gallery/style.min.css 1.84 kB
build/styles/block-library/gallery/theme-rtl.css 941 B
build/styles/block-library/gallery/theme-rtl.min.css 108 B
build/styles/block-library/gallery/theme.css 941 B
build/styles/block-library/gallery/theme.min.css 108 B
build/styles/block-library/group/editor-rtl.css 772 B
build/styles/block-library/group/editor-rtl.min.css 335 B
build/styles/block-library/group/editor.css 772 B
build/styles/block-library/group/editor.min.css 335 B
build/styles/block-library/group/style-rtl.css 120 B
build/styles/block-library/group/style-rtl.min.css 103 B
build/styles/block-library/group/style.css 120 B
build/styles/block-library/group/style.min.css 103 B
build/styles/block-library/group/theme-rtl.css 468 B
build/styles/block-library/group/theme-rtl.min.css 79 B
build/styles/block-library/group/theme.css 468 B
build/styles/block-library/group/theme.min.css 79 B
build/styles/block-library/heading/style-rtl.css 604 B
build/styles/block-library/heading/style-rtl.min.css 205 B
build/styles/block-library/heading/style.css 604 B
build/styles/block-library/heading/style.min.css 205 B
build/styles/block-library/html/editor-rtl.css 1.29 kB
build/styles/block-library/html/editor-rtl.min.css 464 B
build/styles/block-library/html/editor.css 1.3 kB
build/styles/block-library/html/editor.min.css 464 B
build/styles/block-library/icon/editor-rtl.css 776 B
build/styles/block-library/icon/editor-rtl.min.css 377 B
build/styles/block-library/icon/editor.css 776 B
build/styles/block-library/icon/editor.min.css 377 B
build/styles/block-library/icon/style-rtl.css 218 B
build/styles/block-library/icon/style-rtl.min.css 154 B
build/styles/block-library/icon/style.css 218 B
build/styles/block-library/icon/style.min.css 154 B
build/styles/block-library/image/editor-rtl.css 1.64 kB
build/styles/block-library/image/editor-rtl.min.css 782 B
build/styles/block-library/image/editor.css 1.64 kB
build/styles/block-library/image/editor.min.css 780 B
build/styles/block-library/image/style-rtl.css 2.92 kB
build/styles/block-library/image/style-rtl.min.css 1.86 kB
build/styles/block-library/image/style.css 2.92 kB
build/styles/block-library/image/style.min.css 1.85 kB
build/styles/block-library/image/theme-rtl.css 971 B
build/styles/block-library/image/theme-rtl.min.css 137 B
build/styles/block-library/image/theme.css 971 B
build/styles/block-library/image/theme.min.css 137 B
build/styles/block-library/latest-comments/style-rtl.css 392 B
build/styles/block-library/latest-comments/style-rtl.min.css 352 B
build/styles/block-library/latest-comments/style.css 390 B
build/styles/block-library/latest-comments/style.min.css 352 B
build/styles/block-library/latest-posts/editor-rtl.css 154 B
build/styles/block-library/latest-posts/editor-rtl.min.css 139 B
build/styles/block-library/latest-posts/editor.css 153 B
build/styles/block-library/latest-posts/editor.min.css 138 B
build/styles/block-library/latest-posts/style-rtl.css 1.36 kB
build/styles/block-library/latest-posts/style-rtl.min.css 520 B
build/styles/block-library/latest-posts/style.css 1.37 kB
build/styles/block-library/latest-posts/style.min.css 520 B
build/styles/block-library/list/style-rtl.css 498 B
build/styles/block-library/list/style-rtl.min.css 107 B
build/styles/block-library/list/style.css 498 B
build/styles/block-library/list/style.min.css 107 B
build/styles/block-library/loginout/style-rtl.css 68 B
build/styles/block-library/loginout/style-rtl.min.css 61 B
build/styles/block-library/loginout/style.css 68 B
build/styles/block-library/loginout/style.min.css 61 B
build/styles/block-library/math/editor-rtl.css 491 B
build/styles/block-library/math/editor-rtl.min.css 105 B
build/styles/block-library/math/editor.css 502 B
build/styles/block-library/math/editor.min.css 105 B
build/styles/block-library/math/style-rtl.css 70 B
build/styles/block-library/math/style-rtl.min.css 61 B
build/styles/block-library/math/style.css 70 B
build/styles/block-library/math/style.min.css 61 B
build/styles/block-library/media-text/editor-rtl.css 389 B
build/styles/block-library/media-text/editor-rtl.min.css 321 B
build/styles/block-library/media-text/editor.css 389 B
build/styles/block-library/media-text/editor.min.css 320 B
build/styles/block-library/media-text/style-rtl.css 873 B
build/styles/block-library/media-text/style-rtl.min.css 552 B
build/styles/block-library/media-text/style.css 901 B
build/styles/block-library/media-text/style.min.css 550 B
build/styles/block-library/more/editor-rtl.css 796 B
build/styles/block-library/more/editor-rtl.min.css 393 B
build/styles/block-library/more/editor.css 798 B
build/styles/block-library/more/editor.min.css 393 B
build/styles/block-library/navigation-link/editor-rtl.css 1.28 kB
build/styles/block-library/navigation-link/editor-rtl.min.css 710 B
build/styles/block-library/navigation-link/editor.css 1.27 kB
build/styles/block-library/navigation-link/editor.min.css 713 B
build/styles/block-library/navigation-link/style-rtl.css 579 B
build/styles/block-library/navigation-link/style-rtl.min.css 190 B
build/styles/block-library/navigation-link/style.css 579 B
build/styles/block-library/navigation-link/style.min.css 188 B
build/styles/block-library/navigation-overlay-close/style-rtl.css 260 B
build/styles/block-library/navigation-overlay-close/style-rtl.min.css 237 B
build/styles/block-library/navigation-overlay-close/style.css 260 B
build/styles/block-library/navigation-overlay-close/style.min.css 237 B
build/styles/block-library/navigation-submenu/editor-rtl.css 1.12 kB
build/styles/block-library/navigation-submenu/editor-rtl.min.css 295 B
build/styles/block-library/navigation-submenu/editor.css 1.12 kB
build/styles/block-library/navigation-submenu/editor.min.css 294 B
build/styles/block-library/navigation/editor-rtl.css 3.28 kB
build/styles/block-library/navigation/editor-rtl.min.css 2.28 kB
build/styles/block-library/navigation/editor.css 3.29 kB
build/styles/block-library/navigation/editor.min.css 2.28 kB
build/styles/block-library/navigation/style-rtl.css 3.59 kB
build/styles/block-library/navigation/style-rtl.min.css 2.52 kB
build/styles/block-library/navigation/style.css 3.59 kB
build/styles/block-library/navigation/style.min.css 2.5 kB
build/styles/block-library/nextpage/editor-rtl.css 799 B
build/styles/block-library/nextpage/editor-rtl.min.css 392 B
build/styles/block-library/nextpage/editor.css 800 B
build/styles/block-library/nextpage/editor.min.css 392 B
build/styles/block-library/page-list/editor-rtl.css 1.18 kB
build/styles/block-library/page-list/editor-rtl.min.css 356 B
build/styles/block-library/page-list/editor.css 1.18 kB
build/styles/block-library/page-list/editor.min.css 356 B
build/styles/block-library/page-list/style-rtl.css 207 B
build/styles/block-library/page-list/style-rtl.min.css 192 B
build/styles/block-library/page-list/style.css 207 B
build/styles/block-library/page-list/style.min.css 192 B
build/styles/block-library/paragraph/editor-rtl.css 315 B
build/styles/block-library/paragraph/editor-rtl.min.css 292 B
build/styles/block-library/paragraph/editor.css 314 B
build/styles/block-library/paragraph/editor.min.css 292 B
build/styles/block-library/paragraph/style-rtl.css 746 B
build/styles/block-library/paragraph/style-rtl.min.css 341 B
build/styles/block-library/paragraph/style.css 752 B
build/styles/block-library/paragraph/style.min.css 340 B
build/styles/block-library/playlist-track/style-rtl.css 453 B
build/styles/block-library/playlist-track/style-rtl.min.css 420 B
build/styles/block-library/playlist-track/style.css 453 B
build/styles/block-library/playlist-track/style.min.css 420 B
build/styles/block-library/playlist/editor-rtl.css 120 B
build/styles/block-library/playlist/editor-rtl.min.css 112 B
build/styles/block-library/playlist/editor.css 120 B
build/styles/block-library/playlist/editor.min.css 112 B
build/styles/block-library/playlist/style-rtl.css 1.52 kB
build/styles/block-library/playlist/style-rtl.min.css 1.42 kB
build/styles/block-library/playlist/style.css 1.52 kB
build/styles/block-library/playlist/style.min.css 1.42 kB
build/styles/block-library/post-author-biography/style-rtl.css 96 B
build/styles/block-library/post-author-biography/style-rtl.min.css 86 B
build/styles/block-library/post-author-biography/style.css 96 B
build/styles/block-library/post-author-biography/style.min.css 86 B
build/styles/block-library/post-author-name/style-rtl.css 76 B
build/styles/block-library/post-author-name/style-rtl.min.css 69 B
build/styles/block-library/post-author-name/style.css 76 B
build/styles/block-library/post-author-name/style.min.css 69 B
build/styles/block-library/post-author/editor-rtl.css 490 B
build/styles/block-library/post-author/editor-rtl.min.css 104 B
build/styles/block-library/post-author/editor.css 490 B
build/styles/block-library/post-author/editor.min.css 104 B
build/styles/block-library/post-author/style-rtl.css 213 B
build/styles/block-library/post-author/style-rtl.min.css 188 B
build/styles/block-library/post-author/style.css 214 B
build/styles/block-library/post-author/style.min.css 189 B
build/styles/block-library/post-comments-count/style-rtl.css 79 B
build/styles/block-library/post-comments-count/style-rtl.min.css 72 B
build/styles/block-library/post-comments-count/style.css 79 B
build/styles/block-library/post-comments-count/style.min.css 72 B
build/styles/block-library/post-comments-form/editor-rtl.css 104 B
build/styles/block-library/post-comments-form/editor-rtl.min.css 96 B
build/styles/block-library/post-comments-form/editor.css 104 B
build/styles/block-library/post-comments-form/editor.min.css 96 B
build/styles/block-library/post-comments-form/style-rtl.css 585 B
build/styles/block-library/post-comments-form/style-rtl.min.css 525 B
build/styles/block-library/post-comments-form/style.css 584 B
build/styles/block-library/post-comments-form/style.min.css 525 B
build/styles/block-library/post-comments-link/style-rtl.css 78 B
build/styles/block-library/post-comments-link/style-rtl.min.css 71 B
build/styles/block-library/post-comments-link/style.css 78 B
build/styles/block-library/post-comments-link/style.min.css 71 B
build/styles/block-library/post-content/style-rtl.css 68 B
build/styles/block-library/post-content/style-rtl.min.css 61 B
build/styles/block-library/post-content/style.css 68 B
build/styles/block-library/post-content/style.min.css 61 B
build/styles/block-library/post-date/style-rtl.css 69 B
build/styles/block-library/post-date/style-rtl.min.css 62 B
build/styles/block-library/post-date/style.css 69 B
build/styles/block-library/post-date/style.min.css 62 B
build/styles/block-library/post-excerpt/editor-rtl.css 78 B
build/styles/block-library/post-excerpt/editor-rtl.min.css 71 B
build/styles/block-library/post-excerpt/editor.css 78 B
build/styles/block-library/post-excerpt/editor.min.css 71 B
build/styles/block-library/post-excerpt/style-rtl.css 171 B
build/styles/block-library/post-excerpt/style-rtl.min.css 155 B
build/styles/block-library/post-excerpt/style.css 171 B
build/styles/block-library/post-excerpt/style.min.css 155 B
build/styles/block-library/post-featured-image/editor-rtl.css 1.14 kB
build/styles/block-library/post-featured-image/editor-rtl.min.css 719 B
build/styles/block-library/post-featured-image/editor.css 1.14 kB
build/styles/block-library/post-featured-image/editor.min.css 717 B
build/styles/block-library/post-featured-image/style-rtl.css 392 B
build/styles/block-library/post-featured-image/style-rtl.min.css 347 B
build/styles/block-library/post-featured-image/style.css 392 B
build/styles/block-library/post-featured-image/style.min.css 347 B
build/styles/block-library/post-navigation-link/style-rtl.css 234 B
build/styles/block-library/post-navigation-link/style-rtl.min.css 215 B
build/styles/block-library/post-navigation-link/style.css 245 B
build/styles/block-library/post-navigation-link/style.min.css 214 B
build/styles/block-library/post-template/style-rtl.css 1.25 kB
build/styles/block-library/post-template/style-rtl.min.css 414 B
build/styles/block-library/post-template/style.css 1.25 kB
build/styles/block-library/post-template/style.min.css 414 B
build/styles/block-library/post-terms/style-rtl.css 108 B
build/styles/block-library/post-terms/style-rtl.min.css 96 B
build/styles/block-library/post-terms/style.css 108 B
build/styles/block-library/post-terms/style.min.css 96 B
build/styles/block-library/post-time-to-read/style-rtl.css 77 B
build/styles/block-library/post-time-to-read/style-rtl.min.css 70 B
build/styles/block-library/post-time-to-read/style.css 77 B
build/styles/block-library/post-time-to-read/style.min.css 70 B
build/styles/block-library/post-title/style-rtl.css 175 B
build/styles/block-library/post-title/style-rtl.min.css 162 B
build/styles/block-library/post-title/style.css 175 B
build/styles/block-library/post-title/style.min.css 162 B
build/styles/block-library/preformatted/style-rtl.css 511 B
build/styles/block-library/preformatted/style-rtl.min.css 125 B
build/styles/block-library/preformatted/style.css 511 B
build/styles/block-library/preformatted/style.min.css 125 B
build/styles/block-library/pullquote/editor-rtl.css 146 B
build/styles/block-library/pullquote/editor-rtl.min.css 133 B
build/styles/block-library/pullquote/editor.css 146 B
build/styles/block-library/pullquote/editor.min.css 133 B
build/styles/block-library/pullquote/style-rtl.css 765 B
build/styles/block-library/pullquote/style-rtl.min.css 365 B
build/styles/block-library/pullquote/style.css 764 B
build/styles/block-library/pullquote/style.min.css 365 B
build/styles/block-library/pullquote/theme-rtl.css 195 B
build/styles/block-library/pullquote/theme-rtl.min.css 176 B
build/styles/block-library/pullquote/theme.css 195 B
build/styles/block-library/pullquote/theme.min.css 176 B
build/styles/block-library/query-pagination-numbers/editor-rtl.css 134 B
build/styles/block-library/query-pagination-numbers/editor-rtl.min.css 121 B
build/styles/block-library/query-pagination-numbers/editor.css 144 B
build/styles/block-library/query-pagination-numbers/editor.min.css 118 B
build/styles/block-library/query-pagination/editor-rtl.css 168 B
build/styles/block-library/query-pagination/editor-rtl.min.css 154 B
build/styles/block-library/query-pagination/editor.css 168 B
build/styles/block-library/query-pagination/editor.min.css 154 B
build/styles/block-library/query-pagination/style-rtl.css 254 B
build/styles/block-library/query-pagination/style-rtl.min.css 237 B
build/styles/block-library/query-pagination/style.css 265 B
build/styles/block-library/query-pagination/style.min.css 237 B
build/styles/block-library/query-title/style-rtl.css 71 B
build/styles/block-library/query-title/style-rtl.min.css 64 B
build/styles/block-library/query-title/style.css 71 B
build/styles/block-library/query-title/style.min.css 64 B
build/styles/block-library/query-total/style-rtl.css 71 B
build/styles/block-library/query-total/style-rtl.min.css 64 B
build/styles/block-library/query-total/style.css 71 B
build/styles/block-library/query-total/style.min.css 64 B
build/styles/block-library/query/editor-rtl.css 1.28 kB
build/styles/block-library/query/editor-rtl.min.css 438 B
build/styles/block-library/query/editor.css 1.28 kB
build/styles/block-library/query/editor.min.css 438 B
build/styles/block-library/quote/style-rtl.css 255 B
build/styles/block-library/quote/style-rtl.min.css 238 B
build/styles/block-library/quote/style.css 256 B
build/styles/block-library/quote/style.min.css 238 B
build/styles/block-library/quote/theme-rtl.css 253 B
build/styles/block-library/quote/theme-rtl.min.css 233 B
build/styles/block-library/quote/theme.css 254 B
build/styles/block-library/quote/theme.min.css 236 B
build/styles/block-library/read-more/style-rtl.css 146 B
build/styles/block-library/read-more/style-rtl.min.css 131 B
build/styles/block-library/read-more/style.css 146 B
build/styles/block-library/read-more/style.min.css 131 B
build/styles/block-library/reset-rtl.css 936 B
build/styles/block-library/reset-rtl.min.css 467 B
build/styles/block-library/reset.css 936 B
build/styles/block-library/reset.min.css 467 B
build/styles/block-library/rss/editor-rtl.css 144 B
build/styles/block-library/rss/editor-rtl.min.css 126 B
build/styles/block-library/rss/editor.css 144 B
build/styles/block-library/rss/editor.min.css 126 B
build/styles/block-library/rss/style-rtl.css 1.11 kB
build/styles/block-library/rss/style-rtl.min.css 284 B
build/styles/block-library/rss/style.css 1.12 kB
build/styles/block-library/rss/style.min.css 283 B
build/styles/block-library/search/editor-rtl.css 217 B
build/styles/block-library/search/editor-rtl.min.css 199 B
build/styles/block-library/search/editor.css 217 B
build/styles/block-library/search/editor.min.css 199 B
build/styles/block-library/search/style-rtl.css 1.1 kB
build/styles/block-library/search/style-rtl.min.css 665 B
build/styles/block-library/search/style.css 1.1 kB
build/styles/block-library/search/style.min.css 666 B
build/styles/block-library/search/theme-rtl.css 130 B
build/styles/block-library/search/theme-rtl.min.css 113 B
build/styles/block-library/search/theme.css 130 B
build/styles/block-library/search/theme.min.css 113 B
build/styles/block-library/separator/editor-rtl.css 106 B
build/styles/block-library/separator/editor-rtl.min.css 100 B
build/styles/block-library/separator/editor.css 106 B
build/styles/block-library/separator/editor.min.css 100 B
build/styles/block-library/separator/style-rtl.css 284 B
build/styles/block-library/separator/style-rtl.min.css 248 B
build/styles/block-library/separator/style.css 297 B
build/styles/block-library/separator/style.min.css 248 B
build/styles/block-library/separator/theme-rtl.css 226 B
build/styles/block-library/separator/theme-rtl.min.css 195 B
build/styles/block-library/separator/theme.css 226 B
build/styles/block-library/separator/theme.min.css 195 B
build/styles/block-library/shortcode/editor-rtl.css 1.1 kB
build/styles/block-library/shortcode/editor-rtl.min.css 286 B
build/styles/block-library/shortcode/editor.css 1.1 kB
build/styles/block-library/shortcode/editor.min.css 286 B
build/styles/block-library/site-logo/editor-rtl.css 1.12 kB
build/styles/block-library/site-logo/editor-rtl.min.css 696 B
build/styles/block-library/site-logo/editor.css 1.12 kB
build/styles/block-library/site-logo/editor.min.css 692 B
build/styles/block-library/site-logo/style-rtl.css 239 B
build/styles/block-library/site-logo/style-rtl.min.css 218 B
build/styles/block-library/site-logo/style.css 238 B
build/styles/block-library/site-logo/style.min.css 218 B
build/styles/block-library/site-tagline/editor-rtl.css 94 B
build/styles/block-library/site-tagline/editor-rtl.min.css 87 B
build/styles/block-library/site-tagline/editor.css 94 B
build/styles/block-library/site-tagline/editor.min.css 87 B
build/styles/block-library/site-tagline/style-rtl.css 72 B
build/styles/block-library/site-tagline/style-rtl.min.css 65 B
build/styles/block-library/site-tagline/style.css 72 B
build/styles/block-library/site-tagline/style.min.css 65 B
build/styles/block-library/site-title/editor-rtl.css 93 B
build/styles/block-library/site-title/editor-rtl.min.css 85 B
build/styles/block-library/site-title/editor.css 93 B
build/styles/block-library/site-title/editor.min.css 85 B
build/styles/block-library/site-title/style-rtl.css 153 B
build/styles/block-library/site-title/style-rtl.min.css 143 B
build/styles/block-library/site-title/style.css 153 B
build/styles/block-library/site-title/style.min.css 143 B
build/styles/block-library/social-link/editor-rtl.css 346 B
build/styles/block-library/social-link/editor-rtl.min.css 314 B
build/styles/block-library/social-link/editor.css 348 B
build/styles/block-library/social-link/editor.min.css 314 B
build/styles/block-library/social-links/editor-rtl.css 737 B
build/styles/block-library/social-links/editor-rtl.min.css 339 B
build/styles/block-library/social-links/editor.css 738 B
build/styles/block-library/social-links/editor.min.css 338 B
build/styles/block-library/social-links/style-rtl.css 1.57 kB
build/styles/block-library/social-links/style-rtl.min.css 1.51 kB
build/styles/block-library/social-links/style.css 1.57 kB
build/styles/block-library/social-links/style.min.css 1.51 kB
build/styles/block-library/spacer/editor-rtl.css 774 B
build/styles/block-library/spacer/editor-rtl.min.css 346 B
build/styles/block-library/spacer/editor.css 774 B
build/styles/block-library/spacer/editor.min.css 346 B
build/styles/block-library/spacer/style-rtl.css 55 B
build/styles/block-library/spacer/style-rtl.min.css 48 B
build/styles/block-library/spacer/style.css 55 B
build/styles/block-library/spacer/style.min.css 48 B
build/styles/block-library/style-rtl.css 21.5 kB
build/styles/block-library/style-rtl.min.css 18 kB
build/styles/block-library/style.css 21.6 kB
build/styles/block-library/style.min.css 18 kB
build/styles/block-library/tab-panel/style-rtl.css 75 B
build/styles/block-library/tab-panel/style-rtl.min.css 64 B
build/styles/block-library/tab-panel/style.css 75 B
build/styles/block-library/tab-panel/style.min.css 64 B
build/styles/block-library/tab/style-rtl.css 233 B
build/styles/block-library/tab/style-rtl.min.css 210 B
build/styles/block-library/tab/style.css 233 B
build/styles/block-library/tab/style.min.css 210 B
build/styles/block-library/table-of-contents/style-rtl.css 89 B
build/styles/block-library/table-of-contents/style-rtl.min.css 83 B
build/styles/block-library/table-of-contents/style.css 89 B
build/styles/block-library/table-of-contents/style.min.css 83 B
build/styles/block-library/table/editor-rtl.css 1.25 kB
build/styles/block-library/table/editor-rtl.min.css 394 B
build/styles/block-library/table/editor.css 1.25 kB
build/styles/block-library/table/editor.min.css 394 B
build/styles/block-library/table/style-rtl.css 1.06 kB
build/styles/block-library/table/style-rtl.min.css 641 B
build/styles/block-library/table/style.css 1.06 kB
build/styles/block-library/table/style.min.css 640 B
build/styles/block-library/table/theme-rtl.css 985 B
build/styles/block-library/table/theme-rtl.min.css 152 B
build/styles/block-library/table/theme.css 985 B
build/styles/block-library/table/theme.min.css 152 B
build/styles/block-library/tabs-menu-item/editor-rtl.css 168 B
build/styles/block-library/tabs-menu-item/editor-rtl.min.css 155 B
build/styles/block-library/tabs-menu-item/editor.css 168 B
build/styles/block-library/tabs-menu-item/editor.min.css 155 B
build/styles/block-library/tabs-menu-item/style-rtl.css 404 B
build/styles/block-library/tabs-menu-item/style-rtl.min.css 361 B
build/styles/block-library/tabs-menu-item/style.css 405 B
build/styles/block-library/tabs-menu-item/style.min.css 362 B
build/styles/block-library/tabs-menu/editor-rtl.css 116 B
build/styles/block-library/tabs-menu/editor-rtl.min.css 104 B
build/styles/block-library/tabs-menu/editor.css 116 B
build/styles/block-library/tabs-menu/editor.min.css 104 B
build/styles/block-library/tabs/style-rtl.css 64 B
build/styles/block-library/tabs/style-rtl.min.css 57 B
build/styles/block-library/tabs/style.css 64 B
build/styles/block-library/tabs/style.min.css 57 B
build/styles/block-library/tag-cloud/style-rtl.css 283 B
build/styles/block-library/tag-cloud/style-rtl.min.css 248 B
build/styles/block-library/tag-cloud/style.css 283 B
build/styles/block-library/tag-cloud/style.min.css 248 B
build/styles/block-library/template-part/editor-rtl.css 1.2 kB
build/styles/block-library/template-part/editor-rtl.min.css 368 B
build/styles/block-library/template-part/editor.css 1.2 kB
build/styles/block-library/template-part/editor.min.css 368 B
build/styles/block-library/template-part/theme-rtl.css 492 B
build/styles/block-library/template-part/theme-rtl.min.css 113 B
build/styles/block-library/template-part/theme.css 492 B
build/styles/block-library/template-part/theme.min.css 113 B
build/styles/block-library/term-count/style-rtl.css 70 B
build/styles/block-library/term-count/style-rtl.min.css 63 B
build/styles/block-library/term-count/style.css 70 B
build/styles/block-library/term-count/style.min.css 63 B
build/styles/block-library/term-description/style-rtl.css 138 B
build/styles/block-library/term-description/style-rtl.min.css 126 B
build/styles/block-library/term-description/style.css 138 B
build/styles/block-library/term-description/style.min.css 126 B
build/styles/block-library/term-name/style-rtl.css 69 B
build/styles/block-library/term-name/style-rtl.min.css 62 B
build/styles/block-library/term-name/style.css 69 B
build/styles/block-library/term-name/style.min.css 62 B
build/styles/block-library/term-template/editor-rtl.css 267 B
build/styles/block-library/term-template/editor-rtl.min.css 225 B
build/styles/block-library/term-template/editor.css 267 B
build/styles/block-library/term-template/editor.min.css 225 B
build/styles/block-library/term-template/style-rtl.css 124 B
build/styles/block-library/term-template/style-rtl.min.css 114 B
build/styles/block-library/term-template/style.css 124 B
build/styles/block-library/term-template/style.min.css 114 B
build/styles/block-library/text-columns/editor-rtl.css 481 B
build/styles/block-library/text-columns/editor-rtl.min.css 95 B
build/styles/block-library/text-columns/editor.css 481 B
build/styles/block-library/text-columns/editor.min.css 95 B
build/styles/block-library/text-columns/style-rtl.css 177 B
build/styles/block-library/text-columns/style-rtl.min.css 165 B
build/styles/block-library/text-columns/style.css 177 B
build/styles/block-library/text-columns/style.min.css 165 B
build/styles/block-library/theme-rtl.css 1.59 kB
build/styles/block-library/theme-rtl.min.css 715 B
build/styles/block-library/theme.css 1.6 kB
build/styles/block-library/theme.min.css 719 B
build/styles/block-library/verse/style-rtl.css 155 B
build/styles/block-library/verse/style-rtl.min.css 137 B
build/styles/block-library/verse/style.css 155 B
build/styles/block-library/verse/style.min.css 137 B
build/styles/block-library/video/editor-rtl.css 825 B
build/styles/block-library/video/editor-rtl.min.css 415 B
build/styles/block-library/video/editor.css 826 B
build/styles/block-library/video/editor.min.css 416 B
build/styles/block-library/video/style-rtl.css 1.02 kB
build/styles/block-library/video/style-rtl.min.css 202 B
build/styles/block-library/video/style.css 1.02 kB
build/styles/block-library/video/style.min.css 202 B
build/styles/block-library/video/theme-rtl.css 967 B
build/styles/block-library/video/theme-rtl.min.css 134 B
build/styles/block-library/video/theme.css 967 B
build/styles/block-library/video/theme.min.css 134 B
build/styles/commands/style-rtl.css 2.07 kB
build/styles/commands/style-rtl.min.css 1.17 kB
build/styles/commands/style.css 2.06 kB
build/styles/commands/style.min.css 1.17 kB
build/styles/components/style-rtl.css 17.3 kB
build/styles/components/style-rtl.min.css 14.1 kB
build/styles/components/style.css 17.4 kB
build/styles/components/style.min.css 14.1 kB
build/styles/customize-widgets/style-rtl.css 2.35 kB
build/styles/customize-widgets/style-rtl.min.css 1.44 kB
build/styles/customize-widgets/style.css 2.35 kB
build/styles/customize-widgets/style.min.css 1.44 kB
build/styles/edit-post/classic-rtl.css 1.29 kB
build/styles/edit-post/classic-rtl.min.css 425 B
build/styles/edit-post/classic.css 1.31 kB
build/styles/edit-post/classic.min.css 428 B
build/styles/edit-post/style-rtl.css 3.98 kB
build/styles/edit-post/style-rtl.min.css 2.67 kB
build/styles/edit-post/style.css 3.99 kB
build/styles/edit-post/style.min.css 2.67 kB
build/styles/edit-site/style-rtl.css 20.9 kB
build/styles/edit-site/style-rtl.min.css 17.1 kB
build/styles/edit-site/style.css 21 kB
build/styles/edit-site/style.min.css 17.1 kB
build/styles/edit-widgets/style-rtl.css 5.29 kB
build/styles/edit-widgets/style-rtl.min.css 3.95 kB
build/styles/edit-widgets/style.css 5.29 kB
build/styles/edit-widgets/style.min.css 3.96 kB
build/styles/editor/style-rtl.css 26.6 kB
build/styles/editor/style-rtl.min.css 22.5 kB
build/styles/editor/style.css 26.6 kB
build/styles/editor/style.min.css 22.4 kB
build/styles/format-library/style-rtl.css 735 B
build/styles/format-library/style-rtl.min.css 326 B
build/styles/format-library/style.css 746 B
build/styles/format-library/style.min.css 326 B
build/styles/list-reusable-blocks/style-rtl.css 1.07 kB
build/styles/list-reusable-blocks/style-rtl.min.css 250 B
build/styles/list-reusable-blocks/style.css 1.07 kB
build/styles/list-reusable-blocks/style.min.css 249 B
build/styles/media-utils/style-rtl.css 2.08 kB
build/styles/media-utils/style-rtl.min.css 1.17 kB
build/styles/media-utils/style.css 2.08 kB
build/styles/media-utils/style.min.css 1.17 kB
build/styles/nux/style-rtl.css 1.48 kB
build/styles/nux/style-rtl.min.css 622 B
build/styles/nux/style.css 1.5 kB
build/styles/nux/style.min.css 618 B
build/styles/patterns/style-rtl.css 1.46 kB
build/styles/patterns/style-rtl.min.css 611 B
build/styles/patterns/style.css 1.46 kB
build/styles/patterns/style.min.css 611 B
build/styles/preferences/style-rtl.css 1.26 kB
build/styles/preferences/style-rtl.min.css 415 B
build/styles/preferences/style.css 1.26 kB
build/styles/preferences/style.min.css 415 B
build/styles/reusable-blocks/style-rtl.css 1.11 kB
build/styles/reusable-blocks/style-rtl.min.css 275 B
build/styles/reusable-blocks/style.css 1.11 kB
build/styles/reusable-blocks/style.min.css 275 B
build/styles/widgets/style-rtl.css 2.05 kB
build/styles/widgets/style-rtl.min.css 1.16 kB
build/styles/widgets/style.css 2.06 kB
build/styles/widgets/style.min.css 1.16 kB

compressed-size-action

@glendaviesnz
Copy link
Copy Markdown
Contributor Author

It is not quite working yet. Warning banner shows but CSS is not stripped - looking at it

@github-actions
Copy link
Copy Markdown

github-actions Bot commented Mar 18, 2026

Flaky tests detected in f9947cc.
Some tests passed with failed attempts. The failures may not be related to this commit but are still reported for visibility. See the documentation for more information.

🔍 Workflow run URL: https://github.com/WordPress/gutenberg/actions/runs/24547321719
📝 Reported issues:

@glendaviesnz
Copy link
Copy Markdown
Contributor Author

Seems to be working now @aaronrobertshaw - was just an issue with the stripping not accounting for escaped content.

Copy link
Copy Markdown
Contributor

@aaronrobertshaw aaronrobertshaw left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the quick work on this fix @glendaviesnz 🚀

This is mostly testing well for me however I think I found one small issue.

✅ Editing as Author strips custom CSS on save and it's no longer output on frontend
✅ Opening a post as Admin does not show the warning banner
✅ Saving a post with custom CSS in blocks as Admin works as expected
✅ Could not add block with custom CSS via code editor as Author
✅ Could not add custom CSS in block content via REST API
✅ Existing tests are passing locally

❓ Warning banner does not show until selecting a block with custom CSS when opening post as an Author

Overall, the approach looks good to me. Mirroring core's KSES pattern with the init and set_current_user hooks seems legit and covers the REST API saves too.

Good catch on the slashing bug as well 👍

It might be worth noting in the PR description that existing posts with the custom CSS already saved won't be cleaned up, and that saved custom CSS will still render on the frontend. Both seem intentional and reasonable, but probably worth being explicit about.

I think this is pretty close. My understanding is that there should be an immediate warning banner for Author users etc and that's not what I was seeing:

Screen.Recording.2026-03-19.at.1.44.12.am.mp4

@glendaviesnz
Copy link
Copy Markdown
Contributor Author

❓ Warning banner does not show until selecting a block with custom CSS when opening post as an Author

It should show as soon as post opened now.

It might be worth noting in the PR description that existing posts with the custom CSS already saved won't be cleaned up

Done

Copy link
Copy Markdown
Member

@ramonjd ramonjd left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the continued efforts here @glendaviesnz

Sorry for all the questions. I'm primarily thinking about how this translates to Core. And I'm overthinking things :D

Comment thread lib/block-supports/custom-css.php Outdated
Comment thread packages/block-editor/src/hooks/custom-css.js Outdated
Comment thread lib/block-supports/custom-css.php
Comment thread packages/block-editor/src/hooks/custom-css.js Outdated
Comment thread packages/block-editor/src/hooks/custom-css.js Outdated
Comment on lines +248 to +249
add_action( 'init', 'gutenberg_custom_css_kses_init', 20 );
add_action( 'set_current_user', 'gutenberg_custom_css_kses_init' );
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just so I understand, these checks remove/add the hooks for different scenarios, e.g., page requests and REST?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes exactly. This mirrors the pattern Core uses for KSES in kses_init() / kses_init_filters(). The init hook covers the normal page-load/REST request path, and set_current_user covers cases where the current user changes after init (e.g. application passwords on REST, or XML-RPC authentication). The remove-then-conditionally-add pattern in gutenberg_custom_css_kses_init() ensures the filters are always in sync with whoever the current user actually is.

Comment thread lib/block-supports/custom-css.php Outdated
*
* @param array $blocks Blocks to process.
*/
$strip = static function ( &$blocks ) use ( &$strip, &$changed ) {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Any reason not to use a helper that returns a boolean?

I guess it's "another function" in the global namespace, but you wouldn't need to capture the references here. And $changed = false; could go.

No action required, just a thought.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No strong reason — the closure keeps it self-contained and avoids polluting the global namespace as you noted. A named helper would be slightly cleaner to read but adds another gutenberg_ prefixed function for something that's only used in one place. Happy to refactor if there's a preference either way, but leaving as-is for now.

* @param string $content Post content to filter.
* @return string Filtered post content with block custom CSS removed.
*/
function gutenberg_strip_custom_css_from_blocks( $content ) {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What are your thoughts on the migration path to Core here? I hesitate to say it out loud but filter_block_kses_value seems like candidate. Anyway, if and when it becomes clear, it might be worth noting them for the backport.

Copy link
Copy Markdown
Contributor Author

@glendaviesnz glendaviesnz Mar 19, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good question. filter_block_kses_value is an interesting candidate — it already walks block attributes during KSES and could potentially strip style.css inline rather than needing the separate content filter approach. The tricky part is that filter_block_kses_value operates at the attribute level during KSES processing, while this approach operates on the full serialized content, and probably more importantly it was already noted on the abandoned fix in core that this is not a KSES issue - mixing the CSS fix back into KSES at this point seems to muddy that water again.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, it's tricky 🤔

The question is going to come up at some point though: "Where would this all live in Core?" As a set of filters perhaps?

*/
function gutenberg_custom_css_force_filtered_html_on_import_filter( $arg ) {
if ( $arg ) {
gutenberg_custom_css_kses_init_filters();
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is this doing exactly? Would it strip CSS for admins during import as well?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, this is the import safety net — again mirroring what Core does for KSES. When force_filtered_html_on_import is true (e.g. during a WXR import), it unconditionally enables the CSS stripping filters regardless of the current user's capabilities. So even an admin importing content would have custom CSS stripped. The rationale is the same as KSES during import: you can't trust the content source, so filter it regardless of who is doing the import.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Got it, thanks for the explainer

Comment on lines +200 to +201
add_filter( 'content_save_pre', 'gutenberg_strip_custom_css_from_blocks', 8 );
add_filter( 'content_filtered_save_pre', 'gutenberg_strip_custom_css_from_blocks', 8 );
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

wp_insert_post_data looks like it comes bundled with post_content and post_content_filtered in the $data arg.

It runs after KSES, but I guess that doesn't matter if we're stripping it.

And I think you wouldn't need the init/set_current_user dance either because wp_insert_post_data fires inside wp_insert_post() at the moment of save, and current_user_can('edit_css')` is evaluated in the hook callback against whoever is actually saving.

I could be missing something obvious.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's a fair point — wp_insert_post_data would simplify things since the capability check happens at save time against the actual user. The main reason for mirroring the KSES pattern (content_save_pre + init/set_current_user) was to stay consistent with how Core handles similar content filtering, which makes the eventual backport more straightforward. The content_save_pre / content_filtered_save_pre hooks are the same ones KSES uses, so the stripping runs at the same stage in the save pipeline. wp_insert_post_data runs later and bundles both fields in $data, which could work but would diverge from the established pattern. Open to changing it if you feel the simplicity outweighs the consistency argument though.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't have a strong opinion, and thanks for confirming.

As noted above I'm just thinking about how this would look in Core, and where the processing would take place.

I guess it's contained to the custom-css.php file for now, and, as you say, it could follow the footnotes precedent:

https://github.com/wordpress/wordpress-develop/blob/trunk/src/wp-includes/blocks.php#L3107

@ramonjd ramonjd added the [Type] Bug An existing feature does not function as intended label Mar 20, 2026
@ramonjd
Copy link
Copy Markdown
Member

ramonjd commented Mar 20, 2026

Just kicked off the E2E tests. They don't look related.

I think this is a good change for the plugin.

What's the Core plan do you think? Did we miss the WordPress boat? There are a couple of RCs https://make.wordpress.org/core/2026/02/12/wordpress-7-0-release-party-schedule/

It's be good to get a Core backport up so folks with bigger brains than I have can discuss it there too.

Thanks, Glen!

@ramonjd ramonjd force-pushed the strip-css-for-non-edit-css-users branch from 2845a81 to 8aa2961 Compare March 20, 2026 02:14
@ramonjd
Copy link
Copy Markdown
Member

ramonjd commented Mar 20, 2026

Rebased

Comment thread lib/block-supports/custom-css.php Outdated
$strip( $block['innerBlocks'] );
}
}
};
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

particularly given that we only changing the JSON attributes and uninterested in the order of traversal, a simpler stack-based approach could be more efficient than recursion due to the continued high cost of PHP function calls.

$blocks  = parse_blocks( $unslashed );
$changed = false;

while ( null !== ( $block = array_pop( $blocks ) ) {
	…
	
	foreach ( $block['innerBlocks'] as $inner_block ) {
		$blocks[] = $inner_block;
	}
}

that might need an extra & somewhere.

I recently also proposed use of the WP_Block_Processor for this kind of operation, as it allows us to avoid a lot of work. it doesn’t yet have support for modifying the JSON attributes, but we can handle that in a couple of different ways currently.

$processor   = new WP_Block_Processor( $unslashed );
$without_css = '';
$was_at      = 0;

while ( $processor->next_block() ) {
	$span = $processor->get_span();
	$text = substr( $unslashed, $span->start, $span->length );

	// the text cannot contain a `style.css` attribute.
	if ( false === strpos( $text, '"css"' ) ) {
		continue;
	}

	$attrs = $processor->allocate_and_return_parsed_attributes();
	if ( ! empty( $attrs['style']['css'] ) ) {
		continue;
	}

	unset( $attrs['styling']['css'] );

	$attrs = empty( $attrs ) ? '' : wp_json_serialize( … );
	$slash = 'void' === $processor->get_delimiter_type() ? '/' : '';

	$without_css .= substr( $unslashed, $was_at, $span->start - $was_at );
	$without_css .= "<!-- wp:{$processor->get_block_type()} {$attrs} {$slash}-->";
	$was_at       = $span->start + $span->length;
}

if ( 0 === $was_at ) {
	return $content;
}

if ( $was_at < strlen( $unslashed ) ) {
	$without_css .= substr( $unslashed, $was_at );
}

return wp_slash( $without_css );

Copy link
Copy Markdown
Contributor Author

@glendaviesnz glendaviesnz Mar 23, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the suggestion! Implemented the stack-based approach in 461e443.

Re WP_Block_Processor — I considered it, but it seems like it is WP 6.9+ and GB currently also supports 6.8, so might be worth revisting once GB support is bumped to 6.9.

For the stack-based loop itself: the key detail is that every entry on the stack is a by-reference alias back into $blocks. When we do $block = &$stack[count($stack) - 1] we get a mutable reference to the actual block in the tree, so unset($block['attrs']['style']['css']) mutates the original $blocks array in-place — no need to rebuild anything. Inner blocks are pushed by reference too (foreach ($block['innerBlocks'] as &$inner_block)), so nested mutations propagate all the way up. The unset($block) at the end of each iteration breaks the reference variable to prevent cross-iteration contamination. Net result: same behavior, no closure overhead, flat loop. If this is not what you were suggesting/expecting, let me know.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, interesting, thanks for the link @dmsnell, I just pushed a change that uses this approach - need to do a bit more testing on it though to confirm it all still works as expected

@glendaviesnz
Copy link
Copy Markdown
Contributor Author

glendaviesnz commented Mar 23, 2026

Should we preserve CSS when it hasn't changed?

Currently gutenberg_strip_custom_css_from_blocks() unconditionally strips all style.css attributes when a user without edit_css saves a post. This is destructive — if an admin added custom CSS and a contributor later edits the post text, the contributor's save wipes out the admin's CSS even though they never touched it.

An alternative: compare the incoming content against the already-saved content and only strip CSS that actually changed.

The problem with content_save_pre

The current filter hook (content_save_pre) only receives the raw content string — no post ID, no access to the previously saved version. So there's no way to compare old vs new at that hook.

A feasible approach: wp_insert_post_data

The wp_insert_post_data filter receives ($data, $postarr) where $postarr['ID'] gives us the post ID for updates. We can then call get_post($postarr['ID']) to retrieve the saved content and compare.

The comparison itself would be straightforward:

  1. Parse both old and new content into blocks
  2. Walk both block trees and collect all style.css values into sorted arrays
  3. If the sorted arrays are identical → CSS is unchanged → preserve it
  4. If they differ → CSS was modified → strip everything (conservative)
  5. For new posts (no saved version) → strip everything

The sorted-array comparison is deliberately conservative: any change to the CSS set (add, remove, modify, duplicate) triggers a full strip. This avoids the complexity of per-block identity matching (blocks don't have stable IDs across parses). Block reordering alone won't trigger a false strip since identical values sort identically regardless of position.

Edge cases

Scenario Behavior
User reorders blocks, CSS unchanged Sorted arrays match → CSS preserved
User duplicates a block with CSS Array length differs → strip all (conservative but safe)
User deletes a block with CSS Missing value → strip all (conservative but safe)
Copy-paste block with CSS from another post New value in set → strip all (correct)
New post, no saved content Strip all (no comparison possible)
Import path Always strip unconditionally (already handled)

Hook change implications

  • Moving from content_save_pre to wp_insert_post_data breaks the kses-mirror pattern but is the only way to get the post ID
  • wp_insert_post_data covers all save paths (REST API, classic editor, XML-RPC)
  • content_filtered_save_pre would need separate handling or an unconditional fallback
  • Slashing behavior is the same ($data['post_content'] arrives slashed)
  • One extra get_post() call per save, but WP likely has the post cached already

Verdict

Feasible and the comparison logic is simple, but the hook change adds complexity. The main benefit is preventing accidental CSS loss when contributors save posts where an admin previously added custom CSS. Worth doing if that's a real pain point, but the current unconditional strip is simpler and more obviously correct from a security perspective.

Thoughts on whether this is worth pursuing @aaronrobertshaw, @ramonjd, @dmsnell ?

Comment thread lib/block-supports/custom-css.php Outdated

while ( ! empty( $stack ) ) {
$block = &$stack[ count( $stack ) - 1 ];
array_pop( $stack );
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I get confused on this because objects are returned as refs and I thought the array would be too. I’m glad you figured out the right conventions.

Comment thread lib/block-supports/custom-css.php Outdated
$unslashed = wp_unslash( $content );

// Fast check: if no "css" key anywhere, skip parsing entirely.
if ( false === strpos( $unslashed, '"css"' ) ) {
Copy link
Copy Markdown
Member

@dmsnell dmsnell Mar 24, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we have str_contains() and WPCS will flag this as poor quality, even though it’s fine.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed

Comment thread lib/block-supports/custom-css.php Outdated

if ( false === $json_rel_end || $json_rel_start >= $json_rel_end ) {
continue;
}
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I left a note in the other PR about this check. at this point we know the conditions have to be true or we would have bailed already. we can provide a comment or leave the check in, but its awkward that we’re not examining $json_rel_start

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed

@dmsnell
Copy link
Copy Markdown
Member

dmsnell commented Mar 24, 2026

whether this is worth pursuing

it definitely seems worth pursuing, but I think it also requires a few more steps of care to ensure we don’t allow something nefarious. for instance, relying on sorted captures of the styles does ensure that no new styles are introduced, but they could have still be moved from one block to another, and I can imagine there could be downsides to that.

we should be able to combine efforts with what is happening with real-time collaboration and identify which portions of the document are changed, and then ask if the CSS is changing or not.

when are you trying to get this in? is it still for WordPress 7.0?

if transplanting existing CSS onto another block is not considered a risk then the sorting approach isn’t bad. it could be better than wiping out everything.


one thing remaining which seems the most important thing here is communicating to an editor that the CSS is being removed. I don’t even feel like this would be a problem if we communicated that in the editor before saving. that would take additional code and wouldn’t be in the REST API calls (though we could also return an error and provide a message like “would wipe out CSS, retry with ?remove_untrusted_css_changes to force”).

I would just really hope we don’t surprise people by corrupting a post on save, especially since this doesn’t typically show up until after leaving the editor and re-opening the post.

within the editor we have clientId values for each block and can positively identify CSS changes. that is, there would be no need to sort blocks because we could identify if the CSS was changed and if so, alert the user and selectively remove the CSS changes, leaving all unchanged CSS the same.

@aaronrobertshaw
Copy link
Copy Markdown
Contributor

The main benefit is preventing accidental CSS loss when contributors save posts where an admin previously added custom CSS.

I'm still catching up on the discussion, but at a glance, if we can tick all the security boxes well enough I'd say optimising for the end user experience here would be the best bet.

@glendaviesnz
Copy link
Copy Markdown
Contributor Author

one thing remaining which seems the most important thing here is communicating to an editor that the CSS is being removed

@dmsnell this PR includes a warning notice in the editor if a user without unfiltered_html opens a post with block level CSS:

Screenshot 2026-03-24 at 2 33 40 PM

within the editor we have clientId values for each block and can positively identify CSS changes. that is, there would be no need to sort blocks because we could identify if the CSS was changed and if so, alert the user and selectively remove the CSS changes, leaving all unchanged CSS the same.

I think the only problem is that a user can manipulate it all, and save, in code view, and so bypass any checks we might be doing in the editor.

@aaronrobertshaw, @ramonjd, @dmsnell I am thinking if we want any chance of getting this into a 7.0 RC (and it seems like it is important enough a security risk to try for that - but happy to take your more current core release experience on that) then I think we need to keep it simple and just stick with the warning to the user and stripping all block CSS if they save.

It seems that adding in trying to determine which CSS may or may not have changed adds another level of complexity and opens us up to missing some combination of manual innocent versus nefarious combination of CSS changes. It seems like this will be an edge case for 7.0. I suspect the number of people adding block level CSS to posts that are then edited by author level users and below is going to be very small, and 🤞 a more robust approach can be put in place for 7.1.

@dmsnell
Copy link
Copy Markdown
Member

dmsnell commented Mar 24, 2026

this PR includes a warning notice in the editor

sorry for missing that @glendaviesnz — very good

getting this into a 7.0 RC

in that case I vote for scope-cutting it and leaving it as-is. @sirreal’s input would also be nice. we will be really rushing if we try to peel open the conservative approach in the timespan of a couple days.

@aaronrobertshaw
Copy link
Copy Markdown
Contributor

in that case I vote for scope-cutting it and leaving it as-is.

+1 to leaving scope as is. Iterating on the approach could be considered an enhancement for 7.1.

@glendaviesnz
Copy link
Copy Markdown
Contributor Author

@dmsnell I had a quick look at the possibility of also adding a warning in REST as you suggested, but this also adds a bit of complexity, are you happy for this to be a follow up as well? I imagine an author or less user updating via REST only, and not the editor is probably also fairly uncommon.

@glendaviesnz
Copy link
Copy Markdown
Contributor Author

@ramonjd, @aaronrobertshaw, @dmsnell, @sirreal - i guess this needs to be answered before we merge this - will leave it in your capable hands to debate this - feel free to go ahead and merge this once that is decided.

@ramonjd
Copy link
Copy Markdown
Member

ramonjd commented Mar 25, 2026

Do you mean this comment?

concerned about the idea of just adding a notice as it won't stop users from potentially breaking a page without the ability to unbreak it.
This needs either a proper solution that won't lead to broken webpages or the per block css feature should be punted from 7.0.

I replied and asked for alternatives: https://core.trac.wordpress.org/ticket/64771#comment:44

Another idea is to punt and leave this in GB for a cycle.

@glendaviesnz
Copy link
Copy Markdown
Contributor Author

Do you mean this comment?

Yes that was it. I personally think @sirreal's latest comment there makes sense. This matches other approaches to non unfiltered_html users editing content, and realistically it is an extreme edge case of an author user being allowed to edit a higher level users post, and then ignoring the warning and modifying and saving, and as you note, revisions are there as a fallback. Pulling the feature seems unnecessary.

@ramonjd
Copy link
Copy Markdown
Member

ramonjd commented Apr 17, 2026

Can we get this in @glendaviesnz and prep WordPress/wordpress-develop#11347 Looks like it plugs a hole

Cover save-time stripping of style.css from block attributes:
single blocks, nested inner blocks, non-block content passthrough,
preservation of other style properties, and empty style cleanup.
content_save_pre receives slashed content (escaped quotes), which
breaks parse_blocks JSON parsing. Unslash before parsing and re-slash
after serializing. Add test for slashed content handling.
The edit hook only renders when a block is selected, so the warning
notice was not shown until the user selected a block with custom CSS.
Move the notice dispatch to useBlockProps which runs for all blocks
on mount via createBlockListBlockFilter, ensuring the banner appears
as soon as the post is opened.
Gutenberg plugin doesn't use @SInCE tags — they're added during Core backport.
Rephrase for clarity: "If you save this post, the custom CSS will be removed."
Trim the customCSS value before checking truthiness so that
whitespace-only strings (e.g. '   ') don't trigger the
"custom CSS will be removed" warning notice.
Replace parse_blocks() + stack traversal + serialize_blocks() with
WP_Block_Parser::next_token() to scan tokens and splice only the
changed attribute JSON into the original string. This avoids the
parse/serialize round-trip and any formatting drift it may cause.

Pattern follows the WordPress importer approach endorsed by dmsnell.
Use str_contains() instead of strpos() for the fast-check and remove
the unnecessary $json_rel_start/$json_rel_end validation since the
parser guarantees valid JSON braces at that point.
…fast-path

- Replace wp_unslash/wp_slash with stripslashes/addslashes (content is always a string)
- Remove str_contains('"css"') short-circuit that could miss alternate JSON encodings
- Document slashed input expectation in @param docstring
- Fix PHPCS alignment warnings
@ramonjd ramonjd force-pushed the strip-css-for-non-edit-css-users branch from a8942ce to f9947cc Compare April 17, 2026 04:14
@ramonjd
Copy link
Copy Markdown
Member

ramonjd commented Apr 17, 2026

I'll merge this, and rebase WordPress/wordpress-develop#11347, and see if we can some 👀 on it.

@ramonjd ramonjd added the Backport to WP 7.0 Beta/RC Pull request that needs to be backported to the WordPress major release that's currently in beta label Apr 17, 2026
@ramonjd ramonjd merged commit 1c7fb7c into trunk Apr 17, 2026
56 of 57 checks passed
@ramonjd ramonjd deleted the strip-css-for-non-edit-css-users branch April 17, 2026 05:05
@github-actions github-actions Bot added this to the Gutenberg 23.1 milestone Apr 17, 2026
@github-actions github-actions Bot removed the Backport to WP 7.0 Beta/RC Pull request that needs to be backported to the WordPress major release that's currently in beta label Apr 17, 2026
gutenbergplugin pushed a commit that referenced this pull request Apr 17, 2026
…it_css (#76650)

Co-authored-by: glendaviesnz <glendaviesnz@git.wordpress.org>
Co-authored-by: aaronrobertshaw <aaronrobertshaw@git.wordpress.org>
Co-authored-by: ramonjd <ramonopoly@git.wordpress.org>
Co-authored-by: dmsnell <dmsnell@git.wordpress.org>
Co-authored-by: sirreal <jonsurrell@git.wordpress.org>
@github-actions
Copy link
Copy Markdown

I just cherry-picked this PR to the wp/7.0 branch to get it included in the next release: 02b2545

@github-actions github-actions Bot added the Backported to WP Core Pull request that has been successfully merged into WP Core label Apr 17, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Backported to WP Core Pull request that has been successfully merged into WP Core [Package] Block editor /packages/block-editor [Type] Bug An existing feature does not function as intended

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants