While this isn’t affecting a lot of people now, it will be in the future. Especially if you use well-supported themes.

Somewhere in version 2.8 or 2.9, WordPress started supporting Theme Updates. In the same way that it supports automatic plugin updates from the plugin repository, a theme developer can now make updates to their theme in the themes repository, and you can upgrade it directly from the WordPress interface.

This is a great thing. Theme developers can fix problems, add features, and have it easy for the users to get those changes right away.

Unfortunately, the theme has historically been the user’s playground. Themes are frequently modified by the user directly. Whether it be for looks or for adding code to be used by plugins or whatever, the theme you’re using is very probably not the theme you downloaded. So upgrading will blow away your changes. Thus, most people are disinclined to upgrade their themes.

The way to avoid this is with a child theme. Child themes derive from another theme, called the parent theme. A child theme, by default, looks exactly like the parent. Then you make your changes to the child, and those changes are used on the site. The parent remains untouched. So, when you upgrade the parent theme, the changes you made don’t go anywhere. They stay right where they are.

So let’s dive right in:

How to Make a Child Theme

First, obviously, install the parent theme. Take note of what directory name it goes into. You can find this on the Theme’s screen, it will tell you what directory each theme is in. The new default theme in 3.0 is “twentyten”. So let’s use that one as our parent.

Now, create a new directory in your /wp-content/themes directory. This is where we’ll put our child theme. Let’s call it “mytheme”.

In the mytheme directory, create a new style.css file. Put this in it:

/*
Theme Name: My Theme
Template: twentyten
*/
@import url('../twentyten/style.css');

Finally, load up WordPress and go activate your new “My Theme” theme. You’ll notice that WordPress tells you both what directory your child theme is in and what directory its parent is located in.

Now you’re running on a child theme. It doesn’t have any changes in it, so it looks exactly like the twentyten theme does, but still, we’re running it.

How to Change Things

Let’s say I wanted to change the color of the post titles to, say, green. A silly change, but it illustrates the point.

Normally, I’d go edit the theme, find wherever the color of the text is defined, and change it or add to it to make the titles change in the way I want. In this case, I do the same thing, but I modify the child theme, and I do it in a way that overrides the specificity of the parent’s CSS code.

To do this, I add this code to mytheme’s style.css file:

#content h2.entry-title a {
   color: green;
}

Why that change? Well, I looked at the parent theme and found that “#content .entry-title a” was what it used to define the color of the post title links. To override that, I need to be more specific.

Specificity is a difficult concept for some people, but basically it breaks down to this: When the browser is parsing the CSS, more specific rules take precedence over less specific rules.

In my case I needed to be more specific than “#content .entry-title a“. By adding the h2 to the .entry-title rule, I achieve that because h2.entry-title only will affect h2’s with the entry-title class, while just .entry-title can affect any tag on the page with that class.

The fact that only the h2’s on my page have .entry-title is irrelevant. The HTML doesn’t actually matter in regards to specificity. A rule is more specific based on what it can affect, not on what it actually affects.

So by making my rule more specific, I can override the color of those title’s in my own CSS file separately, and without changing anything about the parent theme.

Overriding Templates

Child themes are not limited to overriding only styling, although in many cases that may be the only customization you need. Best to stick with the rule of the minimum; try to make the most minimal change you can make to accomplish what you want to accomplish. But if you do want to change the way some of the templates work, you can do that too.

All you have to do is to copy the specific template file you want to alter from the parent theme into the child theme’s directory, then make your changes. The way WordPress works is when it looks for some template file, it looks in the child theme first, then it goes to the parent theme if the file it wants isn’t there.

Note that you’re not limited to overriding existing files in the parent. The entire Template Hierarchy applies to child themes too, so if you want to define a category.php file for Category Templates, and the parent theme doesn’t have that file, then you can create a new one in your child and it will be used. You will probably still want to start out with some existing template from the parent though, so look at the Template Hierarchy to see which template the parent is using for your case. The index.php is the usual suspect in these cases, so you can probably just copy that to the child theme and rename it to the template file you want it to be.

Overriding Functions

One exception to the overriding mechanism of child themes has to do with the functions.php file. In a child theme situation, both functions.php files from both themes are loaded. This is necessary because elements of your parent theme might require pieces of the functions.php file to be loaded. This can make overriding functions in the parent theme tricky unless it’s written to allow you to do just that.

The key to this is that the functions.php file of the child theme is loaded first. So if the parent theme is written in a manner WordPress calls “pluggable“, then you can override those functions.

In the twentyten theme’s functions.php file, several of the functions are defined like this:

if ( ! function_exists( 'twentyten_admin_header_style' ) ) :
function twentyten_admin_header_style() {
...
}
endif;

