Jeremy Felt

My first theme.json


I am not a “themer”, but I do manage my own theme for this site and I do work quite a bit on custom themes for a variety of clients. I spend a lot of time caring about markup used to organize content in an accessible and performant way. And I try to build pleasant editorial experiences for people who create and use their content every day.

I make great design decisions until I don’t, so I generally rely on others to handle the look and feel until it’s in a place where I can get picky about it.

I’m very interested in how the future of WordPress is being shaped by theme.json and block-based themes. This is my first actual attempt to sit down and write something from scratch, using my own site as a starting point.

Excuse the randomness of the notes in this post. I wrote most of this as observational blurbs while I worked and now I’m going back to edit and clarify.

I think the best place to get started is the Block Theme how-to guide on, so that’s where I started.

JSON Configuration

One of the things about using JSON as a configuration format is that there is no great way to leave comments.

One of the other things about JSON is no trailing commas.

And—using double quotes around every property name is slightly annoying.

Be warned. If you make a mistake in your theme.json file that results in invalid JSON, WP_Theme_JSON_Resolver::get_theme_data() will return an empty array of data rather than an error and you’ll be scratching your head as to why things aren’t showing up as expected.

I’m not sure I have a better answer for the configuration, but PHP would at least be somewhat more familiar, would support code comments, and has an easier time with conditional variations. That said, I imagine this will all be much more filterable one day.

Theme files

The first thing I did is create an empty index.html file to see what would happen. From what I can tell, you are no longer responsible for the <html> tag, which I think is good. It’s so much nicer to hook and unhook things on wp_head.

An index.php file is still required, but only for activation. If you remove the index.php file and visit the site on the front-end, everything works. If you go to Appearance -> Themes while the file is removed, your theme will deactivate because it is invalid. Hopefully we can remove this requirement in the future for files that are theme.json based, if only so cruft isn’t required in a repository.

That said, we generally have a pattern already of empty index.php files in wp-content/, wp-content/themes/, etc… So, no big deal.

A functions.php file is not technically required, but I had to add a surprising amount of code. Most of it is hacky stuff that I’ll explain further on, but I’m very surprised I needed to enqueue a stylesheet and declare theme support for a handful of things.

I imagine this stuff will all be part of theme.json in the future, or already is and I missed the documentation.

Template parts

Okay, this is powerful stuff and I’m generally excited about it. I like the idea of someone building out a bunch of templates for a new theme and then handing them to me as a developer to dial in as needed.

There may be some snark in some of my comments because it’s all very unknown to me. We’ll see how this goes. 🙂

I started off by loading a header.html template part in my index.html file.

In that header.html file, I added a site title block and a navigation block and then opened the site editor in WordPress.

Super cool! There’s my site title and navigation block, asking me to choose one of my existing menus.

I choose the menu, save the site, and… now my header.html is overridden by the one stored in the database and I can no longer make changes directly to the theme until I clear customizations through a confusing process and/or delete the template part that was saved. 😞

Suggestion: It would be great if you could choose a mode in which template changes are saved directly to their original theme file rather than the database.

I may be missing something, but my initial reaction is that this completely changes how theme authors will need to approach themes. If an update to markup is made after the first version, there may be no way to guarantee that the update reaches the front-end of a site unless the site owner knows to clear custom changes. This comment on the Gutenberg repository sums up the problem very well.

Back to the navigation block. Once I choose an existing menu, those menu items are inserted as individual navigation links rather than a connection to the menu itself. I believe this means that menus as we know them—a stored entity—are over. This is probably an okay change, but I think it requires a completely new approach to some stuff that we’re used to doing in themes.

Overall lesson: Be very specific about your template parts. If the header has navigation, make a navigation template. If the navigation template part requires more than one block in it, make two more template parts and include them.

Secondary lesson: Approaches will differ widely for people building their own themes, building themes to distribute, and building themes for clients they support.


Questions: How do translations work in block template parts that are included as part of a theme? It seems like we might be taking a step backwards here? Or were translations never that big on the front-end of themes to begin with?


Every front-end page now has a <div class="wp-site-blocks"> wrapper inside the <body> tag. It’s not the worst, but it also seems like unnecessary markup for many sites. I opened an issue to suggest that it be filterable.

It doesn’t seem possible to output any other attribute beyond class on a template part wrapper. This may be a bummer when a data- attribute or id would be useful.

It also does not seem possible to use something like "tagName":false to skip outputting a wrapping tag completely. This leads to unnecessary (or unmanageable) markup around every template part.

One thing that I let get under my skin sometimes is extra markup. 🙂

I submitted a quick pull request to stop duplicate <title> and <meta name="viewport"> tags from being output. I didn’t think that through enough and need to update it to support earlier versions of WordPress. I’ll revisit it soon!

The query pagination block outputs an empty pagination container when no pagination exists. A pull request is open to resolve this.


I like the concept of features like gradients making it easier for people to create fun front-end experiences on their sites.

I don’t like how much work I have to do to not output gobs of color presets on every page view for a site that doesn’t use those gradients. I imagine this will get better as time goes on, but so much unnecessary CSS is loaded by default for the block library already. It’s been unfortunate.

It’d be great if I could specify "coreGradients":false in my theme.json and have all of that default CSS disappear.

Along those lines: Why is duotone baked into core? It’s a fun feature, but it also seems like great plugin material. Or something that should be part of the pattern directory.


I would like WordPress or Gutenberg or the combination of the two to commit to just replacing the entire admin menu.

It’s annoying to have a new navigation on the side triggered by the site icon when you’re in the site editor, but then to have to click “Back” and “Dashboard” to get to the dashboard—where the menu changes completely! There’s no way this a good experience for somebody learning how to use WordPress the first time.

I’d rather see backwards compatibility shattered here and a completely new admin menu shipped. (Look at the code behind the current admin menu and you may agree!) 😅


It’s very strange to poke around at a piece of software that you have used daily for near 16 years and be lost and confused about what you’re actually doing.

I’m starting to grasp what various pieces do and I’m sure I’ll learn the language. I already feel much more confident after playing with things for a couple days and sleeping on it for a few more.

I hope that the experience for new users is better without the baggage of the past. I can visualize some exciting possibilities for block-based sites.

One takeaway that I probably haven’t clarified out loud before: I find myself wishing Gutenberg was pitched as a WordPress replacement and that legacy WordPress was retired. Or that we spent some time separating WordPress into parts we liked and parts we didn’t before joining them back together again when Gutenberg was ready.

The ship of Theseus is a fun thought experiment, but sometimes it feels like rivets are popping off everywhere while the ship keeps expanding under the old shell.

But! That ship has sailed (har har) and I do realize I haven’t been showing up to comment on decisions, so please take all of this as delayed feedback “from the mouth of an understanding and friendly backseat driver.” ❤️

Responses and reactions


Leave a Reply

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

The only requirement for your mention to be recognized is a link to this post in your post's content. You can update or delete your post and then re-submit the URL in the form to update or remove your response from this page.

Learn more about Webmentions.