On Global Styles Saving and REST API endpoints #35141
Replies: 9 comments 5 replies
-
Hey, wanted to share a couple of clarifications. What is described here is only for the user data, like we do with the templates & template parts, that are stored as CPT in the same way.
Note this entity ID is used exclusively in the site editor, which is the only place in which we want to store the user data so far. In the front-end, things work this way: the stylesheet is created by querying the database and deserializing the user data before merging it with the core & theme data. |
Beta Was this translation helpful? Give feedback.
-
I also want to share that we already have an endpoint for settings ( |
Beta Was this translation helpful? Give feedback.
-
If we keep the CPT, can we avoid serialize/deserialize the JSON? In other words, can we store anything other than a string in the CPT? |
Beta Was this translation helpful? Give feedback.
-
I'm writing thoughts as I have them, sorry about the spam :) One other idea to consider is that the global styles sidebar (the mechanism the user interacts with to save its data) is now in the site editor. However, we might want to integrate it in other places (block editor, template editor, etc). What're the pros/cons of the current mechanism vs having a dedicated endpoint should we need to move the sidebar to a place other than the site editor? |
Beta Was this translation helpful? Give feedback.
-
I agree. I don't think there is an alternative data store that would be more compelling.
Agreed. The CPT should be seen as an implementation detail. Having a dedicated endpoint allows us to provide the best DUX.
I'm fine with this if that would significantly simplify the client implementation. However, I think the closest analogous endpoint we have right now is the themes endpoint which links to the active theme instead of having a |
Beta Was this translation helpful? Give feedback.
-
I just noticed as well that we use a variable called |
Beta Was this translation helpful? Give feedback.
-
While iterating on the Global Styles UI, I've noticed that the use-cases initially exposed above are not enough. We also need to fetch the "theme" and the "core" defaults without any user modifications. I've updated the description above to add these two under "questions". Let me know what you think? How should we solve this in a unified way? |
Beta Was this translation helpful? Give feedback.
-
Hi there! 👋 On mobile, we have plans in the near future to allow users to be able to update the global styles settings within the app, so this proposal of having an endpoint that returns and allows to update the global styles would be great. Currently, we use the block editor settings endpoint From that endpoint we use:
It would be great if we could have that included in this endpoint. |
Beta Was this translation helpful? Give feedback.
-
TL:DR; Theme.json definitely should be separated at least between settings & styles, and probably additionally between global and local scopes - even in a 4th level separation that handles "calculations" and returns static values to front-end facing global props and then in the backend code synchronized and unified behind the scenes. The past 3-4 weeks or so I've spent an ungodly amount of time trying to develop around theme.json in creating a custom theme - and I'd say a couple things have come out of it: The problem with #1 is it's just powerful enough where you think it could do just about anything, but is still too limited to really tap into the potential of being a kind of API intermediary between styles, settings, theming, user, core and theme settings/styles. 2.) Using theme.json for settings, styles and all of the above leads to a MASSIVE file. Used as intended as a connector and unifier of multiple systems, it frankly, becomes worse to use than just plain old using postCSS or Sass to separate out and containerize different concerns in CSS, or...just adding a couple small PHP files to keep things sane. 3.) The temptation as a developer is to use theme.json as a way of automating styling - such as type scaling and creating a systematic design 'grid' where spacing is consistent across elements. The problem here is you end up with TONS of custom properties in the body{} element that really have no purpose being there - and stacking relatively expensive calc() functions with custom props (as compared to their static values). What we really want as developers is to plop in a number and it automatically calculate out all of our spacing, change the colors, do all the things based on a single input. That's perfectly fine for a dev env, but when it comes to production it's a waste of resources. So in the end, to be effficient, you're still just using SASS, PostCSS or a calculator to get your variables anyway, then add user input ontop of it and most it ends up breaking - especially any color calculations through it - even if you break up colors based on HSL values to do calculations on L to say, automate a shade/tones palette, the minute a user enters a custom color to override a default the calculation no longer works because the values being broken up just act like any variable - overwriting the original value. That means you either have to have 12-18 different colors in your palette declared (all adding to the global scope) to have shaded colors for elements, or you have to code around it through a php or JS function that hooks the value back into the editor color palettes...and then does so without the benefit of the !important flags. Which leads to... 4.) Specificity issues trying to take a macro system (global props) and layer it on top of a micro system (component based blocks) that have been individually styled to work independently of other components, and you get weird specificity bugs with things like margins, or simply trying to universalize spacing in a theme - which means you have to crack open the custom CSS anyway and directly override the individual block values. For example, if I wanted to be a11y forward thinking and transfer margin-top, -bottom, etc properties to margin-block-start / margin-block-end to be automatically consistent in LTR / RTL / Vertical writing modes, then I've got to do a bunch of manual work because the only values I can input into theme.json is a value that gives the same padding/margin across TRBL properties. Ironically to best use theme.json and not worry so much about specificity and overrides and the like - the best solution I've found is to completely dequeue the block-library style sheets from rendering on the front end altogether, and then just not using spacing variables and being super conscious about what's scoped globally - because we can't get rid of the mandatory defaults for colors and things like that, you blink and you end up with mandatory code all loaded in. Here's an example of how unwiedly theme.json gets -> twentytwentytwo is still early in development and is already at 322 lines of JSON code in a single document - finding a single property in that is a nightmare for maintenance. Blockbase is at 597 lines. A theme I just started putting together today is already at 204 lines. The experience is like if I had to have everything in functions.php present all the time while I'm also working on a stylesheet - and still have to create separate functions.php and stylesheet files anyway. All of this is with only limited global variables that actually create CSS props to automate styling -> preset colors, font-family and fontsizes. We still have to go to custom to create a custom prop for say, line-height and then apply it individually to each value we want it on - which leads back to the using calc() and other things. Imagine over time as the scope expands to become truly global? A "perfect" seeming solution to theme.json from a styling perspective is to handle the logical global basic styles that'll be applied across all CSS classes as appropriate and/or create "design tokens" that can be duplicated and re-used again and again, and then be able to edit just about any attribute of a block or auto-generated CSS class from theme.json directly. For example, if I wanted to use margin-inline-start instead of margin-left, and set a margin-inline-start key instead of a margin-left key, it'd override the CSS value for margin-left by default on the block's CSS class. So in this way, you'd have the top-level global props that cover spacing, grid system scaling, modular scale, inheritance props, color, typography, specific property preferences (e.g. flex vs. grid or block-start vs -top), and then consequently be able to simply change the value of those properties in the block: {} settings - with a single property change. This is somewhat doable via custom settings right now, but you still have to apply them manually via CSS - so this implementation would also require universalizing and systematizing the CSS classes used across all the blocks (effectively making block CSS a "skeletal structure" that theme.json then can manipulate. Basically, I should be able to set a spacing system via theme.json and have it override properties like .has-background (which there was a somewhat solution put in the latest Gutenberg for - but misses p, h1, template block, etc elements/blocks). From a "settings" perspective, we'd basically want this to replace the need to really setup nearly anything via functions.php and leave it open to truly unique exceptions - the same as coding in CSS should be left for, very unique exceptions. add_theme_support replacement is great as a first step considering all the additions from the block editor (and one of the original motivations), but fundamentally, it can definitely have the power to handle things we'd otherwise handle via more complicated PHP classes and the like to re-use the same code again and again for (like add_theme_support originally, enqueueing new scripts/styles, adding new CPT's, enabling/disabling other features, version control, all the little things). So really, what we have is two unique systems that end up serving very different roles - and should be separated on the front end, but ultimately consolidated in the back end, similar to how WP_THEME_JSON and WP_THEME_RESOLVER already work to conslidate core, theme and user settings. Much of this is way out of scope of the discussion and more long-term thinking - obviously these things aren't going to happen overnight, but JSON serves as an incredibly powerful "intermediary" between systems - which was the whole reason theme.json became a thing to begin with. But, considering even with extremely basic 'global styling' and settings features we've already got obnoxiously huge to manage theme.json files as a theme developer - that ultimately, at this point, end up complicating things more than merely adding settings to a functions.php file or theme Class file to handle them on the settings side or just keep using SASS/postCSS or plain-ole overriding CSS via stylesheets anyway, it's a messy mix between "we're so close to the dream that the development stage can't progress fast enough and I'm so hyped" and "why did we do this again?" What we have is a point of entry into a REST API without having to actually code in get/set/put/delete requests or even understand how API's really work. That power should be leveraged.It's as if we're intercepting the API request in the middle of it being processed between systems and realistically, there are three core separations/files that would make a lot of sense:
Which even leads to a logical 4th -> a JSON file that solely handles calculations and then the other files simply take the static result and put those on the front end. There isn't a whole lot of reason outside of a handful of fluid responsive layout / typography settings that should require a browser recalculation everytime someone loads the page. While that wasn't the original intent - it's how it ends up being used because the developer wants convenience for future updates that the user probably won't touch - but ultimately really shouldn't be in a production environment - one at a time they aren't breaking-performance issues, but...as it matures and you have a singular theme.json file that's adding 1000 different props and calcs to a global scope, well, that's a nightmare - easy to say that that's on the theme developer / individual to manage, but reality is we should be smart about execution to set up a good environment. The over-use of root & body scoped CSS custom props isn't unique to theme.json - it's around everywhere, but it adds up, especially as sites get larger and individual elements being effected by them grow bigger. |
Beta Was this translation helpful? Give feedback.
-
Think of Global Styles as a customized override for the theme.json file of each theme. Currently it's being saved as a Custom Post Type . The reasoning for this is the possibility to leverage post type capabilities like revisions, scheduling... later.
Each theme gets assigned a new global styles record as a post and the "post_content" is used to store a serialized JSON of the user settings and styles.
On the editor side, the regular post entities endpoint is used to fetch and update the theme's global styles post record. (the object is JSON serialized/parsed there)
The entity ID used to retrieve and update the settings and styles is provided to the frontend using an editor setting during initialization.
I think this behavior was convenient during prototyping and implementation phase but now that we're getting closer to shipping it in WordPress 5.9. We should take a step a back and consider the best abstractions/endpoints... to use there.
Opinion
GET
orPUT
/global-styles/{ id }
(I'm not sure about whetherglobal-styles
is the best slug there)__experimentalGlobalStylesUserEntityId
setting to indicate which record to retrieve/edit, we could leverage something likeglobal-styles/active
endpoint (similar to/users/me
).Questions
/global-styles/theme/{theme}
global-styles/defaults
Notes
Right now global styles corresponds to both "settings" and "styles", I did wonder whether we should separate these two into two different endpoints but felt it's best to keep them together for now (like theme.json and the UI is also "merged").
What do you all think? What approach should we take?
cc @oandregal @jorgefilipecosta @TimothyBJacobs @mtias
Beta Was this translation helpful? Give feedback.
All reactions