This guide is for site owners, in-house marketers and developers who need to change how a WordPress theme looks or behaves and want those changes to survive the next update. By the end you will know which tool fits each kind of change (child theme, the Site Editor, theme.json, a style variation or a small plugin), have working code for the common cases, and have a step-by-step way out if someone has already edited the parent theme directly.
Last verified: October 2026.
The short answer has not changed: do not edit a theme you did not write and do not control. What has changed is that a child theme is no longer the only alternative. With block themes, much of that work is now a Site Editor change, a theme.json tweak or a style variation, and site functionality belongs in a plugin whatever theme you run.
Why direct edits to a parent theme break
When you update a theme, WordPress replaces the whole theme folder with the new version. Any line you changed in header.php, functions.php or style.css of that theme is gone. The WooCommerce template documentation says the same thing about plugin and parent theme files: edits made there are lost when the plugin or theme updates.
The update does not have to be one you click. Since WordPress 5.5, themes can be set to update automatically from the Themes screen, and many maintenance plans and managed hosts apply updates on a schedule.
Direct edits cause three other problems that are easy to miss:
- You cannot see what changed. Without a clean copy of the original theme, nobody can tell which lines are custom. Handing the site to another developer or agency becomes guesswork.
- Security fixes get skipped. Once people know updating will break the site, they stop updating.
- The built-in editor makes it worse. The Theme File Editor in wp-admin writes straight to the live theme with no history. On client sites I disable it with
define( 'DISALLOW_FILE_EDIT', true );inwp-config.phpand keep all code changes in version control.
There is one case where editing theme files directly is correct: the theme is yours. A custom theme built for the site, with no upstream vendor and no update feed, is not a “parent” of anything. Edit it, commit to Git, deploy.
Your options in 2026
WordPress now gives you five places to put a customisation:
- Site Editor (block themes): layout, templates, template parts, global styles and patterns edited visually. Changes are saved in the database, not in theme files, so a theme update does not overwrite them.
- theme.json: colours, fonts, spacing, layout widths and per-block settings. It works with both block and classic themes.
- Style variation: an alternative
theme.jsonfile stored in the theme’s/stylesfolder that users can switch to. - Child theme: a second theme that inherits everything from the parent and overrides only the files you add. Works for classic and block themes.
- Small custom plugin: code that should keep working if the theme changes, such as custom post types, shortcodes, tracking scripts, checkout tweaks and integrations.
The Theme Handbook’s child theme page describes the loading order for block themes: WordPress defaults, then the parent theme, then the child theme, then user customisations from the Site Editor on top. That last layer is effectively a “grandchild” stored in the database. Proper grandchild themes are not supported; there are only two levels, parent and child.
Decision table: where each change should live
| Change you want | Classic theme | Block theme | Why |
|---|---|---|---|
| Change colours, fonts, spacing | Customizer or child theme.json / CSS | Site Editor Styles, or child theme.json | Database or child files both survive updates |
| A few lines of CSS | Additional CSS or child style.css | Site Editor custom CSS or child style.css | Child file is better if you want it in Git |
| Change a page layout or header | Child theme template override | Site Editor, then save to a child theme | Templates are files in classic themes, blocks in block themes |
| Offer two or three design looks | Not applicable | Style variations in /styles | Users switch looks without new code |
| Add a custom post type or taxonomy | Plugin | Plugin | Content must not vanish if the theme changes |
| Tracking scripts, schema, redirects | Plugin | Plugin | Not presentation, so not theme code |
| Hook into theme-specific actions | Child functions.php | Child functions.php | Only makes sense while that parent is active |
| Change WooCommerce markup | Child theme /woocommerce/ override, or hooks | Block templates in child /templates, or hooks | Prefer hooks; overrides need maintenance |
| Edit a theme you built and own | Edit it directly in Git | Edit it directly in Git | There is no upstream update to lose |
If a change appears in two columns, my rule is simple: if it would still be needed after a redesign with a different theme, it goes in a plugin. If it only makes sense for this theme, it goes in the child theme or the Site Editor.
When a child theme is still the right call
I still create a child theme on most client builds that use a third-party theme, because:
- You override PHP templates in a classic theme. Copying
single.phporheader.phpinto a child theme is still the only update-safe way to change them. - You use theme hooks. Many commercial themes expose their own actions and filters. Code that targets them belongs next to the theme, in the child’s
functions.php. - You want design changes in version control. Site Editor changes live in the database. For a team that reviews changes or hands the site over, I want templates and
theme.jsonas files in Git. - You override WooCommerce templates. Overrides need a theme folder that will not be replaced on update.
- You run staging and production. Files deploy cleanly between environments. Database template edits need to be exported or redone.
A child theme is the wrong tool for functionality. If your child functions.php registers a “Projects” post type and you later switch theme, every project disappears from the admin until the code is moved. Put that in a plugin from day one.
How to build a classic child theme
A child theme needs one required file. The handbook calls style.css “the one absolutely necessary file for a child theme to exist”, and the Template header must match the parent theme’s folder name exactly.
Create wp-content/themes/parent-theme-child/style.css:
/*
Theme Name: Parent Theme Child
Template: parent-theme
Description: Site customisations for example.com
Version: 1.0.0
Text Domain: parent-theme-child
*/
/* Your custom CSS starts here */Replace parent-theme with the real folder name, for example twentytwentyfive.
Then add functions.php to load the stylesheets. Before you copy this, check how the parent loads its CSS. If the parent already enqueues the child stylesheet, you need nothing. If it only loads the active theme’s stylesheet through get_stylesheet_uri(), you need to add the parent’s file yourself:
<?php
/**
* Parent Theme Child functions.
*/
add_action( 'wp_enqueue_scripts', 'ptc_enqueue_styles' );
function ptc_enqueue_styles() {
$parent = wp_get_theme( get_template() );
wp_enqueue_style(
'ptc-parent-style',
get_parent_theme_file_uri( 'style.css' ),
array(),
$parent->get( 'Version' )
);
wp_enqueue_style(
'ptc-child-style',
get_stylesheet_uri(),
array( 'ptc-parent-style' ),
wp_get_theme()->get( 'Version' )
);
}Bump Version in the child style.css when you change it, so browsers fetch the new file.
Two rules from the handbook that trip people up. First, the child functions.php does not replace the parent’s; both run, and the child’s loads first. Second, do not copy functions from the parent into the child. Duplicate function names cause a fatal error. Use the parent’s hooks, or, if the parent wraps a function in if ( ! function_exists() ), define your version in the child.
To override a template, copy the file from the parent into the same relative path in the child and edit the copy. parent-theme/template-parts/content.php becomes parent-theme-child/template-parts/content.php. Inside your own code, use get_theme_file_path() and get_theme_file_uri() so WordPress checks the child first and falls back to the parent.
Block themes: child theme, Site Editor or Create Block Theme
For a block theme, most visual changes can be made in Appearance > Editor without writing any files. Those edits are stored in the database and survive theme updates. The catch, as Carolina Nymark explains on Full Site Editing, is the reverse problem: if the parent theme improves a template you have customised, you will not see the improvement until you reset your customisation.
A block child theme can be as small as a style.css with the Template header and a theme.json. Templates go in /templates and template parts in /parts. A file with the same name as the parent’s overrides it; for patterns, the registered slug must also match.
You do not have to write any of this by hand. The Create Block Theme plugin, maintained on WordPress.org, can create a child theme of the active theme including the changes you have made in the editor, save editor changes back into the theme’s files, create a style variation, clone a theme and export everything as a zip. My workflow on block theme projects is:
- Build the design in the Site Editor on a staging site.
- Use Create Block Theme to create a child theme that includes those changes.
- Commit the child theme to Git.
- After later editor sessions, use “Save Changes” to write them into the child theme’s files, then reset the database copies so the files are the source of truth.
- Deploy the child theme to production like any other code.
Overriding theme.json in a child theme
The child’s theme.json is applied on top of the parent’s. Settings you leave out are inherited. Preset arrays such as the colour palette are replaced, not merged, so if you define a palette you must list every colour you want, not just the one you are changing.
Here is a child theme.json that changes the content width, adds a palette and sets the body font size. It uses version 3, which came in with WordPress 6.6:
{
"$schema": "https://schemas.wp.org/trunk/theme.json",
"version": 3,
"settings": {
"layout": {
"contentSize": "720px",
"wideSize": "1200px"
},
"color": {
"palette": [
{ "slug": "base", "color": "#ffffff", "name": "Base" },
{ "slug": "contrast", "color": "#111111", "name": "Contrast" },
{ "slug": "accent", "color": "#0b5cad", "name": "Accent" }
]
}
},
"styles": {
"typography": {
"fontSize": "1.0625rem"
}
}
}Check the parent’s preset slugs before you change them. Patterns and templates refer to colours by slug, so if the parent uses contrast and you rename it dark, blocks lose their colour.
When a style variation is enough
If the goal is “the same theme, different colours and fonts”, you may not need a child theme at all. A style variation is a JSON file in the theme’s /styles folder that overrides theme.json. Note the handbook’s warning: when a user selects a variation, its data is copied into the database as a user customisation, so later edits to the file will not reach that site until the user switches to another variation and back. Also, a variation added to a third-party theme’s own /styles folder is lost on update, so put it in a child theme’s /styles folder.
WooCommerce template overrides
WooCommerce lets a theme replace its PHP templates. You copy the file from wp-content/plugins/woocommerce/templates/ into a woocommerce folder in your child theme, keeping the same structure but dropping templates. The example in the WooCommerce docs is:
wp-content/plugins/woocommerce/templates/emails/admin-new-order.php
→ wp-content/themes/your-child-theme/woocommerce/emails/admin-new-order.phpOverrides are not updated when WooCommerce updates. Each template carries a version number, and WooCommerce > Status shows a warning when your copy is older than the core version. An outdated checkout or cart template is a common cause of broken stores after a major update. That is why WooCommerce recommends hooks first: add_action() and remove_action() on hooks like woocommerce_single_product_summary can add, move or remove content without copying the file.
Two details that catch people. If your theme has a woocommerce.php file, it takes priority and you cannot override woocommerce/archive-product.php. And on a block theme, the shop, product, cart and checkout layouts are block templates such as single-product.html and archive-product.html; WooCommerce’s block theme documentation says a theme overrides them with a same-named file in its /templates folder. In my experience, on block-theme stores the PHP overrides that still matter most are the email templates.
For checkout logic, price rules or anything that changes how orders behave, write a plugin, not a template override.
When a small plugin beats a child theme
A site-specific plugin is a single PHP file in wp-content/plugins/. It is the right home for anything that is site behaviour rather than design:
<?php
/**
* Plugin Name: Example Site Functions
* Description: Site-specific features that must survive a theme change.
* Version: 1.0.0
*/
defined( 'ABSPATH' ) || exit;
add_action( 'init', function () {
register_post_type( 'project', array(
'label' => 'Projects',
'public' => true,
'show_in_rest' => true,
'supports' => array( 'title', 'editor', 'thumbnail' ),
) );
} );Use a plugin for custom post types and taxonomies, shortcodes and custom blocks, third-party API integrations, WooCommerce checkout or shipping logic, LearnDash course behaviour, and analytics or consent scripts.
Migration path: “I already edited the parent theme”
This is the most common situation I see on sites I take over. Here is the process I follow. Do it on a staging copy, never on the live site.
- Take a full backup of files and database, and confirm you can restore it.
- Find the exact parent version installed. Check the
Versionline in the parent’sstyle.css, or runwp theme listwith WP-CLI. - Get a clean copy of that same version. For WordPress.org themes, download that version from the theme’s page; for commercial themes, from the vendor’s account area. It must be the same version, or the comparison will be full of the vendor’s own changes.
- Compare the two folders.
diff -ru clean-theme/ live-theme/ > theme-changes.difflists every changed line. Put both folders in a Git repository and the diff becomes easy to review. - Sort every change. CSS goes to the child
style.cssortheme.json. Functions go to the childfunctions.phpif they are theme-specific, or to a site plugin if not. Changed templates are copied whole into the child theme. Changed WooCommerce templates go into the child’swoocommercefolder. - Create and activate the child theme. On classic themes, Customizer settings are stored per theme, so the child starts without the parent’s logo, menu locations and colours. Re-enter them, or use the parent’s export/import tool if it has one. On block themes, Create Block Theme’s “Create Child Theme” carries your editor changes across.
- Replace the edited parent with the clean copy, then update it to the latest version.
- Test the pages that matter: home, a post, a key landing page, and on a store the product, cart, checkout and a test order email. Check WooCommerce > Status for outdated templates.
- Commit the child theme and plugin to Git and write a short note on what lives where.
Step 6 is where most attempts go wrong: the site looks broken because menus and Customizer settings appear to be gone. They are not deleted; they are stored against the parent theme.
A child theme plus a small site plugin, both in Git, is also what the next developer expects to find. Clients I work with in the US, UK, EU and Australia often ask for the code in a repository they own at handover; a direct-edited parent theme makes that hard because nobody can separate the vendor’s code from yours.
Frequently asked questions
Do block themes still need child themes?
Not always. Many block theme sites are fine with Site Editor changes saved in the database. A child theme becomes useful when you want templates and theme.json changes as files in Git, deploy between staging and production, or override WooCommerce block templates.
Will I lose my changes when I update a child theme’s parent?
No. Updating the parent replaces only the parent’s folder. Your child theme files stay as they are. You should still check template overrides after major parent updates, because your copied file will not pick up fixes the vendor made to the original.
What happens to my Site Editor changes when I update a block theme?
They stay. The Site Editor saves templates and styles in the database, and the update only replaces theme files. The trade-off is that you will not see the vendor’s improvements to a template you customised until you reset that template.
Can I make a child theme of a child theme?
No. WordPress supports only two levels, parent and child. If you need shared code across several sites, put it in a plugin, or treat the child theme as your own theme and copy the parent’s files into it.
Should custom post types go in functions.php?
Not in a theme’s functions.php. If you change theme later, the post type disappears from the admin and the content becomes unreachable until the code is moved. Register post types and taxonomies in a small site plugin.
Is it safe to use the Theme File Editor in wp-admin?
I avoid it. It writes directly to live files with no history, a PHP syntax error can take the site down, and edits to a parent theme are lost on the next update. Disable it with DISALLOW_FILE_EDIT and make changes through version control instead.
How do I know if my WooCommerce template overrides are out of date?
Go to WooCommerce > Status. The report lists overridden templates and flags any whose version is older than the one WooCommerce ships. Compare your copy against the new core file and carry your changes over.
If your site has a modified parent theme, a WooCommerce store with outdated template overrides, or a block theme you want moved into version control, I can sort out what lives where and leave you with a clean child theme and plugin. See my WordPress theme customization service for how I work.

