12k
All articles

How to Make a WordPress Child Theme

Create a WordPress child theme that preserves customizations through parent updates. Set up classic and block themes, enqueue styles, override templates, and know when a plugin is better.

OpenReplay Team
OpenReplay Team
How to Make a WordPress Child Theme

To create a WordPress child theme, add a new folder to wp-content/themes, put a style.css inside it whose Template header matches the parent theme’s folder name, and activate it. The child inherits the parent’s templates, styles and functionality and holds only your changes.

If you have ever edited a theme’s files directly and then watched the next update wipe them out, a child theme is how you stop that happening.

This guide covers the setup that works in modern WordPress. It walks through a classic child theme with correct enqueueing, template and function overrides, what changes for block themes like Twenty Twenty-Four, and the cases where you don’t need a child theme at all.

Key Takeaways

  • The only file a child theme strictly requires is style.css. Its Template header must exactly match the parent’s folder name, so for Twenty Twenty-Four the value is twentytwentyfour.
  • A child theme’s functions.php does not replace the parent’s. WordPress loads both, and the child’s file runs first.
  • Load child styles with wp_enqueue_style() on the wp_enqueue_scripts hook, not with @import.
  • To override a template, template part or pattern, put a file with the same name in the child theme. Block patterns also need the same Slug.
  • Changes that should survive a theme switch, such as custom post types, belong in a plugin, not a child theme.

Why Does Editing a Parent Theme Directly Fail?

When a theme updates, WordPress replaces its files with the new version, so any edit you made inside the theme folder is lost. A child theme keeps your changes in a separate folder that updates never touch. The Theme Handbook’s child theme guide presents this as the way to take parent updates without giving up your own edits. The theme system stops at two layers, a parent and a child, so you can’t install a grandchild theme on top.

How to Create a Child Theme in WordPress (Classic Themes)

A classic child theme needs a folder, a style.css with a Template header and, in most cases, a functions.php that enqueues the stylesheet. The layout is the same folder, style.css and functions.php structure described in our guide on building a responsive WordPress theme with Bootstrap. The difference is that the child only contains what it changes.

wp-content/themes/
├── twentytwentyfour/
└── tt4-child/
    ├── style.css
    └── functions.php

The style.css Header

Only style.css is strictly required. The Main Stylesheet documentation says any theme needs at least a Theme Name header, and a child theme adds Template on top of that.

/*
 * Theme Name:  TT4 Child
 * Template:    twentytwentyfour
 * Version:     1.0.0
 * Text Domain: tt4-child
 */

Template takes the parent’s folder name, not its display name. If the two don’t match character for character, WordPress won’t link the child to its parent.

Enqueueing Stylesheets Instead of @import

Load child theme styles with wp_enqueue_style() on the wp_enqueue_scripts hook, not with @import. Many older tutorials load the parent styles with @import at the top of the child’s style.css. This approach is outdated:

/* Outdated: do not use */
@import url("../twentytwentyfour/style.css");

The browser only finds the imported file after it has downloaded and parsed the child stylesheet, so the two requests happen one after the other and both block rendering. The import also sits outside WordPress’s enqueue system, which means WordPress can’t manage its dependencies, version it or deduplicate it.

The replacement is wp_enqueue_style() called from a function hooked to wp_enqueue_scripts. That same hook loads scripts too, which our article on adding custom JavaScript to WordPress themes covers.

<?php
// functions.php
add_action( 'wp_enqueue_scripts', 'tt4child_enqueue_styles' );

function tt4child_enqueue_styles() {
	wp_enqueue_style(
		'tt4child-style',
		get_stylesheet_uri(), // the active (child) theme's style.css
		array(),              // $deps: handles that must load first
		'1.0.0'               // $ver: appended as a cache-busting query string
	);
}

The right enqueue code for a child theme depends on what the parent theme already enqueues:

What the parent enqueuesWhat the child does
Both its own and the child’s stylesheetNothing
Only its own stylesheetEnqueue the child with get_stylesheet_uri() (code above)
Only the active theme’s, via get_stylesheet_uri()Enqueue the parent with get_parent_theme_file_uri( 'style.css' )
Nothing (Twenty Twenty-Four, per the Handbook)Enqueue the child with get_stylesheet_uri()

For the third row, use this:

function tt4child_enqueue_styles() {
	wp_enqueue_style(
		'tt4child-parent-style',
		get_parent_theme_file_uri( 'style.css' )
	);
}

To find out which case applies, search the parent’s functions.php for wp_enqueue_style, or look for stylesheet <link> tags in the page source. Stylesheet order is not fixed. It follows the enqueue calls, and the $deps argument takes an array of registered handles that must load first. To make the child print after the parent, pass the parent’s handle in $deps, reading the handle name from the parent’s code. When a child stylesheet URL is wrong, the request returns a 404 and the page renders with only the parent’s CSS. A session replay that records network requests next to the visual playback shows the failed request alongside the unstyled page.

How Do You Override Parent Templates?

To override a parent template, copy the file (don’t move it) into the same relative path in the child theme. When WordPress works through the template hierarchy, it checks the child folder before the parent, so a file with the same name in the child is used. Moving the file instead of copying it changes the parent theme, and the next update puts it back anyway.

twentytwentyfour/page.php  →  copy to  →  tt4-child/page.php

The same rule applies to template parts. You can also add new templates that the parent doesn’t have.

Overriding Parent Functions

