How to Document theme.json Changes So the Next Theme Update Doesn’t Undo Them

theme.json is the central configuration file for block themes in WordPress. It controls global styles, presets, block settings, and the CSS custom properties that cascade through the entire front end. When a publishing team modifies this file—adjusting the color palette, enabling drop caps, or setting a custom content width—those changes live inside a file that ships with the theme. A theme update overwrites that file. The result is a silent regression: layout breaks, brand colors revert, and editorial controls disappear. The fix is not to avoid updates. The fix is a strict documentation protocol that captures every delta so the next update can be reapplied in minutes, not days.

Person writing documentation notes on a desk with a laptop and coffee
Documenting every theme.json change prevents silent regressions after updates.

Why theme.json Changes Vanish Without a Trace

WordPress 5.8 introduced theme.json as the single source of truth for block theme configuration. It replaced scattered PHP calls to add_theme_support() and inline CSS generation with a declarative JSON structure. The file sits in the theme root. When a theme author releases an update—whether it’s a security patch, a WordPress version compatibility fix, or a design refresh—the entire theme directory gets replaced. That includes theme.json. If a publishing team has edited the file directly, those edits are gone. There is no merge, no warning, and no rollback unless the team has a separate record of what was changed and why.

This is not a bug. It is the expected behavior of the WordPress theme update mechanism. The update process downloads the new theme package and extracts it over the existing directory. Any file that is not part of a child theme or a custom location is fair game for replacement. The only defense is a documentation system that treats theme.json modifications as configuration changes that must survive updates, similar to how a team would track changes to wp-config.php or a custom plugin.

What Actually Lives in theme.json

Before documenting changes, a team needs to understand the structure. The theme.json file has a specific schema defined by the WordPress core. The top-level sections are:

  • version: The API version, currently 2 for WordPress 5.8+.
  • settings: Controls what users can do in the editor—color palettes, gradients, font sizes, layout options, and block-specific controls.
  • styles: Sets default visual styles—typography, colors, spacing—that apply globally or to specific blocks.
  • customTemplates: Registers custom block templates.
  • templateParts: Registers template part areas.
  • patterns: Registers block patterns.

For a small-to-mid publishing team, the most common modifications happen in settings and styles. A team might add a brand color to the palette, disable custom font sizes to enforce editorial consistency, or set a wide content width that matches their ad layout. These are not cosmetic tweaks. They are functional constraints that affect how editors build pages. When they disappear after an update, the editorial workflow breaks.

The Core Problem: No Native Child-Theme Override for theme.json

WordPress supports child themes for overriding PHP templates and CSS. A child theme can also include a theme.json file, but the merging behavior is limited. The child theme’s theme.json is merged with the parent’s, but only for certain properties. Specifically, the settings and styles sections are merged, while customTemplates and templateParts are not. This means a team could theoretically put their customizations in a child theme’s theme.json and have them survive parent updates. In practice, this is fragile. The merge logic is not always intuitive. If the parent theme changes a setting that the child theme also defines, the child’s value wins—but only if the merge algorithm recognizes the property as mergeable. Some properties are replaced wholesale. The result is a configuration that may or may not survive an update, depending on what the parent theme changed.

For teams that cannot or will not use a child theme—perhaps because the theme is already a custom build and a child theme adds unnecessary complexity—the only reliable method is to document every change and reapply it after an update. This is not a workaround. It is the correct engineering practice for a file that is not under the team’s version control.

Step 1: Capture the Baseline

Before making any changes, export the current theme.json from the production theme. This is the baseline. Store it in the team’s documentation repository, not in the WordPress theme directory. A good practice is to keep a directory called docs/theme-config/ with the baseline file named theme.json.baseline. This file should never be edited. It exists solely as a reference to diff against.

If the team has already made changes and lost track of the original, download the theme’s original theme.json from the theme’s source—either the WordPress.org theme repository or the theme author’s release package. Do not rely on the current file in the production site. It may already contain undocumented changes.

Step 2: Create a Change Log That Survives

A change log for theme.json must be machine-readable enough to diff against the baseline, but human-readable enough that a developer can reapply changes without reverse-engineering intent. The format that works is a plain-text file with dated entries, each containing:

  • The date of the change.
  • The person who authorized it.
  • The exact JSON path affected (e.g., settings.color.palette).
  • The old value and the new value.
  • The business reason for the change.
  • A link to the related task or issue.

Example entry:

