Don’t edit child themes – use grandchild themes!

Child themes are the easiest way to style WordPress sites. Rather than create a site from scratch, you can create a theme that shares most of its code and styling with a parent theme. The benefits of creating a child theme instead of editing the main theme is that if the main theme gets updates, none of your changes are lost.

But what if you need to modify a child theme? If you’re working with a Framework, like Genesis, it’s very likely you are already using a child theme – and editing that brings about all the disadvantages of editing a parent theme – you lose your changes if the theme is ever updated.

The solution is surprisingly simple. Instead of editing the child theme, create a grandchild theme. It’s very similar to creating a child theme, except you do it via a plugin. You add your custom functions to the plugin, just as you normally would in functions.php (though remember your plugin will be called much earlier than functions.php, so you’ll need to make sure that any code in your plugin only runs when an action is fired). Use the wp_register_style and wp_enqueue_style functions to add your CSS (by default a grandchild theme will add your CSS to the CSS of the parent or child theme, but you can change this behaviour by using the wp_dequeue_style function). Finally filter the result of the get_query_template function to control which PHP files are executed when a page is requested.

A typical grandchild theme might look like this:

/*
Plugin Name: Grandchild Theme
Plugin URI: http://www.wp-code.com/
Description: A WordPress Grandchild Theme (as a plugin)
Author: Mark Barnes
Version: 0.1
Author URI: http://www.wp-code.com/
*/

// These two lines ensure that your CSS is loaded alongside the parent or child theme's CSS
add_action('wp_head', 'wpc_theme_add_headers', 0);
add_action('init', 'wpc_theme_add_css');

// This filter replaces a complete file from the parent theme or child theme with your file (in this case the archive page).
// Whenever the archive is requested, it will use YOUR archive.php instead of that of the parent or child theme.
add_filter ('archive_template', create_function ('', 'return plugin_dir_path(__FILE__)."archive.php";'));

function wpc_theme_add_headers () {
	wp_enqueue_style('grandchild_style');
}

function wpc_theme_add_css() {
	$timestamp = @filemtime(plugin_dir_path(__FILE__).'/style.css');
	wp_register_style ('grandchild_style', plugins_url('style.css', __FILE__).'', array(), $timestamp);
}

// In the rest of your plugin, add your normal actions and filters, just as you would in functions.php in a child theme.

The two actions to add the CSS should be familiar to you (although you may also want to read this post). The filter is the important function. You can create as many of these as you wish, for different pages. Supported pages include:

  • index
  • 404
  • archive
  • author
  • category
  • tag
  • taxonomy
  • date
  • home
  • front_page
  • page
  • paged
  • search
  • single
  • attachment

If you want more control before deciding which template file to give to WordPress, create a proper function and insert your logic code into it:

add_filter ('archive_template', 'emw_archive_template', 10, 1);

function wpc_archive_template ($suggested_templates) {
	// Your logic here
	if ($test_passed)
		return $template_file;
	else
		return $alternative_template_file;
}

Comments

  1. Mark, your author URI is incorrect

  2. In the last code snippet shouldn’t the callback function be wpc_archive_template in the add_filter call?

    • Mark Barnes says:

      No, it’s correct. The callback function is supplied by the ‘function’ function, if that makes sense.

  3. I think the filter name is actually “frontpage_template”, rather than “front_page_template”.

    Also. there are other types of templates that need to be overridden too, like header/footer/sidebar, loop templates included with get_template_part(), the comments template, the search form, etc. Some of them have their own filters (like “get_search_form” — which expects a string of HTML, not a filename), but so far I haven’t found filters for some of the others.

  4. And here we see the problem with theme frameworks like Genesis. WordPress doesn’t do proper grandchild themes (nor should it) so we hack presentation in to a plugin.

    Themes are for presentation. Plugins are for extending function.

    • I agree that theme shops shouldn’t be selling child themes, and that there are good reasons for WP to not support grandchild themes natively, and that presentation doesn’t belong in plugins, but I also think it’s important to not be overzealous about these kinds of things.

      Sometimes you have to work with what you have, even if it’s not an ideal situation; and sometimes what you have is a client whose site was built on a parent/child theme combo like Genesis, and using a technique like this is the least-bad way to maintain the site until it can be rebuilt properly.

      • using a technique like this is the least-bad way to maintain the site until it can be rebuilt properly.

        No. Build it properly in the first place. If you are using a child theme for a system like Genesis, then you should fork it rather than try to hack your presentation into a plugin. Throw the current version of the child theme into Git or SVN, then create a dev branch to contain your customizations. If (and this is a big “if” since most won’t) the child theme is update, you can create a diff between the original and the new version using your VCS and apply the diff to your branch.

        Is it more work? Yes. Is it an ugly hack using a plugin? No. Work with what you have, but don’t advocate a system like this that introduces a third level of moving parts into the theme’s presentation.

        • Actually, that is a good idea. Normally I prefer extending to forking, but in this case I think you’re right. Using a plugin adds more complexity and points of failure, so the benefits of avoiding a fork are outweighed.

          There may still be other use cases where the plugin technique is appropriate, but for this kind of situation I agree with you.

  5. Can you check your spam? I left a long comment on here a week or two ago and it still hasn’t shown up

  6. I’d rather call this as functionality plugin. A theme is a theme :)

  7. While this is a solution it is quite ugly and why frameworks like Genesis need re-thinking. I use a lot of Genesis themes but the fact you cannot child theme any of the themes you get for your money is it’s worst feature.

    I developed my own framework for the themes I have published (themeloom.com) that exists as a folder inside every theme, which means it has all the hooks and solid base that a framework can provide, but all themes can still have children.

  8. I’m with Eric; this goes against WordPress best practice guidelines. I’d go with Eric’s suggestion or I’d add a one-liner to functions.php that’d enqueue a custom CSS file

  9. Andrew Moore says:

    Hi Mark, I’m quite new to website designing but mainly enjoy css and don’t know php very well.
    I’m creating a wordpress multisite website and I could really do with this grandchild setup as I will have a lot of child themes under the genesis framework. It is however a bit concerning this goes against wordpress best practice guidelines. Would it be possible to, say for example if I had the header.php in each child theme – only put:

    then create a ‘default’ directory, then put header.php in that default directory so I can put all my code in there so all child themes will share the code. And do this same process for all child themes- so just putting php include in all the child theme php files, then put the the code in the php files in the created ‘default directory’. If this doesn’t work i’ll probably decide to edit the genesis framework and just replace the files after each upgrade.

Trackbacks

  1. [...] Child Theme erstellt wird, ein “Child of a Child” erzeugt werden. Einen Ausweg zeigt der Beitrag “WordPress Grandchildren Themes” mit der Anregung, Enkel-Themen als Plugin zu implementieren. Share [...]

  2. […] If a user wants to modify your child theme, it has to create… wait for it… a grandchild theme. And now we have files for our themes living in three parallel directories. Let’s say a […]

  3. […] cannot create a grandchild theme even though Smashing Magazine wrongly states this. However, Mark Barnes and AppThemes write a great tutorials on how to create a grandchild […]

  4. […] Mark Barnes – Don’t edit child themes – use grandchild themes! […]

Speak Your Mind

*