Skip to content

Changes to theme.json #29891

Closed
Closed

Description

@oandregal

Part of #20331

@mtias @youknowriad @mcsf @nosolosw provided thoughts for this task.

As we approach the 5.8 cycle and the merge target for the theme.json API, it’s a good time to evaluate what is working and what needs some improvement. All in all, theme.json is responsible for providing configuration settings, global customization on things like text and links, and default style attributes for blocks. The first and last points seem to be fairly well established and their use fairly clear by themes, but the second point needs a bit more formalization.

The latest round of UI design iterations for the Global Styles sidebar puts a bit more emphasis on the style settings of cross-block elements. In light of this and the feedback gathered from themes so far there are a few aspects that can be improved if we clarify these three representations (settings, elements, blocks) a bit better.

To dive into this, let's explore an example of a theme.json that:

  • (settings) provides a default color palette and a different color palette for the heading block
  • (settings) disables the link color UI in the editor, except for the heading block
  • (styles) provides a general link color and a specific link color for the heading block
  • (styles) provides different font sizes for each heading configuration (h1-h6)
  • (styles) provides a font size for the quote block
  • (styles) provides background color and a different font size for links

With the current approach

{
 "settings": {
   "defaults": {
     "color": {
       "palette": [ /* default color palette */ ],
       "link": false
     }
   },
   "core/heading/h1": {
     "color": {
       "palette": [ /* heading color palette */ ],
       "link": true
     }
   },
   "core/heading/h2": {
     "color": {
       "palette": [ /* heading color palette */ ],
       "link": true
     }
   },
   "core/heading/h3": {
     "color": {
       "palette": [ /* heading color palette */ ],
       "link": true
     }
   },
   "core/heading/h4": {
     "color": {
       "palette": [ /* heading color palette */ ],
       "link": true
     }
   },
   "core/heading/h5": {
     "color": {
       "palette": [ /* heading color palette */ ],
       "link": true
     }
   },
   "core/heading/h6": {
     "color": {
       "palette": [ /* heading color palette */ ],
       "link": true
     }
   }
 },
 "styles": {
   "root": { // The "body" CSS selector.
     "color": {
       "link": "hotpink", // The "a" CSS selector within the body.
       "background": "value"
     }
   },
   "core/heading/h1": { // The "h1" selector.
     "color": {
       "link": "green",
       "text": "value"
     }
   },
   "core/heading/h2": { // The "h2" selector.
     "color": {
       "link": "green",
       "text": "value"
     }
   },
   "core/heading/h3": { // The "h3" selector.
     "color": {
       "link": "green",
       "text": "value"
     }
   },
   "core/heading/h4": { // The "h4" selector.
     "color": {
       "link": "green",
       "text": "value"
     }
   },
   "core/heading/h5": { // The "h5" selector.
     "color": {
       "link": "green",
       "text": "value"
     }
   },
   "core/heading/h6": { // The "h6" selector.
     "color": {
       "link": "green",
       "text": "value"
     }
   },
   "core/quote": { // The ".wp-block-quote" selector.
     "typography": {
       "fontSize": "value"
     }
   }
 }
}

Some of the struggles of the current approach are:

  • We currently have two mechanisms to target DOM elements of a block: core/heading/h1 to target H1 elements and styles.color.link to target a elements within the heading block.

  • With the current approach theme authors can only set the color of the links but not the rest of its style properties (text-decoration, border, background-color, etc).

  • For blocks that use block selectors (core/heading/h1, etc) there's no way to provide a style or setting for all the configurations of the same block (e.g.: presets for core/heading or a particular color style for all headings). theme.json spec: use block names for settings & block selectors for styles #29773

  • The current API for settings & styles promotes block-level APIs while themes have expressed the desire of being able to set things across blocks. An example we've noticed is that current themes with theme.json support use settings["defaults"] to target settings but not settings["core/heading/h1"] ― this is a hint about what are the primary and secondary use cases. See the latest round of mockups for the global styles sidebar as another case in which we want to provide an API to set styles across blocks.

  • The current "root" and "defaults" selectors have been reported to be confusing. As we allow composing theme.json objects further (for example, to change the settings for a “page” template or a template part) the presence of a nested “root” object becomes more strange.

Being able to target blocks and elements

The proposal formalizes what we have been aiming to do for Links but extends it to other elements. This makes it more clear that, in addition to blocks, themes and the global styles UI can target specific cross-block elements. Instead of using core/heading/h1 we can use h1 directly (independently from the heading block) and instead of using styles.color.link we can target a elements directly.

The idea is that these elements are the same that were shared in the mockups for the global styles sidebar. Initially, these elements are set by core but plugins/themes (or even users through the style variations mechanisms) could be able to register custom ones in the future.

{
 "settings": {
   "color": {
     "palette": [ /* default color palette */ ],
     "link": false
   },
   "blocks": {
     "core/heading": {
       "color": {
         "palette": [ /* heading color palette */ ],
         "link": true
       }
     }
   }
 },
 "styles": {
   "color": { // Target the document (body).
     "background": "value"
   },
   "elements": {
     "link": { // This is the "a" css selector.
       "color": {
         "text": "green",
         "background": "yellow" // NOT POSSIBLE BEFORE.
       },
       "typography": {
         "fontSize": "value" // NOT POSSIBLE BEFORE.
       }
     },
     "h1": { // This is the "h1" CSS selector.
       "typography": {
         "fontSize": "value"
       }
     },
     "h2": { // This is the "h2" CSS selector.
       "typography": {
         "fontSize": "value"
       }
     },
     "h3": { // This is the "h3" CSS selector.
       "typography": {
         "fontSize": "value"
       }
     }
     // ... and so on
   },
   "blocks": {
     "core/heading": { // This is the "h1, h2, h3, h4, h5, h6" CSS selector.
       "elements": {
         "link": {
           "color": {
             "text": "green"
           }
         }
       },
       "color": {
         "text": "value"
       }
     },
     "core/quote": { // This is the ".wp-block-quote" selector.
       "typography": {
         "fontSize": "value"
       }
     }
   }
 }
}

