
I've watched countless clients lose their customizations after updating a WordPress theme. It happens more often than you'd think—hours of CSS tweaks, template modifications, and function additions wiped out in a single click. Child themes prevent this entirely. In this guide, I'll show you exactly how to create and use child themes to customize WordPress safely and permanently.
What Is a WordPress Child Theme?
A child theme is a theme that inherits all the functionality, features, and styling of another theme (called the parent theme). It lets you modify or extend the parent theme without touching its files directly.
When WordPress loads a page, it checks the child theme first. If a template file exists in the child theme, WordPress uses that version. If not, it falls back to the parent theme's version. This inheritance model is what makes child themes so powerful.
Why You Need a Child Theme
- Update-safe customizations: Parent theme updates won't overwrite your changes
- Easy rollback: Delete the child theme file and the parent's version takes over
- Organized code: Your custom code lives in one clearly separated location
- Learning tool: Experiment with theme development without breaking a working site
- Client projects: Deliver customizations that survive theme updates
When You Don't Need a Child Theme
Not every customization requires a child theme. Skip it if you're:
- Only adding custom CSS via the WordPress Customizer (Appearance → Customize → Additional CSS)
- Using a site-specific plugin for functionality like custom post types
- Working with a theme that has its own override system (like some FSE themes)
- Building a completely custom theme from scratch
Creating Your First Child Theme
The process requires exactly two files: style.css and functions.php. Here's the step-by-step approach.
Step 1: Create the Child Theme Directory
Create a new folder in wp-content/themes/. The convention is to name it after the parent theme with -child appended:
wp-content/themes/
├── twentytwentyfive/ ← Parent theme
├── twentytwentyfive-child/ ← Your child theme
│ ├── style.css
│ └── functions.php
Step 2: Create the style.css File
The style.css file must contain a specific header comment that tells WordPress this is a child theme and identifies its parent:
/*
Theme Name: Twenty Twenty-Five Child
Theme URI: https://yoursite.com
Description: Custom child theme for Twenty Twenty-Five
Author: Your Name
Author URI: https://yoursite.com
Template: twentytwentyfive
Version: 1.0.0
License: GNU General Public License v2 or later
License URI: https://www.gnu.org/licenses/gpl-2.0.html
Text Domain: twentytwentyfive-child
*/
/* Your custom styles go below this line */
The critical field is Template. It must exactly match the parent theme's directory name (not the display name). This is case-sensitive.
Step 3: Create the functions.php File
The functions.php file handles enqueueing the parent theme's styles. This is the correct way to do it:
<?php
/**
* Twenty Twenty-Five Child Theme Functions
*/
add_action('wp_enqueue_scripts', 'child_theme_enqueue_styles');
function child_theme_enqueue_styles() {
// Enqueue parent theme stylesheet
wp_enqueue_style(
'parent-style',
get_template_directory_uri() . '/style.css'
);
// Enqueue child theme stylesheet (loads after parent)
wp_enqueue_style(
'child-style',
get_stylesheet_directory_uri() . '/style.css',
array('parent-style'),
wp_get_theme()->get('Version')
);
}
Important directory functions:
get_template_directory_uri()— Always points to the parent themeget_stylesheet_directory_uri()— Points to the active theme (child theme when active)get_template_directory()— Parent theme's server pathget_stylesheet_directory()— Child theme's server path
Step 4: Activate the Child Theme
Go to Appearance → Themes in your WordPress admin, and you'll see your child theme listed. Click "Activate." Your site should look exactly the same as before since the child theme inherits everything from the parent.
Customizing Styles
The most common use of child themes is adding custom CSS. Any styles in your child theme's style.css load after the parent's styles, so they take precedence.
Overriding Parent Styles
/* Override the site title font size */
.site-title {
font-size: 2.5rem;
letter-spacing: -0.02em;
}
/* Change the primary link color */
a {
color: #2563eb;
}
a:hover {
color: #1d4ed8;
}
/* Customize the header background */
.site-header {
background-color: #0f172a;
padding: 1.5rem 0;
}
/* Modify the footer layout */
.site-footer {
background-color: #1e293b;
color: #e2e8f0;
padding: 3rem 0;
}
Adding Responsive Styles
/* Custom responsive adjustments */
@media (max-width: 768px) {
.site-title {
font-size: 1.75rem;
}
.entry-content {
padding: 0 1rem;
}
.widget-area {
display: none;
}
}
@media (max-width: 480px) {
.site-header {
padding: 1rem 0;
}
.nav-menu {
flex-direction: column;
}
}
Using CSS Custom Properties
Modern parent themes often use CSS custom properties (variables), which makes overriding much cleaner:
/* Override theme design tokens */
:root {
--wp--preset--color--primary: #2563eb;
--wp--preset--color--secondary: #7c3aed;
--wp--preset--color--background: #f8fafc;
--wp--preset--color--foreground: #0f172a;
--wp--preset--font-size--large: 1.75rem;
--wp--custom--spacing--outer: 2rem;
}
This approach works well with block themes and Full Site Editing (FSE) themes that rely heavily on CSS custom properties.
Overriding Template Files
To customize a template's HTML structure, copy the file from the parent theme into your child theme and modify it there.
How Template Override Works
- Find the template file you want to modify in the parent theme directory
- Copy it into your child theme at the same relative path
- Edit the copy in your child theme
Parent theme:
twentytwentyfive/templates/single.html
Child theme override:
twentytwentyfive-child/templates/single.html
WordPress will automatically use the child theme's version.
Classic Theme Template Override Example
For classic PHP themes, the process is identical:
Parent: twentytwentyfive/single.php
Child: twentytwentyfive-child/single.php
Here's an example of overriding single.php to add a custom author box:
<?php
/**
* Template for displaying single posts
* Overrides parent theme's single.php
*/
get_header();
?>
<main id="primary" class="site-main">
<?php
while (have_posts()) :
the_post();
get_template_part('template-parts/content', 'single');
// Custom author box
?>
<div class="custom-author-box">
<div class="author-avatar">
<?php echo get_avatar(get_the_author_meta('ID'), 80); ?>
</div>
<div class="author-info">
<h4><?php the_author(); ?></h4>
<p><?php echo get_the_author_meta('description'); ?></p>
<a href="<?php echo get_author_posts_url(get_the_author_meta('ID')); ?>">
View all posts
</a>
</div>
</div>
<?php
// Post navigation
the_post_navigation(array(
'prev_text' => '← %title',
'next_text' => '%title →',
));
// Comments
if (comments_open() || get_comments_number()) {
comments_template();
}
endwhile;
?>
</main>
<?php
get_sidebar();
get_footer();
Template Parts Override
You can also override specific template parts without copying the entire page template:
Parent: twentytwentyfive/template-parts/content.php
Child: twentytwentyfive-child/template-parts/content.php
This is more surgical—you only override the specific component you need to change.
Adding Custom Functionality
The child theme's functions.php runs in addition to the parent's functions.php (it doesn't replace it). This means you can add new functions and override "pluggable" functions.
Adding Widget Areas
// Register a custom sidebar
add_action('widgets_init', 'child_register_sidebars');
function child_register_sidebars() {
register_sidebar(array(
'name' => 'Custom CTA Sidebar',
'id' => 'cta-sidebar',
'description' => 'Appears on landing pages',
'before_widget' => '<section id="%1$s" class="widget %2$s">',
'after_widget' => '</section>',
'before_title' => '<h3 class="widget-title">',
'after_title' => '</h3>',
));
}
Adding Custom Navigation Menus
// Register an additional navigation menu
add_action('after_setup_theme', 'child_register_menus');
function child_register_menus() {
register_nav_menus(array(
'footer-menu' => 'Footer Navigation',
'social-menu' => 'Social Links Menu',
));
}
Removing Parent Theme Features
Sometimes you need to undo something the parent theme does. Use remove_action() or remove_filter() with the correct priority:
// Remove parent theme's custom header support
add_action('after_setup_theme', 'child_remove_parent_features', 11);
function child_remove_parent_features() {
// Remove parent theme's header image support
remove_theme_support('custom-header');
// Remove parent theme's specific action (must match priority)
remove_action('wp_head', 'parent_theme_custom_meta', 10);
}
// Override parent theme's excerpt length
add_filter('excerpt_length', 'child_custom_excerpt_length', 999);
function child_custom_excerpt_length($length) {
return 25;
}
The priority 11 in after_setup_theme ensures the child theme's function runs after the parent's (which typically uses priority 10).
Overriding Pluggable Functions
Some parent themes define functions as "pluggable" using function_exists() checks:
// In parent theme:
if (!function_exists('theme_posted_on')) {
function theme_posted_on() {
echo '<time>' . get_the_date() . '</time>';
}
}
// In child theme functions.php (loaded first):
function theme_posted_on() {
echo '<time datetime="' . get_the_date('c') . '">';
echo get_the_date('F j, Y') . ' at ' . get_the_time('g:i a');
echo '</time>';
echo ' by <span class="author">' . get_the_author() . '</span>';
}
Since the child theme's functions.php loads before the parent's, the function_exists() check in the parent will find your version already defined and skip its own.
Working with Block Themes and FSE
WordPress Full Site Editing (FSE) themes use a different template system based on HTML files and theme.json. Child themes work with FSE but with some differences.
Overriding theme.json
Create a theme.json file in your child theme to override the parent's design settings:
{
"$schema": "https://schemas.wp.org/trunk/theme.json",
"version": 3,
"settings": {
"color": {
"palette": [
{
"slug": "primary",
"color": "#2563eb",
"name": "Primary"
},
{
"slug": "secondary",
"color": "#7c3aed",
"name": "Secondary"
}
]
},
"typography": {
"fontFamilies": [
{
"fontFamily": "Inter, sans-serif",
"slug": "body-font",
"name": "Body Font"
}
],
"fontSizes": [
{
"slug": "small",
"size": "0.875rem",
"name": "Small"
},
{
"slug": "medium",
"size": "1rem",
"name": "Medium"
},
{
"slug": "large",
"size": "1.5rem",
"name": "Large"
}
]
},
"spacing": {
"units": ["px", "em", "rem", "%", "vw"]
}
},
"styles": {
"color": {
"background": "#f8fafc",
"text": "#0f172a"
},
"elements": {
"link": {
"color": {
"text": "#2563eb"
},
":hover": {
"color": {
"text": "#1d4ed8"
}
}
}
}
}
}
The child theme's theme.json is merged with the parent's, so you only need to include the values you want to change.
Overriding Block Templates
FSE templates use HTML files in the templates/ directory:
twentytwentyfive-child/
├── templates/
│ ├── single.html ← Overrides parent's single post template
│ └── page.html ← Overrides parent's page template
├── parts/
│ └── header.html ← Overrides parent's header template part
├── style.css
├── functions.php
└── theme.json
Common Child Theme Mistakes
Avoid these pitfalls that trip up even experienced developers:
Mistake 1: Importing Parent Styles with @import
/* DON'T do this - it's slow and creates render-blocking requests */
@import url('../twentytwentyfive/style.css');
Always use wp_enqueue_style() in functions.php as shown earlier. The @import method adds an extra HTTP request and blocks rendering.
Mistake 2: Wrong Template Value in style.css
/* WRONG - using display name */
Template: Twenty Twenty-Five
/* CORRECT - using directory name */
Template: twentytwentyfive
The Template field must match the parent theme's folder name exactly.
Mistake 3: Not Matching Parent Hook Priorities
// If parent registers something at priority 15:
add_action('wp_enqueue_scripts', 'parent_enqueue', 15);
// You must match or exceed that priority to remove it:
remove_action('wp_enqueue_scripts', 'parent_enqueue', 15); // Correct
remove_action('wp_enqueue_scripts', 'parent_enqueue'); // Won't work (defaults to 10)
Mistake 4: Copying Too Many Template Files
Only copy template files you actually need to modify. Copying every template from the parent theme into the child theme means you won't get template improvements from parent theme updates.
Mistake 5: Hardcoding Parent Theme Paths
// WRONG - hardcoded path
$image = '/wp-content/themes/twentytwentyfive/images/logo.png';
// CORRECT - using WordPress functions
$image = get_template_directory_uri() . '/images/logo.png';
Performance Considerations
Child themes add minimal overhead, but keep these points in mind:
- Additional stylesheet: The child theme's CSS file is an extra HTTP request. Keep it small or inline critical styles
- Template loading: WordPress checks the child theme directory first, adding negligible file system lookups
- Function loading order: Both
functions.phpfiles load, so avoid duplicating functionality - Image assets: Store large assets in the child theme only if the parent doesn't have them
For most sites, the performance impact of a child theme is negligible compared to the maintainability benefits.
Child Theme Development Workflow
Here's the workflow I use for client projects:
- Install and activate the parent theme to verify it works correctly
- Create the child theme with the two required files
- Activate and test to confirm the site looks unchanged
- Add customizations incrementally, testing after each change
- Version control the child theme with Git (ignore the parent theme)
- Document overrides in a README for future developers
# Initialize Git in the child theme directory
cd wp-content/themes/twentytwentyfive-child
git init
git add .
git commit -m "Initial child theme setup"
FAQ
Can I use a child theme with any WordPress theme?
Yes, child themes work with any properly coded WordPress theme. Both classic PHP themes and modern block/FSE themes support child themes. The only requirement is that the parent theme is installed (it doesn't need to be active).
Will my child theme break if the parent theme is updated?
No—that's the entire point of child themes. Your child theme files are completely separate from the parent theme. When the parent updates, your customizations remain untouched. The only risk is if the parent theme removes a function or hook your child theme depends on, which is rare with reputable themes.
How do I convert an existing customized theme to use a child theme?
Create a new child theme, then move your custom code from the parent theme's files into the corresponding child theme files. For functions.php, copy only your custom functions (not the parent's original functions). For template files, copy only the files you've modified. For CSS, move your custom styles to the child theme's style.css.
Can I have a child theme of a child theme (grandchild)?
WordPress does not support grandchild themes. A child theme's Template field must reference a parent theme, not another child theme. If you need multiple levels of customization, use conditional logic in a single child theme or consider a site-specific plugin for functionality.
Should I put custom functionality in the child theme or a plugin?
Use the child theme for presentation-related customizations: styles, template overrides, and theme-specific features. Use a plugin for functionality that should persist regardless of the active theme: custom post types, shortcodes, API integrations, and business logic. If switching themes would break the feature, it belongs in a plugin.
Child themes are a fundamental WordPress development skill that protects your work and keeps client sites maintainable. Start using them on every project, even if you're only making minor CSS changes. Have questions? Feel free to reach out.

Fysal Yaqoob
Expert WordPress & Shopify Developer
Senior full-stack developer with 10+ years experience specializing in WordPress, Shopify, and headless CMS solutions. Delivering custom themes, plugins, e-commerce stores, and scalable web applications.
Practice: WordPress Developer Games
Take a break and level up your WordPress skills with our interactive developer games!


