WordPress child theme: why you need one and how to create it

A child theme inherits everything from a parent theme but keeps your customizations in separate files that survive parent theme updates. This guide walks through creating one for both classic and block themes, with the exact files, enqueue pattern, and template override rules.

Goal. By the end of this article you will have a working child theme that inherits the parent theme's styles and templates, lets you override any of them safely, and survives every parent theme update without losing a single line of your custom code.

Prerequisites

  • A WordPress 5.9+ site with admin access and the ability to edit files via FTP, SSH, or your hosting file manager. If you are running an older version, the classic-theme steps still apply but the block-theme (FSE) section does not.
  • A parent theme already installed and activated. This guide uses Twenty Twenty-Four for the block-theme path and Twenty Twenty-One for the classic-theme path, but the process is the same for any parent theme.
  • Access to wp-content/themes/ on the server. If your host blocks file-level access, check whether they offer a built-in child theme generator in the hosting panel.

What a child theme is and why you need one

A child theme is a separate theme directory that declares a single parent (the "template" theme) and inherits all of that parent's templates, styles, and functionality. Any file you place in the child theme directory overrides the equivalent file in the parent. Files you do not override continue to load from the parent, unchanged.

This is a WordPress core mechanism, not a plugin feature. WordPress has supported child themes since version 3.0, and the Theme Handbook's child theme documentation is the canonical reference.

Why this matters: every time the parent theme updates (security patches, new features, compatibility fixes), WordPress overwrites every file in the parent theme directory. Any CSS, PHP, or template file you edited directly in the parent is gone. A child theme puts your changes outside the blast radius of that overwrite.

What happens to parent theme edits on update

Three scenarios that trip people up regularly:

  • Direct file edits to the parent theme (editing style.css, header.php, functions.php inside the parent directory): lost entirely on the next update. No recovery path unless you have a backup.
  • CSS added via the Customizer's "Additional CSS" field: stored in the database, so it survives theme file updates. But it is tied to the active theme. If you switch themes or activate a child theme, that CSS becomes inactive. And the Customizer Additional CSS field only exists for classic themes; block themes use the Site Editor's global styles instead.
  • Site Editor customizations (templates, styles, and patterns saved via the block editor UI in block themes): stored in the database and survive parent theme updates without a child theme. A child theme is not needed for Site Editor changes, only for file-level modifications like custom theme.json settings, PHP in functions.php, or HTML template overrides.

The child theme covers the first scenario completely and the third partially. If all your customizations are CSS-only on a classic theme, the Customizer field works. For anything more, a child theme is the right answer.

Creating a child theme for a classic theme

A child theme needs a minimum of two files: style.css and functions.php. The directory name can be anything, but the convention is parentname-child.

Step 1: create the child theme directory

Create a new folder inside wp-content/themes/. For a child of Twenty Twenty-One:

wp-content/themes/twentytwentyone-child/

Step 2: create style.css with the required header

Create style.css in the child theme directory with this header:

/*
 Theme Name: Twenty Twenty-One Child
 Template:   twentytwentyone
*/

/* Your custom CSS goes below this line */

Two fields are required. Theme Name is any name you choose for your child theme. Template must match the parent theme's directory name exactly, not its display name. The Theme Handbook is explicit: the value "must be a 100% match of the folder name of the parent theme, relative to the wp-content/themes folder."

If Template does not match, WordPress will not recognise the parent-child relationship and the theme will either fail to activate or display without any parent styles.

Step 3: create functions.php and enqueue the parent stylesheet

Create functions.php in the child theme directory:

<?php
// Enqueue the parent theme's stylesheet, then the child's
add_action( 'wp_enqueue_scripts', 'twentytwentyone_child_enqueue_styles' );

function twentytwentyone_child_enqueue_styles() {
    // Load the parent stylesheet first
    wp_enqueue_style(
        'twentytwentyone-style',
        get_template_directory_uri() . '/style.css'
    );

    // Load the child stylesheet second, with parent as dependency
    wp_enqueue_style(
        'twentytwentyone-child-style',
        get_stylesheet_uri(),
        array( 'twentytwentyone-style' ) // ensures correct cascade order
    );
}

get_template_directory_uri() points to the parent theme. get_stylesheet_uri() points to the child theme's style.css. The $deps array tells WordPress to load the parent first, so your child CSS overrides land later in the cascade. The wp_enqueue_style() documentation explains the dependency parameter in detail.