That is a pluggable function. Basically, before it defines the function, it checks to see if the function is already defined. If the parent theme uses this mechanism, then a child theme can override this function by simply defining a function of the same name first. So all you have to do to change it is to copy the function into your child’s functions.php file and make your changes. When the parent theme loads, it will see that you already defined the function and continue on.

Another way to override things is through the normal WordPress action and filter hook mechanisms. If a theme’s functions.php file uses those, then you can simply add your own hooked functions with different names. However, because the child’s functions.php file loads first, it can’t actually unhook things defined by the parent theme.

The way to get around this is to use the after_setup_theme action hook. This action is called immediately after both functions.php files are loaded.

For example, if I look at the twentyten theme, I’ll find this:

function twentyten_excerpt_length( $length ) {
	return 40;
}
add_filter( 'excerpt_length', 'twentyten_excerpt_length' );

I don’t want that, I want my excerpts to be 55 words instead. So I add this to my functions.php file:

function my_excerpt_length( $length ) {
	return 55;
}
add_filter( 'excerpt_length', 'my_excerpt_length' );

Whoops! It doesn’t work. Why not? Because I didn’t remove twentyten’s hook, and its filter is overriding mine. So I have to add this too:

function my_undo_hooks( $length ) {
	remove_filter( 'excerpt_length', 'twentyten_excerpt_length' );
}
add_action( 'after_setup_theme', 'my_undo_hooks' );

And then it works. I’ve added my filter, and removed the one in twentyten. Voila.

Programmer Note

In a WordPress theme you’ll often find references to “stylesheet_uri” and “stylesheet_dir”. You’ll also find references to “template_uri” and “template_dir”. Normally, these are the same thing. In a child theme case, they’re not. Stylesheet refers to the child theme. Template refers to the parent theme. This is an important distinction that you’ll want to make when creating your theme. You should probably use stylesheet in most cases, except for when you need to specifically refer to the parent (for image URL creation and such).

Conclusion

Child themes are a very good way to survive theme upgrades, and if you’re using a well supported theme, these are likely to become more common. It’s still perfectly safe to modify your theme directly (except for twentyten! Normal WP upgrades overwrite twentyten), but it’s always a good idea to keep your customizations separate. They’re a lot easier to manage that way.

Shortlink:

