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 template defaults. When you modify it directly inside a parent theme, the next update will overwrite every change. The fix is not to avoid updates. The fix is a documentation and override system that survives the update cycle. This article covers the exact failure modes, the file hierarchy that governs resolution, and a documentation method that keeps your customizations intact and traceable.

Close-up of a developer editing a JSON configuration file on a laptop

Why Direct theme.json Edits Are a Time Bomb

Small-to-mid publishing teams often run a lean stack: a parent block theme, a child theme for CSS tweaks, and maybe a custom plugin for shortcodes. When a designer or developer adjusts global typography, color palettes, or block spacing, the fastest path is to open the parent theme’s theme.json and change the values. It works immediately. It also guarantees that the next automatic or manual theme update will flatten those changes. I have seen teams lose hours of layout work because a minor theme update reset the font ramp, broke the content width, or reintroduced a deprecated color palette. The core issue is not the update itself. The issue is the absence of a documented override layer that survives the parent theme’s version bump.

WordPress resolves theme.json settings through a merge process. The parent theme’s file is read first, then any child theme’s theme.json is merged on top. User customizations saved via the Site Editor are stored in the database and take highest priority. If you edit the parent file directly, you are working at the lowest priority level. The next update replaces that file entirely. Your changes vanish. The only durable approach is to move every customization into a child theme’s theme.json or into the database, and to document what you moved and why.

How WordPress Resolves theme.json: The Merge Order

Understanding the resolution order prevents you from fighting the system. WordPress core defines default settings. The active theme’s theme.json overrides those defaults. A child theme’s theme.json overrides the parent. Finally, user customizations stored in the wp_global_styles post override everything. This cascade means you can selectively override individual properties without duplicating the entire file. The problem is that most teams do not know which properties they have overridden, because they never recorded the original values or the rationale.

The merge is not a simple deep merge. WordPress uses a specific algorithm that handles settings and styles differently. For settings, arrays are merged recursively. For styles, the child or user values replace the parent values entirely for each top-level key. If you override styles.blocks.core/paragraph.typography.fontSize in a child theme, you must include the full path. A partial override can unintentionally drop other style properties. This is a common source of silent breakage after updates.

What Breaks After an Update: Real Failure Modes

I have catalogued the most frequent casualties of undocumented theme.json edits. Each one is preventable with a child theme override and a single documentation entry.

Color Palette Reset

You define a brand palette in the parent theme’s settings.color.palette. The update ships a new default palette. Your custom colors disappear from the editor. The front end falls back to CSS custom properties that no longer match. The fix is to copy your palette into the child theme’s theme.json under the same path. Document the hex values and the design tokens they map to.

Typography Preset Collapse

You adjust font sizes, fluid typography ranges, or font families. The update restores the theme’s original presets. Headings revert to the wrong scale. Line heights break. The fix is to override only the changed presets in the child theme. Do not copy the entire typography section. That creates a maintenance burden when the parent adds new presets. Document each overridden preset with the before and after values.

Block Gap and Layout Widths

You change settings.layout.contentSize or wideSize. The update resets them. Your content area snaps back to the theme default. Alignwide blocks overflow or shrink. The fix is a child theme override. Document the pixel values and the design decision behind them.

Custom Block Settings

You enable or disable block supports like duotone, spacing, or border controls. The update reverts them. Editors lose controls they relied on. The fix is to explicitly set the desired supports in the child theme. Document which blocks were changed and why.

Developer comparing two versions of a configuration file on a split screen

The Documentation Method That Survives Updates

Documentation is not a README file that nobody reads. It is a structured changelog tied to the child theme’s theme.json that makes every override auditable. I use a single Markdown file named THEME_JSON_OVERRIDES.md stored in the child theme root. It contains three sections: Active Overrides, Resolved Overrides, and Merge Conflict Notes.

Active Overrides

Each entry records the JSON path, the parent theme’s original value, the child theme’s override value, the date, and the reason. Example:

Path: settings.color.palette
Parent value: [default theme palette]
Child value: [brand palette with 5 custom colors]
Date: 2025-01-15
Reason: Brand alignment. Parent palette uses generic colors.

This format forces you to look up the parent value before overriding. That lookup alone prevents many unnecessary overrides. When the parent theme updates, you diff the new parent theme.json against your documentation. If the parent’s value for a path has not changed, your override is still safe. If it has changed, you have a documented starting point for the merge.

Resolved Overrides

When a parent update incorporates a change you previously overrode, move the entry to the Resolved section. Note the parent version that resolved it. This keeps the Active list clean and shows the history of your relationship with the upstream theme.

Merge Conflict Notes

When a parent update changes a value you also override, you have a conflict. Record the parent’s new value, your current override, and the decision you made. Did you keep your override? Adopt the parent’s new value? Create a hybrid? This section is your audit trail for future theme updates.

Child Theme theme.json: Structure and Scope

Your child theme’s theme.json should contain only the properties you are overriding. Do not copy the entire parent file. A minimal child theme.json looks like this:

{
  "version": 2,
  "settings": {
    "color": {
      "palette": [
        {
          "slug": "brand-blue",
          "color": "#1a3b5c",
          "name": "Brand Blue"
        }
      ]
    },
    "layout": {
      "contentSize": "720px"
    }
  },
  "styles": {
    "typography": {
      "fontSize": "18px"
    }
  }
}

This file overrides the color palette, the content width, and the base font size. Everything else inherits from the parent. When the parent updates, only these three overrides need review. The documentation file tells you why each exists.