Note that:

  • The distinction between defaults and root is dropped: the settings & styles that lived within them are now top-level keys that target the document (settings => control the whole editor, styles => style the corresponding body/template part/etc).
  • Settings & styles can still address particular blocks, which are grouped under a blocks key (so it's clear that's a secondary API).
  • There's a new elements key in styles to target the elements suggested by the global styles sidebar mockups, including links or H1-H6 DOM tags.
  • elements can be nested within a particular block but a particular block can't be nested within another block.
  • There’s a more clear separation within the style group between the configuration of blocks and the configuration of elements that occur across blocks.

Updating the theme.json shape

While the theme.json file is still experimental the plan is to make changes in a way that the plugin can support the two versions for a couple of weeks (a release or two, depending on the schedule) to both give time to adapt and to allow comparisons. Ultimately, only the version that lands in core will be supported going forward.

Activity

  1. added
    [Feature] ThemesQuestions or issues with incorporating or styling blocks in a theme.
    Global StylesAnything related to the broader Global Styles efforts, including Styles Engine and theme.json
    on Mar 16, 2021
  2. oandregal commented on Mar 16, 2021

    @oandregal
    MemberAuthor
  3. aristath commented on Mar 17, 2021

    @aristath
    Member

    It feels like styles will now refer to selectors 🤔
    If that is the case, then this here is a bit confusing: "link": { // This is the "a" css selector.
    Why not do it like "a": { // This is the "a" css selector.?
    Would that not be more consistent with all the other things we have like "h1": { // This is the "h1" CSS selector. ?

  4. oandregal commented on Mar 17, 2021

    @oandregal
    MemberAuthor

    Ah, I see how some of those comments may be a bit misleading. Here's an attempt at clarification:

    • The serialization of an element to CSS is dependant on the context. This is to say that elements don't map to the same "thing" always: for example, the link element can be serialized as the a CSS selector in one block and to button in another block. It can also map to a CSS Custom Property --wp--style--link--color. It's going to depend on the context.

    • Elements can be seen as "pieces" that form the blocks. Their goal is to give semantics to something that's very messy. Once blocks declare these selectors, the mockups are really powerful: users are not setting the color of an a element, they are setting the color of "links" which every block decides how it's serialized to the global styles stylesheet.

    The details about this need to be fleshed-out in the PR that refactors theme.json with support for the link element. I hope it becomes more clear over there.

  5. oandregal commented on Mar 18, 2021

    @oandregal
    MemberAuthor

    I've started to work on this.

  6. self-assigned this
    on Mar 18, 2021
  7. carolinan commented on Mar 26, 2021

    @carolinan
    Contributor

    The separation of elements and blocks is clear. I do worry about the size of the file and how to keep it readable.

    So it is possible to both target H1, heading block H1 and Site title
    but not h1.sitetitle or a site title H1 block inside a header template area, or a post-author inside a query, correct?

  8. oandregal commented on Apr 28, 2021

    @oandregal
    MemberAuthor

    #30541 to implement this is at the latest stages (polishing, fixing some bugs).

  9. dogooddesignco commented on May 2, 2022

    @dogooddesignco

    This might be a different issue, I don't have much experience raising issues on github, but now when I use the "elements" object in theme.json, those settings are inlined in the editor styles, and then my custom editor styles are loaded after this, which overrides the settings in theme.json. For example, I have the following in my theme.json:
    `"elements": {

            "h1": {
    
                "typography": {
    
                    "fontSize": "var(--wp--custom--text-5-xl)",
    
                    "fontWeight": "bold",
    
                    "lineHeight": "1"
    
                },
    
                "spacing": {
    
                    "margin": {
    
                        "bottom": "var(--wp--custom--scale-4)"
    
                    }
    
                }
    
            },
    
            "h2": {
    
                "typography": {
    
                    "fontSize": "var(--wp--custom--text-4-xl)",
    
                    "fontWeight": "bold",
    
                    "lineHeight": "1"
    
                }
    
            }
    
        },`
    

    However editor stylesheet begins with a reset which sets all heading levels to font-size: inherit;
    So, in the editor my headings are all the base font size, since the reset overrides the styles from theme.json.
    However on the frontend, the order is reversed and the styles from the theme.json file take precedence (which is my desired behavior).

    There seems to be an inconsistency in the order in which these styles are loaded in the editor vs the frontend.

    Side-question: is it possible to still use the old method of targeting "core/heading/h1" in the "styles" object? When I try it, it has no effect.

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

Metadata

Metadata

Assignees

Labels

Global StylesAnything related to the broader Global Styles efforts, including Styles Engine and theme.json[Feature] ThemesQuestions or issues with incorporating or styling blocks in a theme.[Status] In ProgressTracking issues with work in progress

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions

    Sponsor
    SponsoredKunjungi sekarang
    Promo