theme.json Block Theme Guide: Where add_theme_support Went

Where add_theme_support went in block themes: the theme.json v3 settings that replace it, the layers that override your file, and what stays in PHP.

If you built classic themes, your functions.php probably opened with a block of add_theme_support() calls: a color palette, font sizes, wide alignment, custom spacing. In a block theme you go looking for that block and it is not there.

The short answer: in a block theme, most of those editor-facing add_theme_support() calls are replaced by keys in a theme.json file at the theme root. The palette becomes settings.color.palette, font sizes become settings.typography.fontSizes, align-wide and friends become settings.appearanceTools and layout settings, and front-end styling moves into the styles section. functions.php still exists and still runs; it just stops being where the design system lives.

This guide is written against theme.json version 3, which the WordPress block editor handbook’s theme.json Version 3 reference (read 2026-09-11) says works with WordPress 6.6 or later. The current WordPress release is 7.1, released 2026-08-19, per the WordPress releases page read the same day. theme.json changes between major versions, so check that reference before relying on any key here.

The old function, the new key

The handbook’s Global Settings and Styles guide (read 2026-09-11) publishes an equivalence table. The rows most classic-theme developers need:

Classic add_theme_support()theme.json version 3 setting
editor-color-paletteprovide a list via color.palette
editor-gradient-presetsprovide a list via color.gradients
disable-custom-colorsset color.custom to false
disable-custom-gradientsset color.customGradient to false
editor-font-sizesprovide a list via typography.fontSizes
disable-custom-font-sizesset typography.customFontSize to false
custom-line-heightset typography.lineHeight to true
custom-spacingset spacing.padding to true
custom-unitsprovide a list via spacing.units
editor-spacing-sizesprovide a list via spacing.spacingSizes
link-colorset color.link to true
borderset border properties to true
appearance-toolsset appearanceTools to true

All of those sit under the top-level settings object.

The table answers “where did it go.” It does not answer “what else changed,” which is the part that actually costs time.

A minimal version 3 file

The top-level properties listed in the version 3 reference are settings, styles, customTemplates, templateParts and patterns, alongside version and $schema. A starting file, composed from the documented keys:

{
	"$schema": "https://schemas.wp.org/trunk/theme.json",
	"version": 3,
	"settings": {
		"appearanceTools": true,
		"color": {
			"custom": false,
			"defaultPalette": false,
			"palette": [
				{ "slug": "brand", "color": "#1d4ed8", "name": "Brand" },
				{ "slug": "ink", "color": "#111827", "name": "Ink" }
			]
		},
		"layout": {
			"contentSize": "720px",
			"wideSize": "1200px"
		},
		"typography": {
			"fontSizes": [
				{ "slug": "small", "size": "0.875rem", "name": "Small" },
				{ "slug": "large", "size": "1.5rem", "name": "Large" }
			]
		}
	},
	"styles": {}
}

Reading it against the reference:

  • appearanceTools turns on a bundle of editor controls at once. The reference lists background image and size, border properties, link and heading and button color options, dimensions, sticky positioning, spacing and line height.
  • color.custom: false removes the free color picker so editors stay on your palette. color.defaultPalette: false hides WordPress’s own default colors.
  • layout.contentSize “Sets the max-width of the content” and layout.wideSize “Sets the max-width of wide (.alignwide) content.” These two replace a lot of hand-written container CSS.
  • typography.fontSizes populates the font size selector.

The $schema line is not decoration. Point your editor at it and you get autocomplete and validation for every key, which catches the typos that otherwise fail silently.

Note one inconsistency in the documentation itself. The Themes Handbook’s introduction to theme.json (read 2026-09-11) still shows "version": 2 in its skeleton, while the block editor handbook’s guide and reference use version 3, introduced in WordPress 6.6. Write new files as version 3.

Settings versus styles

This split is the mental model shift.

settings decides what editors are allowed to choose. Palettes, size presets, which controls appear, layout widths. It is configuration of the editor and of the presets.

styles decides what things look like by default. Colors, typography and spacing applied to the site root, to elements such as links and headings, and to individual blocks.

