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: https://www.wp-code.com/
Description: A WordPress Grandchild Theme (as a plugin)
Author: Mark Barnes
Version: 0.1
Author URI: https://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?

  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.

        • Bill Barnwell says

          I’m interested in this method of managing child theme updates via Github. Can anyone go in to more detail on this? I’ve got a child theme that is not currently available from the developer on Github. I can put the files there in my own repo and create a Dev branch, but I’m unclear as to how you manage theme developer updates without losing your own customizations. Or, does this have to be done via Fork?

  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.

  10. Hi Mark

    I just came across your article and wanted to weigh in. I’ve just developed a new plugin to help with update-safe customizing of framework child themes. I’m a big user of Genesis and pretty much built it out of ‘need’. WP Clips is small (6kb-10kb), flexible, unobtrusive, and allows you to add code using the WordPress editor or via FTP. Would love to hear your thoughts – http://wpclips.net

    Best always
    Jon

  11. I would like tot hank you for this article and the example. I have created grand-child-theme and it saves a lot of time for me. Please go to http://www.wpyui.com and see what I have done with my grandchild themes.

  12. Wow! At last I got a web site from where I be capable of really take
    useful information regarding my study and knowledge.

  13. I’ve been browsing on-line greater thuan 3 hokurs as
    of late, but I never found any attention-grabbing article like yours.

    It’s pretty worth sufficient for me. In my view, if all webmasters and blloggers made just right content materiaal as yoou did, the
    net might be much molre useful than eve before.

  14. Nοt only that sometimes new theme aⅾds new functionality for a website.
    One of thee mooѕt ρⲟpular blogging platforms which might be beіng utilized bby many dіfferent individuals world widde is Word –
    Press. Theey arе used to prоvide certain functionalities to tthe CMSwhich otһerwise
    would call for a development intensive activity.

  15. I have fun with, result in I discovered exactly what I was looking for.

    Youu have ended my four day lengthy hunt!
    God Bless you man. Have a nice day. Bye

  16. We did not know how to change the code for custom integration of the Groovy Mega Menu into Turnkey StoreFront which is already a child theme of Primer. Thanks for the decision!

  17. Hey Guys,

    this works fine, but i have problems to replace the header.php from the child-theme with my grandchild-plugin. This: add_filter (‘get_template_part’, create_function (”, ‘return plugin_dir_path(__FILE__).”header.php”;’)); don’t work – have you an hint for me?

    Kind Regards

  18. where van i get RH grandchild plugin for wordpress ?

  19. nice collection of wordpress themes.

Speak Your Mind

*

This site uses Akismet to reduce spam. Learn how your comment data is processed.