Do not use @import url('../twentytwentyone/style.css') in the child style.css. That pattern appears in older tutorials but adds an extra HTTP request and blocks rendering. The enqueue approach is what WordPress recommends.

Step 4: activate the child theme

Go to Appearance > Themes in wp-admin. Your child theme appears in the list. Activate it.

Expected result: the site looks identical to before. The parent's styles load first, your child's empty style.css adds nothing on top, and the visual result is a pixel-perfect match. If the site looks unstyled, the Template value is wrong or the enqueue function has a typo.

Enqueueing correctly when the parent already enqueues itself

Some parent themes register and enqueue their own style.css with a known handle. In that case, you do not need to enqueue the parent yourself; you only need to enqueue the child with the parent's handle as a dependency.

Check the parent theme's functions.php for a line like:

wp_enqueue_style( 'parent-theme-handle', get_stylesheet_uri() );

If that handle exists, your child's functions.php simplifies to:

<?php
add_action( 'wp_enqueue_scripts', 'my_child_enqueue_styles' );

function my_child_enqueue_styles() {
    wp_enqueue_style(
        'my-child-style',
        get_stylesheet_uri(),
        array( 'parent-theme-handle' ) // use the parent's actual handle
    );
}

When in doubt, enqueue both explicitly (as in Step 3). Enqueueing a stylesheet that is already enqueued under a different handle results in it loading twice, which is wasteful but not broken. Loading it zero times is broken.

Overriding parent theme templates

WordPress's template hierarchy applies to child themes with one important rule: the child theme's copy of a template file takes priority over the parent's at the same specificity level.

To override a template, copy the file from the parent theme directory into the child theme directory with the same filename and relative path. For example, to override single.php:

  1. Copy wp-content/themes/twentytwentyone/single.php to wp-content/themes/twentytwentyone-child/single.php.
  2. Edit the child's copy. The parent's version is now ignored for that template.

Expected result: pages that use single.php now render from the child's version. All other templates still come from the parent.

A specificity caveat that catches people. A child theme's generic category.php does not override a parent theme's more-specific category-recipes.php. WordPress picks the most-specific matching file regardless of whether it lives in the child or the parent. The template hierarchy documentation is clear on this: specificity wins over theme hierarchy.

Adding custom functions to functions.php

The child theme's functions.php does not replace the parent's. Both files load, with the child's loading first. This means you can add hooks, filters, and new functions in the child without duplicating the parent's code.

Do not copy functions from the parent's functions.php into the child. If the parent declares function mytheme_setup() and you copy the same function into the child, PHP will fatal error on a duplicate function declaration. The Theme Handbook warns against this explicitly.

If you need to change a parent function's behaviour, use the hooks the parent provides. Well-built themes wrap their functions in if ( ! function_exists() ) checks specifically so child themes can override them by declaring the function first (since the child loads before the parent). If the parent does not use that pattern, use remove_action() or remove_filter() in the child's functions.php to detach the parent's hook and attach your own.

Creating a child theme for block themes (FSE)

Block themes (Full Site Editing, introduced in WordPress 5.9) use a different customization model. Templates are HTML files, not PHP. Styles are defined in theme.json, not style.css. But child themes still work, and the principle is the same: put your overrides in the child directory, let the parent handle everything else.

The minimum files

A block child theme needs:

  1. style.css with the Theme Name and Template header, identical to the classic version. WordPress still uses this file to recognise the child theme. For a child of Twenty Twenty-Four:
/*
 Theme Name: Twenty Twenty-Four Child
 Template:   twentytwentyfour
*/
  1. theme.json with at least a version field. This is where you put your style and setting overrides instead of CSS:
{
    "$schema": "https://schemas.wp.org/wp/6.7/theme.json",
    "version": 3
}

The version field is required. Omitting it causes settings to fail silently. Version 3 was introduced in WordPress 6.6; use version 2 if you need to support WordPress 6.5 or earlier.

  1. functions.php is optional for block child themes. Because block themes do not enqueue style.css for rendering (styles come from theme.json), you only need functions.php if you are adding PHP hooks, filters, or custom post types. If you do want the child's style.css loaded as an actual stylesheet, you need to enqueue it explicitly, the same way you would for a classic child theme.

Overriding theme.json settings