In a classic theme both jobs lived in CSS and PHP, often tangled. In a block theme you declare the options in settings, then use them in styles, and WordPress generates the CSS. Presets become CSS custom properties, so a palette entry with the slug brand is usable in your own stylesheet as var(--wp--preset--color--brand).

The layers that override your file

This is the section most tutorials skip, and it explains the most common “theme.json does nothing” report.

Your theme.json is not the only source of settings and styles. WordPress has its own core defaults underneath it. And on top of it sits the user layer: the Global Settings and Styles guide notes that “Users, via the site editor, will also be able to override theme’s or core’s preferences.” The Themes Handbook’s child themes page (read 2026-09-11) describes user customizations as an additional override layer that stores changes in the database instead of the filesystem.

If anyone has saved a change in the Site Editor’s Styles panel, that saved value can win over what your theme.json says, and editing the file will appear to do nothing. The file is being read. It is being outvoted.

Before you debug the JSON, check whether the site has saved global style customizations. On a development site, resetting those customizations in the Site Editor tells you quickly whether the file or the database is in charge. On a client’s production site, do not reset anything without asking: those customizations are their work.

The other silent failure is invalid JSON. A trailing comma or a missing quote and the whole file is not applied, without an error on the page. Validate against the schema first. For the general method of hunting bugs that produce no error, see debugging code that runs but gives the wrong result.

What stays in functions.php

theme.json took over the design system. It did not take over behavior. A block theme’s functions.php still loads and still runs, and it is still where you:

  • enqueue scripts and any stylesheet that theme.json cannot express,
  • register block patterns, block styles and custom blocks,
  • add hooks and filters that change behavior rather than appearance,
  • keep anything that is logic rather than configuration.

The timing rules are the same as they always were. Theme setup code belongs on after_setup_theme, and asset loading on the enqueue hooks. Where those sit in a request is covered in the WordPress execution order.

Templates changed shape too. Block themes use HTML block templates, and the customTemplates and templateParts keys in theme.json describe them. The PHP template files of a classic theme are not how a block theme’s layout is built.

Classic themes can use theme.json too

theme.json is not only for block themes. The handbook’s Theme Support guide (read 2026-09-11) repeatedly refers to “block themes or themes providing a theme.json file”, meaning a classic theme can add a theme.json to control editor settings while keeping its PHP templates.

One compatibility note from that guide is worth knowing before you mix approaches: for themes that provide theme.json, it is “not recommended” to use the wp-block-styles theme support. Put block styling in theme.json instead, so global styles and block styles do not fight.

If you are migrating, a sensible order is: add theme.json with settings only, confirm the editor shows the right palette and sizes, then move visual defaults into styles a section at a time, deleting the equivalent add_theme_support() calls and CSS as you go.

When something still looks wrong

theme.json problems rarely produce a PHP error, but the PHP around them can. If a pattern registration or an enqueue in functions.php fails, log it quietly rather than printing errors to visitors, as described in logging WordPress errors without displaying them. Then work through the layers in order: is the JSON valid, is the key in the right place for version 3, is a user customization overriding it, and is a plugin adding its own styles on top.

FAQ

Where did add_theme_support go in block themes? Most editor-related supports moved into theme.json under settings. For example, editor-color-palette becomes color.palette, editor-font-sizes becomes typography.fontSizes, and appearance-tools becomes appearanceTools: true, per the WordPress Global Settings and Styles guide read 2026-09-11.

Which theme.json version should I use? Version 3, which the WordPress block editor reference says works with WordPress 6.6 or later. Some older handbook pages still show version 2 in examples.

Why do my theme.json changes have no effect? The two usual causes are invalid JSON, which stops the file being applied, and saved user customizations from the Site Editor, which sit in the database as a layer above the theme and can override it.

Do block themes still need functions.php? Yes, for behavior: enqueues, block pattern and block style registration, hooks and filters. theme.json replaces the design configuration, not the logic.

Written by

Shah Alom

Shah Alom is the founder and writer behind Ebuhu, where he covers PHP, WordPress development, plugin and theme development, debugging, practical programming techniques, and AI-assisted coding. Drawing on hands-on web development experience, he focuses on clear, practical guidance that helps developers understand how things work, avoid common mistakes, and write more reliable code.

Leave a Reply

Your email address will not be published. Required fields are marked *