To customize a block theme in WordPress 7.1 you have four places to put the change, and only one of them is the right answer for any given change. The Site Editor’s Styles panel is the fastest, and it is also the one that quietly overrides your theme’s theme.json forever afterwards — which is why so many developers edit theme.json, reload the front end, and see absolutely nothing happen.
That is not a caching problem and it is not a bug. It is the global styles cascade doing exactly what it is documented to do. Once you can see the four layers, picking where a change belongs stops being a matter of taste and becomes a two-second decision.
Who this is for
style.css and PHP template files, the child theme advice here still applies but the theme.json and Styles sections do not. Check which you have at Appearance: if you see Editor instead of Customize, you are on a block theme.The four layers, and why your change disappeared
WordPress builds the stylesheet for a block theme by merging several sources of the same theme.json data structure. The Theme Handbook lists them in order: WordPress defaults, parent theme, child theme, user customizations — and it is explicit that user customizations “can override theme.json, templates, and patterns”.
| Layer | Where it lives | Survives a theme update? | Who can change it |
|---|---|---|---|
| 1. WordPress defaults | Core’s own theme.json in wp-includes/ | Replaced on every core update | Nobody — don’t touch it |
| 2. Parent theme | wp-content/themes/your-theme/theme.json | No. Overwritten by the theme’s next release | You, if you own the theme |
| 3. Child theme | wp-content/themes/your-theme-child/theme.json | Yes | You |
| 4. User customizations | A wp_global_styles post in the database, written by the Site Editor | Yes — and it keeps winning over layers 1–3 | Any editor with access to the Site Editor |
Here is the sequence that catches people. Someone opens Appearance → Editor → Styles, nudges the body text colour, and hits Save. WordPress writes a wp_global_styles record for that theme containing that one property. Three weeks later you decide the body colour should be different, edit styles.color.text in theme.json, deploy it, and nothing changes — because layer 4 still has an opinion about that exact property and layer 4 wins.
It is property-level, not file-level, which is what makes it so confusing to debug. Your other theme.json changes apply fine. Only the handful of properties someone has ever touched in the Styles panel are frozen, and nothing in the interface tells you which ones.
Where to customize a block theme: four places, compared
Those four layers map onto four practical ways to make a change. On a narrow screen this table stacks into one card per option.
| Approach | Needs file access? | Version controllable | Overridden by | Best for | Where it hurts |
|---|---|---|---|---|---|
| Site Editor Styles | No | No — it is a database row | Nothing. It is the top layer | One-off colour and typography decisions on a site you alone manage | Invisible to your repo, blocks future theme.json edits, and no per-property reset |
Child theme theme.json | Yes | Yes | Site Editor Styles | Anything you want in Git, reviewed, and deployed — the default for client work | A second theme folder to maintain, and the child gets its own separate Styles record |
Style variation in /styles | Yes | Yes | Site Editor Styles | Offering two or three complete looks someone can switch between | Only usable if you control the theme folder; a parent-theme update wipes a variation you added to the parent |
| Additional CSS | No | No | Nothing — it loads last | The 5% a design system genuinely cannot express: a third-party widget, a print rule | Unbounded. It is where block themes go to become classic themes again |
The criteria I judged these on
Stating these up front so you can disagree with the weighting rather than the conclusion. These are the things that have actually gone wrong on sites I have had to fix.
Option 1: the Site Editor Styles panel
Go to Appearance → Editor, then click the half-shaded circle icon at the top right. You get panels for Typography, Colors, Layout, Background and Blocks. In WordPress 7.1 these also carry the new responsive controls, so you can set a different value for mobile and tablet without a media query — covered separately in how to use responsive styles in WordPress 7.1 without custom CSS.
This is genuinely the right choice in two situations: you are the only person who will ever touch the site’s design, or you are prototyping and want to see the change before you commit to it. It is fast, it is live, and it requires no deployment.
Two things to know before you save here
theme.json later” is a job, not a formality.Option 2: a child theme with its own theme.json
This is the answer for anything you want in version control, and for every site you do not personally own. A block child theme is smaller than a classic one — frequently just two files, because the Theme Handbook notes the style.css enqueue step is “often not needed for block themes because their style handling is generally done via theme.json“.
WP-CLI will scaffold the folder, though be aware it is written for classic themes and will give you a functions.php with a parent-stylesheet enqueue you probably want to delete:
wp scaffold child-theme bloqra-child --parent_theme=bloqra \
--theme_name="Bloqra Child" --activate
Or write the two files by hand. The Template header is the part that matters — it must be the parent’s directory name, not its display name:
/* wp-content/themes/bloqra-child/style.css */
/*
Theme Name: Bloqra Child
Template: bloqra
Version: 1.0.0
*/
Then the file that does the work. theme.json is on schema version 3, which has been current since WordPress 6.6, so put "version": 3 at the top and nothing else. Below is a child theme.json that overrides three things against the real preset slugs from the theme this site runs:
{
"$schema": "https://schemas.wp.org/trunk/theme.json",
"version": 3,
"settings": {
"color": {
"palette": [
{ "slug": "primary", "name": "Primary", "color": "#1F6FEB" },
{ "slug": "accent", "name": "Accent", "color": "#00D5BE" }
]
}
},
"styles": {
"typography": {
"fontFamily": "var:preset|font-family|serif",
"lineHeight": "1.7"
},
"blocks": {
"core/button": {
"border": { "radius": "4px" }
}
}
}
}
Two details in there are worth pulling out. Redeclaring a palette entry with the same slug as the parent’s replaces that colour everywhere it is used — every block already set to “Primary” follows along, which is the whole point of working in tokens rather than hex codes. And inside styles you reference presets with the var:preset|... syntax, not CSS var(); WordPress compiles it to var(--wp--preset--font-family--serif) for you.
To find the slugs your own theme actually defines, read its theme.json rather than guessing. The theme I run here exposes a nine-step primary ramp, a neutral ramp, seven spacing steps from 2-xs to 2-xl, and three font families — sans, serif, mono. Disclosure: I build and maintain Bloqra, the theme and blocks used on this site. Twenty Twenty-Five, bundled free with WordPress, is organised the same way and is a perfectly good place to learn this on — the mechanics in this article are core behaviour, not anything specific to one theme.
Templates work the same way: drop templates/single.html into the child and it replaces the parent’s. The Handbook is explicit that you can “overwrite any template, part, or pattern that exists in the parent theme”, with the caveat that a replacement pattern must keep the same registered Slug field.
Option 3: a style variation in /styles
A style variation is a JSON file in the theme’s /styles folder that offers a complete alternative look, selectable from the Styles panel. Each file needs a unique filename and sits at the theme root — your-theme/styles/latte.json in the Handbook’s example. The contents are a theme.json fragment plus a title:
/* wp-content/themes/bloqra-child/styles/high-contrast.json */
{
"$schema": "https://schemas.wp.org/trunk/theme.json",
"version": 3,
"title": "High Contrast",
"settings": {
"color": {
"palette": [
{ "slug": "primary", "name": "Primary", "color": "#000000" }
]
}
},
"styles": {
"color": { "background": "#FFFFFF", "text": "#111111" }
}
}
Use this when the real requirement is “give the client two looks to choose from”, not “change this one colour”. It is the only option in this article that hands a non-technical user a meaningful design switch without giving them the ability to break the type scale. Put it in the child theme, not the parent, for the same reason as everything else here.
Option 4: Additional CSS, and when it is defensible
Block themes did not abolish CSS. There are two places for it. Site-wide CSS lives behind the ellipsis menu in the header of the Styles panel — the location moved during the 6.x series, so if a tutorial tells you it is under the Customizer, that tutorial predates your WordPress. Per-block CSS is better: open Styles → Blocks, pick a block, and use the Additional block CSS field. You write declarations only, with no selector and no braces:
font-style: italic;
border-left-width: 4px;
WordPress scopes that to the block for you — entered on the Quote block it comes out as .wp-block-quote { font-style: italic; }. That scoping is why per-block CSS is almost always preferable to a site-wide rule: you cannot accidentally hit something three templates away.
Defensible uses: styling markup a third-party plugin outputs that no block controls reach; a @media print rule; a one-off fix with a ticket number in a comment above it. Not defensible: rebuilding your type scale, because every rule you add there is a rule the Styles panel no longer knows about and your next designer cannot find.
Diagnosing a theme.json edit that does nothing
Work through these in order. The first two cost thirty seconds and account for most cases.
- Check the JSON is valid. One trailing comma and WordPress silently ignores the entire file rather than erroring.
php -r 'var_dump(json_decode(file_get_contents("theme.json")));'returningNULLis your answer. - Check you are editing the active theme. With a child theme active, the parent’s
theme.jsonis still read, but any property the child also declares wins. Editing the parent’s copy of a property the child overrides does nothing, correctly. - Check whether a user global styles record exists.
wp_global_stylesis a private post type, so it never appears in the admin. From the shell:
# One row per theme that has ever been customized in the Site Editor
wp post list --post_type=wp_global_styles --post_status=publish \
--fields=ID,post_title,post_name,post_modified
A row whose post_name matches your active theme’s directory means layer 4 is in play. If that is the culprit, the supported fix is the Styles panel’s three-dot menu → Reset to defaults, after you have written down what was in there, because it clears the lot. Do that on staging first and test the site the way you would after a major update before repeating it on production.
Two more causes worth knowing. A full-page cache or a CDN will happily serve the old compiled stylesheet — clear both before you start doubting the cascade. And if the change still will not land after all of that, turn on logging and look for a JSON or theme error rather than guessing; enabling WordPress debugging and reading the error log safely walks through doing that without exposing notices to visitors.
So which one should you use?
- Your own blog, you are the only editor: Site Editor Styles. Genuinely. The version-control argument does not apply to a site with one person on it, and you will make the change in ten seconds.
- A client site, or anything with a staging environment: child theme with its own
theme.json, and tell the client not to use the Styles panel. Then actually check — a single saved property there will undo your next deployment in a way that looks like a caching bug. - You own the theme: change the parent’s
theme.jsonand ship a new version. The whole child-theme discussion exists because you cannot update someone else’s files; it does not apply to your own. - Two or three complete looks to choose between: style variations in the child theme’s
/stylesfolder. - No file access at all — managed host, no SFTP, no CLI: Styles panel plus per-block Additional CSS is your entire toolkit. Export a copy of what you set somewhere outside WordPress, because “Reset to defaults” is the only undo and it is total.
- A plugin’s markup you cannot reach with block controls: Additional block CSS, scoped as tightly as you can get it, with a comment saying why.
One habit worth adopting whichever you pick: write down where your design lives. “Colours and type in bloqra-child/theme.json; nothing in the Styles panel” is one line in a README and it saves the next person — frequently you, in eight months — an afternoon of confusion. If you are still choosing a theme, the ability to keep that line short is a reasonable thing to weigh; this checklist for choosing a WordPress theme covers the rest.
Frequently asked questions
Do I still need a child theme for a block theme?
Only if you need your changes in files rather than in the database. The Site Editor can override anything theme.json sets, so a child theme is no longer the only way to customize safely — it is the way to customize reviewably. For client work, team work, or anything with a deployment pipeline, that distinction is the whole argument. For a personal blog it often is not.
Why doesn’t my theme.json change show on the front end?
Most often because someone saved that same property in the Site Editor’s Styles panel, and user customizations sit above the theme in the cascade. Check for a wp_global_styles post for your active theme, clear any page cache, and confirm the JSON parses. A single syntax error makes WordPress ignore the whole file without complaint.
Does a block child theme need a functions.php?
Usually not. A style.css with a Template header pointing at the parent’s folder name, plus a theme.json, is a working block child theme. The Theme Handbook notes the parent-stylesheet enqueue is “often not needed for block themes”. Add a functions.php when you have PHP to run — it loads alongside the parent’s rather than replacing it.
Will activating a child theme keep my Site Editor customizations?
No. Global styles are stored per theme — WordPress looks up the global styles post for whichever theme is active — so switching to a child theme starts you from its theme.json with no user layer. Screenshot or note your Styles settings before you switch, then reproduce the ones you want in the child’s theme.json, which is where they should have been anyway.
What theme.json version should I use in 2026?
Version 3, declared as "version": 3. It has been the current schema since WordPress 6.6 and remains so on WordPress 7.1. Copying "version": 2 from an older tutorial still works but puts you on a schema with different defaults for things like defaultFontSizes, which produces exactly the sort of inherited-value confusion this article is about.
Can I stop clients using the Styles panel?
Access to the Site Editor follows the edit_theme_options capability, so an Editor-role user does not get it while an Administrator does. If the people writing content do not need it, giving them the Editor role rather than Administrator removes the problem without any custom code — and is worth doing for several other reasons too.
Is Additional CSS bad practice in a block theme?
In small, scoped doses, no — some things genuinely have no block control, and pretending otherwise produces worse workarounds. Prefer the per-block Additional block CSS field over site-wide CSS so WordPress scopes the rule for you. The failure mode is volume: once there are two hundred lines in there, your design has quietly moved out of the design system and back into a stylesheet nobody maintains.
Sources
- Child Themes — WordPress Theme Handbook, for the layer ordering and the block-theme enqueue and template-override notes
- theme.json Version 3 Reference — the current schema, for WordPress 6.6 and later
- Style variations — the
/stylesfolder convention and file shape - Styles overview — the Styles panel UI paths, Additional block CSS, and Reset to defaults
- WP_Theme_JSON_Resolver::get_user_global_styles_post_id() — confirms user styles are a
wp_global_stylespost looked up per active theme - WordPress 7.1 “Mary Lou” — responsive styles, custom breakpoints in
theme.json, and interactive styles - wp scaffold child-theme — WP-CLI command reference

Leave a Reply to This Post