Child Themes

A child theme overrides a parent's templates and functions without touching its files, so the parent can still be updated.

Syntaxstyle.css header: Theme Name: My Child / Template: parent-theme-folder

A 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

Example · php
<?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.

Example · css
/*
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.

Example · php
<?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.

Example · php
<?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

  • Be the first to comment on this lesson.