Version Control Is Not Documentation

Git tells you what changed. It does not tell you why. A diff of theme.json shows a line was added or removed. It does not capture the design decision, the stakeholder request, or the upstream dependency. Your documentation file fills that gap. Commit it alongside the child theme’s theme.json. The two files together form a complete record.

Handling User Customizations from the Site Editor

Editors with administrator access can modify global styles through the Site Editor. Those changes are stored in the database as a custom post type. They survive theme updates because they are not file-based. The problem is they are invisible to version control and to anyone who does not know to look for them. A theme update can introduce a conflict between the database styles and the new parent styles. The result is unpredictable.

I recommend a policy: no user customizations via the Site Editor for global styles. Lock it down with remove_theme_support( 'appearance-tools' ) if your team does not need the interface. If you must allow it, document every saved customization in the same THEME_JSON_OVERRIDES.md file under a “Database Overrides” section. Export the current global styles with wp global-styles export and store the JSON in the repository. This gives you a snapshot to diff against after updates.

Automating the Diff Before Every Update

Manual review fails under pressure. When a critical security update ships, nobody reads documentation. They click update and hope. A pre-update script can prevent the worst outcomes. I use a simple shell script that runs before wp theme update:

  1. Back up the current parent theme.json.
  2. Download the new version to a temp directory.
  3. Diff the old and new parent theme.json files.
  4. Cross-reference the diff against the child theme’s theme.json and the documentation file.
  5. Output a list of potential conflicts.

This script does not resolve conflicts. It surfaces them. The output is a plain-text report that tells you which of your overrides might be affected. You can then decide to postpone the update, adjust your child theme, or accept the risk. The script is not complex. It is a set of jq queries and diff commands wrapped in a few lines of bash. The value is in making the invisible visible.

Code diff displayed on a monitor with highlighted changes in a configuration file

Documentation Template for theme.json Overrides

Copy this template into your child theme’s THEME_JSON_OVERRIDES.md. Fill it out every time you touch a theme.json value. Do not skip entries because you are in a hurry. An incomplete log is worse than no log because it creates false confidence.

# theme.json Override Log

## Active Overrides

| Path | Parent Value | Child Value | Date | Reason |
|------|--------------|-------------|------|--------|
| settings.color.palette | [default] | [brand] | 2025-01-15 | Brand alignment |
| settings.layout.contentSize | 650px | 720px | 2025-01-15 | Wider reading line for editorial content |
| styles.blocks.core/button.border.radius | 4px | 0px | 2025-02-01 | Design system requires sharp corners |

## Resolved Overrides

| Path | Parent Value | Child Value | Resolved In | Notes |
|------|--------------|-------------|-------------|-------|
| settings.color.palette | [default] | [brand] | Parent v1.3.0 | Parent adopted our palette |

## Database Overrides

| Date | Exported JSON File | Notes |
|------|-------------------|-------|
| 2025-02-10 | global-styles-2025-02-10.json | Editor adjusted heading sizes |

## Merge Conflict Notes

| Date | Path | Parent New Value | Our Override | Decision |
|------|------|-----------------|--------------|----------|
| 2025-03-01 | settings.layout.contentSize | 680px | 720px | Kept our override; parent change was unrelated |

When the Parent Theme Changes the Schema

WordPress 6.6 introduced new theme.json properties and deprecated others. When the schema version increments, your overrides may reference paths that no longer exist. The update does not warn you. It silently ignores invalid paths. Your customizations disappear without an error.

Before updating a theme, check its theme.json schema version. If it has changed, review the WordPress release notes for breaking changes. The WordPress theme.json reference documents the current schema. Compare your override paths against the new schema. Update any deprecated paths. Add a note to your documentation file under a “Schema Migration” section.

FAQ

What is the safest way to override a single color in the palette without breaking the rest?

Do not override the entire settings.color.palette array. Instead, use wp_theme_json_data_theme filter in your child theme’s functions.php to modify the palette programmatically. This lets you add, remove, or replace specific colors without touching the parent’s array structure. Document the filter and the color values in your override log.

How do I know if a theme update will overwrite my child theme overrides?

It will not overwrite your child theme’s theme.json file. The risk is that the parent’s changes conflict with your overrides in ways that produce broken output. Run a diff between the old and new parent theme.json before updating. Cross-reference the changed paths with your override log. Test on a staging environment first.

Can I use a plugin to manage theme.json overrides instead of a child theme?

Plugins can hook into wp_theme_json_data_theme and modify the data. This works, but it scatters your configuration across the codebase. A child theme keeps overrides in one place and is easier to document. If you already use a custom plugin for site functionality, adding overrides there is acceptable if you document them in the same structured log.

What should I do if I inherited a site with undocumented parent theme edits?

First, diff the current parent theme.json against the original version from the theme’s repository. Identify every change. Create a child theme and move each change into it. Document each one. Then update the parent theme to the latest version and verify the site still renders correctly. This is tedious but necessary. Skipping it guarantees future breakage.

Documenting theme.json changes is not a one-time task. It is a discipline. Every override you do not document is a future outage you have already scheduled. The method described here is not elegant. It is a low-tech, high-reliability system that works when you are the only developer and when you are part of a team. The next time a theme update lands, you will know exactly what to check and why.

If you are dealing with a site that already has broken template output after an update, start with What to Fix First When a New WordPress Site Says Nothing Found to rule out fundamental routing issues before diving into theme configuration.