29 Comments

  1. Great tutorial Otto! It would be nice if WordPress provided better guidelines like this for theme developers. Like you said, “theme has historically been the user’s playground” which is definitely true.

    We started supporting child themes a few months back and it has really made our customers happy. No more blowing away their changes when a theme update comes out.

    Question for you. It’s easy to notify users when a theme gets updated since it’s in the WP theme repository. How could one code something like that for a non-theme repository?

  2. I followed your directions but WP says the theme is broken because it expects a template in addition to the stylesheet? Do I copy all of the twentyten template files into my child theme directory except for the stylesheet?

    • No. You simply left out the Template: line in your stylesheet. A child theme has to have a parent theme.

      It’s also possible that you’re using the wrong kind of carriage returns. Make sure that if you uploaded the file via FTP that you put it in Text mode first, to do the proper conversion.

  3. I’m trying to do this locally on my Mac with a MAMP WP install. Things look right inside WP-
    “The template files are located in /themes/twentyten. The stylesheet files are located in /themes/mytheme. My Theme uses templates from Twenty Ten. Changes made to the templates will affect both themes.”
    -but the connection to the css file is broken. I also tried using a complete url for the @import location.
    Is there some reason I can’t configure this locally?

  4. This was just what I needed – thanks!

  5. Thanks Otto!
    I was stock with a filter that was overriden by the default themes filter. Thanks for showing how to remove a filter from the parent theme.

  6. […] then override it with anything you add in your child them style.css file. That was a mouth full. Otto on WordPress has a very good and detailed […]

  7. Quite extensive. Thanks for the details.

  8. […] Tech Ninja Yes, it's actually quite simple. I wrote a brief tutorial on how to do it here:http://ottopress.com/2010/wordpr…It only goes into the very basics, but if you know how to create a theme, you should be able to pick […]

  9. Fantastic resource. I searched so long for this exact solution as I was writing a custom filter but nothing new was happening. So glad I found this page!

  10. Thank you so much. This was exactly the info I needed.

  11. […] team follower Yes, it's actually quite simple. I wrote a brief tutorial on how to do it here:http://ottopress.com/2010/wordpr…It only goes into the very basics, but if you know how to create a theme, you should be able to pick […]

  12. Hi,

    I’ve been pulling my hair out trying to work out why this doesn’t work – the widgets override is working fine, but the ‘OVERRIDE EXCERPT READ MORE LINK’ isn’t. Do you know why? I assume it’s not possible to have multiple instances of add_action( ‘after_setup_theme’, ‘function_name’) either right?

    Thanks,

    osu

    function twentyten_child_theme_setup() {

    // OVERRIDE SIDEBAR GENERATION!
    function osu_twentyten_widgets_init() {
    // Siedbar 1, located on LHS sidebar
    register_sidebar( array(
    'name' => __( 'Primary Widget Area', 'twentyten-child' ),
    'id' => 'primary-widget-area',
    'description' => __( 'The primary widget area where the navigation goes', 'twentyten-child' ),
    'before_widget' => '',
    'after_widget' => '',
    'before_title' => '',
    'after_title' => '',
    ) );
    // Area 2, located on RHS sidebar
    register_sidebar( array(
    'name' => __( 'Secondary Widget Area', 'twentyten-child' ),
    'id' => 'secondary-widget-area',
    'description' => __( 'The secondary widget area', 'twentyten-child' ),
    'before_widget' => '',
    'after_widget' => '',
    'before_title' => '',
    'after_title' => '',
    ) );
    }
    remove_action( 'widgets_init', 'twentyten_widgets_init' );
    add_action( 'widgets_init', 'osu_twentyten_widgets_init' );

    // OVERRIDE EXCERPT READ MORE LINK
    function osu_readon_link() {
    return ' ' . __( 'Read on →', 'twentyten-child' ) . '';
    }
    function osu_auto_excerpt_more( $more ) {
    return ' …' . osu_readon_link();
    }
    remove_filter( 'excerpt_more', 'twentyten_auto_excerpt_more' );
    add_filter( 'excerpt_more', 'osu_auto_excerpt_more' );

    }
    add_action( 'after_setup_theme', 'twentyten_child_theme_setup' ); /* IMPORTANT: Run the code after theme setup! */

  13. […] to do this, you can view the answers on How to override parent functions in child themes or read Otto’s ProTip on child […]

  14. […] this tutorial, well written and lots of great resources (tools, software, references at the end.) WordPress Protip: Child Themes Another really good tutorial, with an intro to overriding with action and filter hooks. The Codex […]

  15. Thank you so much for clearing this up for me with your very easy to follow tutorial.

  16. Thanks so much for this – as a beginner, I find it difficult to wade through the jargon that seems irresistible to most tutorial writers, but this one was nicely light on the jargon 🙂

    Quick question to see if I’m understanding what you’re doing.

    I would like to translate the word “Home” in my navigation bar to Chinese (using a child theme I’ve called MGCK).

    I basically took what was in the parent (twenty eleven) functions.php and named it with my own name:

    function mgck_page_menu_args( $args ) {
    	$args['show_home'] = '主页';
    	return $args;
    }

    Then I cancel this function in the parent theme like this?

    function translate_home_nav ( $args ) {
    	remove_filter( 'show_home', 'twentyeleven_page_menu_args' );
    }
    add_action( 'after_setup_theme', 'translate_home_nav' );
  17. Great tutorial Otto! My main issue was overriding parent’s funtions, which I’ll use your method. We depend of theme developers.

  18. Hi to everyone this is great tutorial but in my case things are complicated.

    i have this:

    function auctionTheme_slider_post_function()
    {
    ?>

    <a href="”><img width="150" height="110" class="image_class3"
    src="” alt=”” />

    <a href="” rel=”bookmark” title=”Permanent Link to “>

    <a href="” class=”buttonlight”>

    <a href="”><img width="140" height="190" class="image_class3"
    src="” alt=”” />

    <a href="” rel=”bookmark” title=”Permanent Link to “>

    <a href="” class=”buttonlight”>

    <?php
    }

    add_filter('auctionTheme_get_post', 'auctionTheme_get_post_function',0,1);
    add_filter('auctionTheme_get_post_grid', 'auctionTheme_get_post_function_grid',0,1);

    the only thing i want to change is the width and heigh if you notice.Can please anyone tell me what do i have to do? Thank you very much in advance.

  19. As a beginner. I need to know that if My parent theme function.php i need to customize a function in the end there is no add_action or add_fillter so how can i customize the theme in my child function.php ?

  20. Thx for your helpful Tutorial. Especially the overwriting from the parent theme function was what I was looking for.
    Greetz Mike

  21. Great tutorial, many thanks!
    In your example about Overriding Functions, what would then be the final code at child theme functions?

    function my_undo_hooks( $length ) {
        remove_filter( 'excerpt_length', 'twentyten_excerpt_length' );
    }
    add_action( 'after_setup_theme', 'my_undo_hooks' );
    
    function my_excerpt_length( $length ) {
        return 55;
    }
    add_filter( 'excerpt_length', 'my_excerpt_length' );

    Is that correct?

    Thanks again!

Leave a Reply

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

Need to post PHP code? Wrap it in [php] and [/php] tags.