Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Changes to theme.json #29891

Closed
oandregal opened this issue Mar 16, 2021 · 7 comments · Fixed by #30541
Closed

Changes to theme.json #29891

oandregal opened this issue Mar 16, 2021 · 7 comments · Fixed by #30541
Assignees
Labels
[Feature] Themes Questions or issues with incorporating or styling blocks in a theme. Global Styles Anything related to the broader Global Styles efforts, including Styles Engine and theme.json [Status] In Progress Tracking issues with work in progress

Comments

@oandregal
Copy link
Member

oandregal commented Mar 16, 2021

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.

@oandregal oandregal added [Feature] Themes Questions or issues with incorporating or styling blocks in a theme. Global Styles Anything related to the broader Global Styles efforts, including Styles Engine and theme.json labels Mar 16, 2021
@oandregal
Copy link
Member Author

cc @carolinan @aristath @kjellr @scruffian @MaggieCabrera @jasmussen FYI.

@aristath
Copy link
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. ?

@oandregal
Copy link
Member Author

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.

@oandregal
Copy link
Member Author

I've started to work on this.

@carolinan
Copy link
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?

@oandregal
Copy link
Member Author

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

@dogooddesignco
Copy link

dogooddesignco commented May 2, 2022

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
Labels
[Feature] Themes Questions or issues with incorporating or styling blocks in a theme. Global Styles Anything related to the broader Global Styles efforts, including Styles Engine and theme.json [Status] In Progress Tracking issues with work in progress
Projects
None yet
Development

Successfully merging a pull request may close this issue.

5 participants