A child theme’s functions.php doesn’t replace the parent’s. Per the Handbook, WordPress runs both files, starting with the child’s and moving straight on to the parent’s. Two things follow from that load order. Parent functions wrapped in function_exists() (pluggable functions) can be redefined in the child. Any other parent function has to be unhooked or supplemented. Don’t paste the parent’s functions.php code into the child either: declaring the same function names twice stops the site with a fatal error.

A pluggable function in the parent looks like this:

// Parent theme
if ( ! function_exists( 'parenttheme_credit' ) ) {
	function parenttheme_credit() { /* ... */ }
}

Because the child runs first, defining the same name in the child means the parent’s version is skipped:

// Child theme
function parenttheme_credit() {
	echo '<p>Custom credit line</p>';
}

If the function isn’t pluggable, remove it with remove_action(), using the same hook and priority it was registered with. A remove_action() call placed at the top level of the child’s file runs before the parent has added its hook, so there is nothing to remove yet. Run it from after_setup_theme, which runs once both themes’ functions.php files have loaded:

// Parent theme
add_action( 'init', 'parenttheme_setup_extra', 20 );

// Child theme
add_action( 'after_setup_theme', function () {
	remove_action( 'init', 'parenttheme_setup_extra', 20 );
} );

remove_filter() works the same way for filters. To add to a parent function instead of replacing it, attach your own function to the same hook with a later priority. The default priority for add_action() is 10, and larger numbers run later:

add_action( 'parent_footer', 'tt4child_footer_extra', 20 );

How Do Child Themes Work for Block Themes?

A block-theme child, such as one built on Twenty Twenty-Four, often needs only style.css and theme.json. Styling mostly lives in theme.json, so the Handbook notes that enqueueing style.css is often unnecessary, and many block children have no functions.php at all.

Classic childBlock child
Required filestyle.cssstyle.css
Where styles livestyle.css (enqueued)theme.json
functions.phpUsually, for enqueueingOften none
Templates.php files at the theme root.html files in templates/
Template parts.php files such as header.php.html files in parts/
PatternsPHP files in patterns/ or register_block_pattern()PHP files in patterns/
tt4-child/
├── style.css
├── theme.json
├── templates/
│   └── single.html
├── parts/
│   └── header.html
└── patterns/
    └── (same filename as the parent pattern).php

To override a template, part or pattern, add a file with the same name. For patterns, the registered Slug header must also match the parent’s, so copy it from the parent file:

<?php
/**
 * Title: Footer
 * Slug: parent-slug/pattern-name
 */
?>

A minimal theme.json pins the schema and uses version 3, which requires WordPress 6.6 or later:

{
	"$schema": "https://schemas.wp.org/wp/6.6/theme.json",
	"version": 3,
	"styles": {
		"typography": {
			"lineHeight": "1.7"
		}
	}
}

The parent and child theme.json files combine according to specific merge rules, with the child’s values taking priority. Customizations saved in the Site Editor are also stored in the database and sit above the child theme in the Handbook’s layer model. If a child template seems to be ignored, clear that template’s saved customization in the Site Editor.

When You Don’t Need a Child Theme

For small visual tweaks or functional features, you don’t need a child theme. On a classic theme, the Customizer’s Additional CSS is enough for a few rules. With a block theme active, custom CSS goes through the Site Editor’s Styles panel instead. Functional changes such as custom post types belong in a plugin, so they still work after a theme switch. If your changes grow large enough that the child theme is hard to manage, the Handbook suggests forking the parent into a theme of your own.

Conclusion

A child theme comes down to one folder and a style.css whose Template value matches the parent’s folder name. On classic themes, add enqueue code that fits what the parent loads. On block themes, theme.json and same-named template files do the work. Start by checking which stylesheets your parent enqueues, then add only the files you actually need to change.

FAQs

What is the difference between get_template_directory_uri() and get_stylesheet_directory_uri() in a child theme?

When a child theme is active, get_template_directory_uri() returns the parent theme's directory URL, while get_stylesheet_directory_uri() returns the child theme's directory URL. Use the stylesheet variant for files stored in the child. Since WordPress 4.7, get_theme_file_uri() is often the better choice: it returns the child's copy of a file if one exists and falls back to the parent's file otherwise.

Why did my Customizer settings and menu locations disappear after activating a child theme?

WordPress stores Customizer settings (theme mods) separately for each theme, keyed to the active theme's folder name, so a child theme starts with its own empty set and does not inherit the parent's. Your menus still exist, but you have to assign them to menu locations again and re-enter or import the other settings. The parent's settings stay in the database and come back if you switch to the parent.

What happens to a template file copied into a child theme when the parent theme updates?

The child's copy stays exactly as you saved it, and WordPress keeps using it in place of the parent's updated file. Any bug fixes, security patches or markup changes the parent makes to that file never reach your override. After each parent update, compare your overridden files with the new parent versions and merge in what you need. Override as few files as possible to keep this manageable.

Can I create a child theme for a block theme without writing code?

Yes. The official Create Block Theme plugin on WordPress.org has a Create Child Theme option. It generates a child of the active block theme, such as Twenty Twenty-Four, and writes the changes you made in the Site Editor into the child's files. The plugin is built for block themes, so a child of a classic parent still needs the style.css and functions.php setup described above.

DevTools for the frontend

Gain Debugging Superpowers

Unleash the power of session replay to reproduce bugs, track slowdowns and uncover frustrations in your app. Get complete visibility into your frontend with OpenReplay — the most advanced open-source session replay tool for developers.

Star on GitHub12k

We use cookies to improve your experience. By using our site, you accept cookies.