Child Themes
A child theme overrides a parent's templates and functions without touching its files, so the parent can still be updated.
style.css header: Theme Name: My Child / Template: parent-theme-folderA child theme is a theme whose style.css header carries a Template field naming another theme's directory. WordPress then activates both: the child is the stylesheet, the parent is the template. Editing a parent theme directly means losing every change on its next update; a child theme is how you avoid that.
What a child needs
A directory, and a style.css with Theme Name and Template. functions.php is optional.
How overriding works
Template files are resolved child-first: put single.php or template-parts/content.php in the child at the same relative path and it replaces the parent's. functions.php is the exception — it is not replaced. Both files load, the child's first, which is what makes the parent's function_exists() guards work.
Loading the stylesheets
The parent's CSS is not loaded automatically. If the parent enqueues its own stylesheet, enqueue the child's with the parent's handle in $deps so yours cascades after. If the parent does not, enqueue both. Never use CSS @import — it blocks rendering until the first file has parsed.
Path functions
get_stylesheet_directory() points at the child, get_template_directory() at the parent. Using the wrong one is the most common child-theme bug.
Example
<?php
/**
* Child theme functions.php.
*
* Loaded BEFORE the parent's functions.php, so anything the parent wraps in
* if ( ! function_exists() ) can be pre-empted by declaring it here.
*/
defined( 'ABSPATH' ) || exit;
function mychild_enqueue_styles() {
/*
* Look up the handle the PARENT registered for its own stylesheet — open
* its functions.php and read the wp_enqueue_style() call. Guessing the
* handle means the dependency is ignored and the file loads twice.
*/
$parent_handle = 'parenttheme-style';
wp_enqueue_style(
'mychild-style',
get_stylesheet_uri(), // the CHILD's style.css
array( $parent_handle ), // load after the parent's CSS
wp_get_theme()->get( 'Version' ) // the child's Version header
);
}
add_action( 'wp_enqueue_scripts', 'mychild_enqueue_styles' );
/**
* Override a pluggable parent function. Because this file runs first, the
* parent's guarded definition is skipped entirely.
*/
if ( ! function_exists( 'parenttheme_excerpt_length' ) ) {
function parenttheme_excerpt_length( $length ) {
return 20;
}
}When to use it
- Customising a third-party or premium theme that still receives updates
- Overriding one template of a starter theme without forking the whole thing
- Replacing a parent theme's pluggable function with your own
- Adding site-specific CSS that survives the parent theme's next release
More examples
The child's style.css header
Template must be the parent's directory name exactly — 'twentytwentyfour', not 'Twenty Twenty-Four'. Theme Name and Template are the only two headers that matter functionally; the rest is metadata. Give the child its own Version so wp_get_theme()->get('Version') is a usable cache-buster.
/*
Theme Name: Parent Theme Child
Template: parent-theme
Author: A Developer
Version: 1.0.0
Text Domain: parent-theme-child
License: GPL-2.0-or-later
*/
/* Child overrides. This file is what get_stylesheet_uri() returns. */
.site-title { letter-spacing: -0.02em; }When the parent does not enqueue its own stylesheet
Use this only when you have confirmed the parent loads nothing itself; enqueuing a stylesheet the parent already queued under a different handle downloads it twice. get_parent_theme_file_uri() is the explicit parent-directory counterpart to get_theme_file_uri(), which prefers the child.
<?php
add_action( 'wp_enqueue_scripts', function () {
// Parent CSS first…
wp_enqueue_style(
'parent-style',
get_parent_theme_file_uri( 'style.css' ) // always the PARENT directory
);
// …then the child, depending on it so the cascade order is guaranteed.
wp_enqueue_style(
'child-style',
get_stylesheet_uri(),
array( 'parent-style' ),
wp_get_theme()->get( 'Version' )
);
} );Child-first paths, and the ones that are not
A parent theme should use get_template_directory() for its own includes so a child cannot accidentally shadow them, and get_theme_file_uri() for assets so a child can. In a child theme, get_stylesheet_directory() is almost always the one you want.
<?php
// Child-aware — resolve to the child when the file exists there, else parent.
get_stylesheet_directory(); // /themes/my-child
get_stylesheet_directory_uri();
get_theme_file_path( 'inc/x.php' ); // checks child, falls back to parent
get_theme_file_uri( 'assets/logo.svg' );
get_stylesheet_uri(); // child's style.css
// Always the parent, regardless of the active child.
get_template_directory(); // /themes/parent-theme
get_template_directory_uri();
get_parent_theme_file_path( 'inc/x.php' );
get_parent_theme_file_uri( 'assets/logo.svg' );
// So in a child's functions.php this loads the PARENT's file — usually a bug:
require_once get_template_directory() . '/inc/helpers.php';
// and this loads the child's, which is normally what you meant:
require_once get_stylesheet_directory() . '/inc/helpers.php';
Discussion