## 2025-01-14 — Jonas Venn
### Path: settings.color.palette
- Added "Brand Navy" (#0A1F3F) as the first palette entry.
- Reason: New brand guidelines require navy as the primary editorial accent.
- Issue: PROJ-421
### Path: settings.layout.contentSize
- Changed from 840px to 780px.
- Reason: Ad unit redesign reduced sidebar width; content area needed to shrink to maintain readability line length.
- Issue: PROJ-422

Store this file as theme-json-changelog.md in the same documentation directory. Every time someone edits theme.json, they must add an entry. This is not optional. If a change is not documented, it does not exist. The team lead reviews the changelog before approving any theme update.

Close-up of a notebook with handwritten configuration notes next to a keyboard
A dedicated changelog file captures the exact path, old value, new value, and reason for each modification.

Step 3: Use a Diff-Based Verification Script

Documentation is only as good as its accuracy. After a theme update, a developer must verify that the new theme.json matches the expected state. The manual method is to open the baseline, the changelog, and the current file side by side and visually scan. This fails. Humans miss things. The correct method is a diff script that programmatically compares the expected state against the actual state.

The expected state is the baseline plus all documented changes. A simple Node.js script can read the baseline, apply the changes from a structured changelog (JSON or YAML), and diff the result against the current theme.json. The script outputs a list of discrepancies. If the list is empty, the theme update preserved the customizations. If not, the team knows exactly what broke.

Here is a minimal example of the expected-state generation logic:

const fs = require('fs');
const baseline = JSON.parse(fs.readFileSync('theme.json.baseline'));
const changes = JSON.parse(fs.readFileSync('theme-json-changes.json'));

function applyChange(obj, path, value) {
  const keys = path.split('.');
  let current = obj;
  for (let i = 0; i < keys.length - 1; i++) {
    if (!current[keys[i]]) current[keys[i]] = {};
    current = current[keys[i]];
  }
  current[keys[keys.length - 1]] = value;
}

changes.forEach(change => applyChange(baseline, change.path, change.newValue));
fs.writeFileSync('expected-theme.json', JSON.stringify(baseline, null, 2));

Then diff the expected file against the actual theme’s theme.json using diff expected-theme.json wp-content/themes/your-theme/theme.json. This is not a suggestion. It is the minimum viable verification for a team that cannot afford regressions.

Step 4: Reapply Changes with a Script, Not by Hand

Once the diff reveals what was lost, reapplication should be automated. A second script reads the same structured changelog and writes the changes directly into the theme’s theme.json. This eliminates typos, missing commas, and incorrect nesting—the three most common failure modes of manual JSON editing.

The script must validate the resulting JSON against the WordPress theme.json schema before saving. The schema is available at https://schemas.wp.org/trunk/theme.json. Use a JSON Schema validator in the script. If the schema validation fails, the script aborts and reports the error. This prevents deploying a broken configuration to production.

For teams using a deployment pipeline, this reapplication script should run as part of the post-update hook. For teams doing manual updates, the script is run immediately after updating the theme and before clearing any caches.

Step 5: Lock Down Direct Editing

The most common source of lost changes is a well-meaning developer who edits theme.json directly on the server to fix a quick styling issue, then forgets to document it. The fix is to make the file read-only for everyone except a designated deployment user. On a Linux server:

chmod 444 wp-content/themes/your-theme/theme.json
chown deploy-user:deploy-group wp-content/themes/your-theme/theme.json

This does not prevent updates—the update process runs as the web server user or a deployment user that can override permissions—but it stops casual edits. If someone needs to change the file, they must go through the documentation and reapplication process. This is friction by design. Friction prevents silent data loss.

What to Do When the Theme Update Changes the Schema

Sometimes a theme update changes the structure of theme.json itself—renaming a key, moving a setting to a different path, or adding a new required property. The diff script will flag these as discrepancies, but they are not regressions. They are intentional changes by the theme author. The team must decide whether to adapt their customizations to the new structure or override the theme’s changes.

This decision requires a human. The script should output a clear report separating “missing customizations” from “structural changes.” The changelog should then be updated to reflect the new paths. For example, if the theme moved settings.color.palette to settings.color.paletteTheme, the changelog entry must be updated to the new path, and the reapplication script must target the new path. This is a maintenance task, not a one-time setup. Budget for it in every update cycle.

Developer comparing two code files side by side on dual monitors
A diff script separates intentional theme changes from lost customizations, making the update review process precise.

Why the Site Editor Is Not a Substitute

WordPress provides a Site Editor (Appearance → Editor) that allows users to modify global styles through a UI. Changes made there are stored in the database, not in theme.json. They survive theme updates. This seems like a simpler solution. It is not. Database-stored styles are opaque. They cannot be version-controlled, reviewed in a pull request, or deployed across environments. For a publishing team that maintains staging and production environments, database-stored styles are a synchronization nightmare. The theme.json file is the source of truth. The Site Editor is a prototyping tool. Treat it as such.

If a team member experiments with styles in the Site Editor and wants to promote them to the theme, the correct workflow is to export the styles using the “Export” option in the Site Editor, extract the relevant JSON, and add it to the documented changelog. Then clear the database-stored styles so they do not override the file-based configuration. This is a manual process. It is also the only process that ensures consistency across environments.

Integrating with Version Control

The documentation directory—containing the baseline, changelog, and scripts—should live in the team’s version control system. The theme’s theme.json should not. The theme is a third-party dependency. Version-controlling it creates merge conflicts and false confidence. Instead, version-control the configuration that the team owns: the changelog and the expected state.

When a theme update is released, the workflow is:

  1. Update the theme on a staging environment.
  2. Run the diff script to identify discrepancies.
  3. Review the report. Update the changelog if structural changes require path updates.
  4. Run the reapplication script to apply customizations.
  5. Validate the resulting theme.json against the schema.
  6. Test the site visually for regressions.
  7. Commit the updated changelog and expected state to version control.
  8. Deploy to production.

This is not a heavy process. It is a checklist that takes 15 minutes for a typical update. The alternative is hours of debugging why the site’s colors broke, followed by a frantic search through backup files. The choice is obvious.

Common Failure Modes and Their Fixes

Failure: The changelog is out of date

A developer made a change six months ago and forgot to document it. The diff script flags it as a discrepancy, but no one remembers why the change was made. Fix: The changelog must be updated at the time of the change, not retroactively. Enforce this with a pre-commit hook that checks if theme.json was modified and, if so, requires a corresponding changelog entry. This is a process problem, not a technical one.

Failure: The reapplication script overwrites theme improvements

The theme update added a new setting that the team wants to keep, but the reapplication script replaces the entire settings object with the team’s custom version. Fix: The reapplication script must merge changes at the property level, not replace entire sections. Use a deep merge function that preserves keys not present in the changelog. This requires careful implementation, but it is a one-time cost.

Failure: Schema validation fails after reapplication

The team’s customizations are valid JSON but violate the theme.json schema—for example, adding a property that the current API version does not support. Fix: The reapplication script must validate against the schema before saving. If validation fails, the script must report the specific error and the offending path. The team then decides whether to update the customization or override the schema check. Do not deploy a schema-invalid file. WordPress may silently ignore it, leading to unpredictable behavior.

FAQ

Can I just use a child theme’s theme.json to avoid this whole process?

You can, but the merge behavior is not fully reliable for all properties. The settings and styles sections merge, but customTemplates and templateParts do not. Additionally, if the parent theme changes a setting that your child theme also defines, the child’s value wins—but only if the merge algorithm recognizes the property as mergeable. Some properties are replaced wholesale. For teams that need deterministic control, a documented changelog and reapplication script is more predictable than relying on the child-theme merge.

What if I don’t have a developer to write the diff and reapplication scripts?

The manual alternative is to keep the changelog as a plain-text file and reapply changes by hand after each update. This is error-prone but still better than no documentation. The key is to have the changelog in a structured format that a developer can later use to automate the process. Start with the manual changelog. When the team grows, the scripts can be built from that existing data.

How often should I expect theme updates to break my customizations?

Every time the theme author releases an update that touches the same sections you have customized. If you only modify the color palette and the theme update does not change the color palette, your customizations will be lost but easily reapplied. If the theme update restructures the color palette—for example, moving it to a new path—you will need to update your changelog paths. The frequency depends on the theme’s release cadence and the scope of your customizations. Assume every update will require reapplication and budget accordingly.

Is there a way to get notified before a theme update overwrites my file?

WordPress does not provide a pre-update hook that allows you to inspect the incoming files. The only reliable method is to never update a theme directly on production. Always update on a staging environment first, run the diff script, and only then deploy to production. This is standard practice for any team that values stability. If you are updating themes on production without a staging environment, you have a larger problem than lost theme.json changes. See What to Fix First When a New WordPress Site Says Nothing Found for related environment setup considerations.

Next Steps for the Team

Start with the changelog. Create the docs/theme-config/ directory today. Export the current theme.json as the baseline. Write down every customization you know about, even if you have to reverse-engineer them from memory. Then make the changelog a required part of your development workflow. The scripts can come later. The documentation is the foundation. Without it, every theme update is a gamble. With it, updates become a routine maintenance task that takes minutes, not an emergency that breaks the site.

This article is part of a series on WordPress systems engineering for publishing teams. The next topic will cover how to manage block patterns across environments without duplicating content—a related configuration problem that shares the same root cause: treating the database as a configuration store when it should be a content store.