The child's theme.json merges with the parent's via WP_Theme_JSON_Resolver::get_merged_data(). The merge priority, lowest to highest:

  1. WordPress core defaults
  2. Block-level data
  3. Theme (parent, then child at the same origin level)
  4. User customizations from the Site Editor (highest priority)

To override the parent's primary color, for example:

{
    "$schema": "https://schemas.wp.org/wp/6.7/theme.json",
    "version": 3,
    "settings": {
        "color": {
            "palette": [
                {
                    "color": "#1a3d5c",
                    "name": "Primary",
                    "slug": "primary"
                },
                {
                    "color": "#f5f1eb",
                    "name": "Base",
                    "slug": "base"
                }
            ]
        }
    }
}

A critical caveat: the merge is not deep at the array level. If you override the color palette, you must include the entire palette array, not just the entry you want to change. Full Site Editing's child theme documentation spells this out: "Settings and styles in the child theme.json replace the equivalent in the parent; it is not possible to make partial edits" at the array level.

Overriding block templates

Block theme templates live in a templates/ directory as .html files. To override one, copy it from the parent's templates/ into the child's templates/ with the same filename. The loading order WordPress follows:

  1. Child .html template
  2. Child .php template (fallback)
  3. Parent .html template
  4. Parent .php template (fallback)

Template parts work the same way, in the parts/ directory.

When you do NOT need a child theme

Not every customization requires a child theme. Skip it when:

  • All your styling changes are made through the Site Editor (block themes) or the Customizer's Additional CSS (classic themes). Both store changes in the database, outside the theme files.
  • You only need a few CSS rules and do not modify any templates or PHP. A small custom CSS plugin or the Customizer field is simpler.
  • You are building a fully custom theme from scratch rather than modifying an existing one.

You do need a child theme when you are editing theme PHP files, overriding template files, modifying theme.json directly (outside the Site Editor), or adding functionality via functions.php that belongs in the theme rather than a plugin.

Verify the final result

After activating the child theme, check three things:

  1. The front-end looks correct. Browse the home page, a single post, a category archive, and the 404 page. Compare against the parent theme's appearance. Any visual breakage means a missing enqueue or a broken Template header.
  2. The child theme is shown in Appearance > Themes. WordPress lists it as a child of the parent. If the parent relationship is not shown, the Template value in style.css is wrong.
  3. Your overrides take effect. If you added custom CSS, inspect the element in the browser's dev tools and confirm the child stylesheet loads after the parent. If you overrode a template, view a page that uses it and verify the change is visible.

Common problems

  • Site looks completely unstyled after activation. The parent stylesheet is not loading. Check that the enqueue function in functions.php uses the correct parent handle or path, and that get_template_directory_uri() points to the actual parent directory.
  • "Stylesheet is not readable" or "The parent theme is missing" error. The Template value in style.css does not match the parent theme's folder name. Folder names are case-sensitive on Linux servers.
  • Changes in theme.json are ignored. Missing "version" field in the child's theme.json, or the version number does not match the WordPress version's supported schema. WordPress 6.6+ uses version 3; WordPress 5.9 through 6.5 use version 2.
  • Duplicate function fatal error. You copied a function from the parent's functions.php into the child. Remove the duplicate and use hooks instead.
  • Child CSS is not overriding parent styles. The cascade order is wrong. Make sure the child stylesheet declares the parent's handle as a dependency so it loads after the parent.

For performance issues after activating a new theme or child theme, see why WordPress can feel slow after an update, which covers the cache-clearing and OPcache effects of theme changes.

When to escalate

If the child theme is not behaving as expected after following this guide, collect the following before asking for help:

  • WordPress version (visible in Dashboard > Updates)
  • PHP version (visible in Tools > Site Health > Info > Server)
  • Parent theme name and version
  • The full contents of the child theme's style.css header
  • The full contents of the child theme's functions.php
  • For block themes: the child's theme.json
  • Any error messages from the browser console or wp-content/debug.log

That information lets a developer or your hosting support reproduce the problem without guessing. For a detailed walkthrough of the debug flags that produce debug.log, see the wp-config.php reference.

Need a WordPress fix or custom feature?

From error fixes to performance improvements, I build exactly what's needed—plugins, integrations, or small changes without bloat.

Explore web development

Search this site

Start typing to search, or browse the knowledge base and blog.