[wp-trac] [WordPress Trac] #64418: Valid CSS is causing failure in the Additional CSS panel

WordPress Trac noreply at wordpress.org
Tue Dec 23 12:17:13 UTC 2025


#64418: Valid CSS is causing failure in the Additional CSS panel
--------------------------+-------------------------
 Reporter:  drw158        |       Owner:  jonsurrell
     Type:  defect (bug)  |      Status:  assigned
 Priority:  normal        |   Milestone:  7.0
Component:  Customize     |     Version:  4.7
 Severity:  normal        |  Resolution:
 Keywords:  has-patch     |     Focuses:  css
--------------------------+-------------------------

Comment (by jonsurrell):

 Replying to [comment:16 westonruter]:
 > I believe we need a workaround similar to what was done in
 `WP_Customize_Manager::save_changeset_post()` for storing Customizer
 changesets (the `customize_changeset` CPT) where it wraps the call to
 `wp_update_post()` as follows…

 I think you're right. These default filters on post content are all
 intended to run on HTML and are unsuitable for other content types like
 CSS (even if it's CSS intended for a `<style>` element).

 I have concerns because global styles stores JSON with a bunch of fields
 and I'm not familiar with the entire structure and how it's used or may be
 used in the future.

 Below is an example of a `wp_global_styles` post type. This all appears to
 be intended for use inside of CSS, but it's not a single CSS text. It's
 parts of CSS that's going to be stitched together in some way. That makes
 it very difficult to reason about what's actually safe in here until we
 rely on things like the HTML API for constructing STYLE tags where we can
 be confident that the CSS text is correctly prepared (escaped) for an HTML
 STYLE tag.

 {{{#!json
 {
   "styles": {
     "css": "@property --animate {\n  syntax: \"<custom-ident>\";\n
 inherits: true;\n  initial-value: false;\n}\n at property --base-animation-
 duration {\n  syntax: \"<time>\";\n  inherits: true;\n  initial-value:
 300ms;\n}\n at keyframes marquee {\n  0% {\n    transform: rotate(-10deg)
 scale(0.9);\n  }\n  100% {\n    transform: rotate(12deg) scale(1.2);\n
 }\n}\nmain {\n  h1,\n  h2,\n  h3,\n  h4,\n  h5,\n  h6 {\n    --animate:
 marquee;\n    position: relative;\n\n    &::after {\n      color: red;\n
 display: inline-block;\n      animation: var(--animate) 600ms linear
 infinite alternate;\n    }\n  }\n\n  h1 {\n    counter-increment:
 heading-1;\n    counter-reset: heading-2 heading-3 heading-4 heading-5
 heading-6;\n    &::after {\n      content: \"<h1> \" counter(heading-1);\n
 animation-duration: calc(var(--base-animation-duration) * 2);\n    }\n
 }\n  h2 {\n    counter-increment: heading-2;\n    counter-reset: heading-3
 heading-4 heading-5 heading-6;\n    &::after {\n      content: \"<h2> \"
 counter(heading-1) \".\" counter(heading-2);\n      animation-duration:
 calc(var(--base-animation-duration) * 3);\n    }\n  }\n  h3 {\n
 counter-increment: heading-3;\n    counter-reset: heading-4 heading-5
 heading-6;\n    &::after {\n      content: \"<h3> \" counter(heading-1)
 \".\" counter(heading-2) \".\"\n        counter(heading-3);\n
 animation-duration: calc(var(--base-animation-duration) * 5);\n    }\n
 }\n  h4 {\n    counter-increment: heading-4;\n    counter-reset: heading-5
 heading-6;\n    &::after {\n      content: \"<h4> \" counter(heading-1)
 \".\" counter(heading-2) \".\"\n        counter(heading-3) \".\"
 counter(heading-4);\n      animation-duration: calc(var(--base-animation-
 duration) * 7);\n    }\n  }\n\n  h5 {\n    counter-increment: heading-5;\n
 counter-reset: heading-6;\n    &::after {\n      content: \"<h5> \"
 counter(heading-1) \".\" counter(heading-2) \".\"\n
 counter(heading-3) \".\" counter(heading-4) \".\" counter(heading-5);\n
 animation-duration: calc(var(--base-animation-duration) * 11);\n    }\n
 }\n\n  h6 {\n    counter-increment: heading-6;\n    &::after {\n
 content: \"<h6> \" counter(heading-1) \".\" counter(heading-2) \".\"\n
 counter(heading-3) \".\" counter(heading-4) \".\" counter(heading-5)
 \".\"\n        counter(heading-6);\n      animation-duration: calc(var
 (--base-animation-duration) * 13);\n    }\n  }\n}",
     "blocks": {
       "core/paragraph": {
         "css": "content: \"<script>alert(1);</script>\""
       },
       "core/site-title": {
         "typography": {
           "fontFamily": "var(--wp--preset--font-family--beiruti)",
           "fontWeight": "600",
           "letterSpacing": "2.4px",
           "textTransform": "uppercase"
         }
       }
     },
     "color": {
       "background": "var(--wp--preset--color--accent-5)"
     },
     "elements": {
       "h4": {
         "typography": {
           "fontSize": "var(--wp--preset--font-size--large)"
         }
       },
       "heading": {
         "typography": {
           "fontFamily": "var(--wp--preset--font-family--beiruti)",
           "fontWeight": "500",
           "letterSpacing": "-0.02em",
           "lineHeight": "1.02"
         }
       }
     },
     "typography": {
       "fontFamily": "var(--wp--preset--font-family--literata)",
       "fontSize": "var(--wp--preset--font-size--medium)",
       "letterSpacing": "-0.01em",
       "lineHeight": "1.6"
     }
   },
   "settings": {
     "color": {
       "palette": {
         "theme": [
           {
             "color": "#FFFFFF",
             "name": "Base",
             "slug": "base"
           },
           {
             "color": "color-mix(in srgb, currentColor 20%, transparent)",
             "name": "Accent 6",
             "slug": "accent-6"
           }
         ]
       }
     },
     "typography": {
       "fontFamilies": {
         "theme": [
           {
             "name": "Beiruti",
             "slug": "beiruti",
             "fontFamily": "Beiruti, sans-serif",
             "fontFace": [
               {
                 "fontFamily": "Beiruti",
                 "fontStyle": "normal",
                 "fontWeight": "200 900",
                 "src": [
                   "file:./assets/fonts/beiruti/Beiruti-
 VariableFont_wght.woff2"
                 ]
               }
             ]
           }
         ]
       },
       "fontSizes": {
         "theme": [
           {
             "fluid": {
               "max": "2.8rem",
               "min": "2rem"
             },
             "name": "Extra Extra Large",
             "size": "2rem",
             "slug": "xx-large"
           }
         ]
       }
     }
   },
   "isGlobalStylesUserThemeJSON": true,
   "version": 3
 }
 }}}

-- 
Ticket URL: <https://core.trac.wordpress.org/ticket/64418#comment:18>
WordPress Trac <https://core.trac.wordpress.org/>
WordPress publishing platform


More information about the wp-trac mailing list