How to create child themes for our Modularity theme for WordPress

Updated on

Building child themes for your WordPress theme is a good way to future-proof your site from future theme upgrades.  In this post, I’m going to show you how to create your very own child theme for Modularity, our multimedia theme framework that powers many of our themes.

Preview Example Child Theme

Download Example Child Theme

What you need

  • Modularity 2.5 or higher
  • WordPress 2.9 or higher
  • A text editor.  We use Coda.  Anyone of these will work, though.
  • A wee bit of css, html and php knowledge (don’t worry if you don’t…we’ll give examples)
  • FTP access to your server & WordPress install

How a child theme works

A child theme inherits all of the theme files of the parent theme, unless specified in the child theme.   At the very minimum, a child theme must consist of the child theme folder (call it whatever you want, no empty spaces) and a style.css file.  If you add any one of these template files in your child theme, WordPress will use them instead of the parent theme files.  Now, because Modularity contains many additional files (sliders, slideshow, other homepage apps) that don’t exist in the WordPress template hierarchy, we’ll need to change the file paths to where these new template files will reside.   More on this later.

Style.css

As I mentioned above, a child theme must have a style.css file and it must contain this info at the very top:

/*
Theme Name: Child Theme
Theme URI: http://graphpaperpress.com
Description: Child Theme for Modularity
Author: Thad Allender
Author URI: http://graphpaperpress.com
Template: modularity
Version: 1.0
*/

@import url("../modularity/style.css");

The @import rule must precede all other rules. All styling rules you add must be placed after it. This rule instructs the browser to: Jump one level up (../) into the themes directory, go into modularity, get the content of style.css and @import it here.  You can override any css styles contained in the parent theme by adding the css to this stylesheet beneath the @import rule.  For example, if you wanted to change the background color from black to white, you would add this to the child theme’s style.css file:

body { background: #fff }

Now, if we put all this together, we would have this code on style.css:

/*
Theme Name: Child Theme
Theme URI: http://graphpaperpress.com
Description: Child Theme for Modularity
Author: Thad Allender
Author URI: http://graphpaperpress.com
Template: modularity
Version: 1.0
*/

@import url("../modularity/style.css");
body { background: #fff }

Important notes about style.css:

  1. The child theme will not be recognized by WordPress unless a file called style.css is found in its directory.
  2. WordPress identifies themes by reading the part between /* and */.  If you leave this off, your theme won’t work.
  3. The Template line is important, since it declares the parent theme. The parent must be declared by the name of its directory exactly as you see it, case-sensitively — not by the name of the theme. The two are often different.

You can add as many css classes as you would like to style.css. To figure out which css classes you would like to override, we like to use the Firebug extension for Firefox.  This tool allows you to point your cursor on an item on the page and inspect the exact css classes that control it’s styling.  You can also edit the css live on the page.  When you like the results, you can save these changes onto your child theme’s style.css file.  Watch this video tutorial on using Firebug for more info:

Functions.php

Functions.php is a very powerful file for WordPress themes.  It is typically the place where theme authors insert additional functions that can manipulate the WordPress admin panel, add theme options, insert javascripts, define global variables, and much more.  All child themes for Modularity must have a functions.php file.  At a bare minimum, it should contain the following info:

<?php

// Define Theme Options Variables
$themename='Child Theme';

?>

This one line will defines the name of your child theme.   Below is a more advanced functions.php file for the child theme we are building:

<?php

// Define Theme Options Variables
$themename='Child Theme';
$default_thumb = get_bloginfo('stylesheet_directory') . "/images/default-thumb.jpg";

// Load some javascripts for child theme
if (!is_admin()) add_action( 'init', 'load_base_child_js' );
function load_base_child_js( ) {
 wp_enqueue_script('fader', get_bloginfo('stylesheet_directory').'/js/jquery.fader.js', array('jquery'));
}

?>

Important notes about functions.php:

Here, we are defining a new default thumbnail to be used and we are also loading a new javascript called jquery.fader.js.  There are one important takeaway from the code above: The use of stylesheet_directory.  This statement makes WordPress look in the child theme directory for the files that it is inserting, rather than the parent directory.  To make WordPress look in the parent directory, you would change stylesheet_directory to template_directory. You can read more about the bloginfo(); function at the WordPress Codex.

Header.php

We have added header.php into our example child theme because we are going to replace the default navigational items (nav.php) with a series of custom navigation links.  We have to overwrite the header.php file so that WordPress doesn’t use Modularity’s header.php file and thus, insert Modularity’s nav.php file.  This might be tough to grasp at first.  If so, re-read the paragraph above until it sticks.  Here is child theme’s header.php file:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" <?php language_attributes(); ?>>
<head profile="http://gmpg.org/xfn/11">

    <title><?php wp_title( '-', true, 'right' ); echo wp_specialchars( get_bloginfo('name'), 1 ); ?></title>
	
	<meta http-equiv="content-type" content="<?php bloginfo('html_type') ?>; charset=<?php bloginfo('charset') ?>" />
	<meta name="description" content="<?php bloginfo('description') ?>" />
	<?php if(is_search()) { ?>
	<meta name="robots" content="noindex, nofollow" /> 
    <?php }?>
    
<!-- BeginStyle -->
	<link rel="stylesheet" type="text/css" href="<?php bloginfo('stylesheet_url'); ?>" />
	<link rel="stylesheet" href="<?php bloginfo('template_directory'); ?>/styles/print.css" type="text/css" media="print" />
	<!--[if IE]><link rel="stylesheet" href="<?php bloginfo('template_directory'); ?>/styles/ie.css" type="text/css" media="screen, projection" /><![endif]-->
	<!--[if IE 7]><link rel="stylesheet" href="<?php bloginfo('template_directory'); ?>/styles/ie7.css" type="text/css" media="screen, projection" /><![endif]-->
<!-- EndStyle -->


	<link rel="alternate" type="application/rss+xml" title="RSS 2.0" href="<?php if ( get_option('gpp_feedburner_url') <> "" ) { echo get_option('gpp_feedburner_url'); } else { echo get_bloginfo_rss('rss2_url'); } ?>" />
	<link rel="pingback" href="<?php bloginfo('pingback_url'); ?>" />

	<?php wp_head(); ?>
	<!-- Conditional Javascripts -->
	<!--[if IE 6]>
	<script src="<?php bloginfo('template_directory'); ?>/includes/js/pngfix.js"></script>	
	<![endif]-->
	<!-- End Conditional Javascripts -->

	<?php if ( is_singular() ) wp_enqueue_script( 'comment-reply' ); ?>

</head>

<body <?php body_class(); ?>>

<!-- BeginHeader -->
<div id="top">
<div id="masthead">
        <div id="logo">
            <h1 class="sitename"><a href="<?php bloginfo('url'); ?>" title="<?php bloginfo('description'); ?>"><?php if(get_option('gpp_logo_off')=="true") { bloginfo('name'); } else { ?><img class="title" src="<?php if ( get_option('gpp_logo') <> "" ) { echo get_option('gpp_logo'); } else { bloginfo('stylesheet_directory'); ?>/images/logo.png<?php } ?>" alt="<?php bloginfo('name'); ?>" /><?php } ?></a></h1>
           
            <div class="description"><?php bloginfo('description'); ?></div>
        </div>

</div>

<?php include ('nav.php'); ?>

<div class="clear"></div>
</div>
<!-- EndHeader -->

<div class="container">
<div class="container-inner">

<!-- BeginContent -->

If this looks scary, don’t fret, because there is really only one line we are interested in talking about. Locate line 48:

<?php include ('nav.php'); ?>

This code says this: Include the contents of the file nav.php and insert it right here.  Please note:  nav.php must be located relative (in the same directory) to header.php.  If you didn’t overwrite header.php, WordPress would use the header.php file from Modularity, and thus, insert the nav.php file located in the Modularity theme folder.

Nav.php

As I mentioned above, we are overwriting header.php so that we can change the navigational items to custom, “hard-coded” links.  The nav.php file in Modularity contains about 226 lines of code, which is pretty large considering that it merely outputs a few lines of html code that makes your navigation.  Most of this code is used to query the navigational display options that you have set on Modularity’s theme options panel.  If all you wanted to do was to show your categories in one drop down list in your child theme, you could add this to nav.php located in your child theme:

<!-- Navigation -->
<ul class="sf-menu">
  <li>
    <a href="#" title="Navigation">Navigation</a>
    <ul>
      <?php wp_list_categories('title_li='); ?>
    </ul>
  </li>
</ul>

If you wanted to show a few links to pages, you could do this:

<!-- Navigation -->
<ul class="sf-menu">
  <li>
    <a href="#" title="Navigation">Navigation</a>
    <ul>
      <?php wp_list_categories('title_li='); ?>
    </ul>
  </li>
  <li><a href="/about/" title="About page">About</a></li>
  <li><a href="/contact/" title="Contact page">Contact</a></li>
</ul>

If you wanted to “hard-code” in a series of links in a drop-down list to other websites, you could do this:

<!-- Navigation -->
<ul class="sf-menu">
  <li>
    <a href="http://example.com">Sub list</a>
    <ul>
      <li><a href="http://example.com">Sub list 1</a></li>
      <li><a href="http://example.com">Sub list 2</a></li>
      <li><a href="http://example.com">Sub list 3</a></li>
      <li><a href="http://example.com">Sub list 4</a></li>
      <li><a href="http://example.com">Sub list 5</a></li>
    </ul>
  </li>
  <li>
    <a href="#" title="Navigation">Navigation</a>
    <ul>
      <?php wp_list_categories('title_li='); ?>
    </ul>
  </li>
  <li><a hef="/about/" title="About page">About</a></li>
  <li><a hef="/contact/" title="Contact page">Contact</a></li>
</ul>

You can refer to these instructions for listing all pages and these instruction for list all categories. You can even pass parameters to these WordPress template tags to have further creative control over what the tags output onto in your navigation.

Home.php

This is the main file that controls how your homepage looks and where the homepage apps are arranged vertically.  Here is the contents of Modularity’s home.php file:

<?php get_header(); ?>

<!-- Pagination -->
<?php if ( $paged < 1 ) { ?>

<?php if ( get_option('gpp_welcome') == 'true' || !get_option('gpp_welcome') ) { include (TEMPLATEPATH . '/apps/welcome.php'); } ?>

<?php if ( get_option('gpp_slideshow') == 'true' || !get_option('gpp_slideshow') ) { include (TEMPLATEPATH . '/apps/slideshow.php'); } ?>

<?php if ( get_option('gpp_video') == 'true' ) { include (TEMPLATEPATH . '/apps/video-home.php'); } ?>

<?php if ( get_option('gpp_slider') == 'true' || !get_option('gpp_slider') ) { include (TEMPLATEPATH . '/apps/slider.php'); } ?>

<?php if ( get_option('gpp_slider_posts') == 'true' ) { include (TEMPLATEPATH . '/apps/slider-posts.php'); } ?>

<?php if ( get_option('gpp_featured') == 'true' || !get_option('gpp_featured') ) { include (TEMPLATEPATH . '/apps/featured.php'); } ?>

<!-- End Pagination -->
<?php } ?>

<?php if ( get_option('gpp_blog') == 'true' ) { include (TEMPLATEPATH . '/apps/blog.php'); } ?>

<?php if ( get_option('gpp_category_columns') == 'true' || !get_option('gpp_category_columns') ) { include (TEMPLATEPATH . '/apps/category-columns.php'); } ?>

<!-- Footer -->
<?php get_footer(); ?>

Starting at the top, we get the header with this template tag:

<?php get_header(); ?>

Next, we tell WordPress to only show the Welcomebox, Slideshow, Video, Slider, Slider Posts and Featured apps on the homepage with this statement:

<?php if ( $paged < 1 ) { ?>

The statement ends a few lines down with this:

<?php } ?>

Why?  If you choose to enable the Blog app on your homepage, you will more than likely want to be able to paginate to older posts.  You likely won’t, however, want your Welcome message to appear on every paginated post.  This is why we wrap these apps in the if ( $paged < 1) statement.

Home.php checks your theme options settings to see which apps you have enabled.  If they are enabled, then home.php includes the app file with this statement:

<?php if ( get_option('gpp_slideshow') == 'true' || !get_option('gpp_slideshow') ) { include (TEMPLATEPATH . '/apps/slideshow.php'); } ?>

In English, this statement reads like this: If the slideshow is turned on or the slideshow option isn’t set yet, then include the contents of the file located in /moduarity/apps/slideshow.php.  Each one of these similar statements on the homepage checks your theme options setting and includes different app files.  You can rearrange the files simply by copying and pasting each homepage app statement where ever you want on home.php.  You can even paste these statements into any other theme files, assuming that you are inserting them into a region that spans the full 950 pixels of the page and not inside another WordPress loop. In the example below, I’m going to cut and paste the homepage Welcome app (welcome.php) into the header right below the EndHeader comment, and wrap it in an if ( is_home () ) statement, so it only shows on the homepage:

<!-- Only show welcomebox on the homepage -->
<?php if(is_home()) { ?>
<div class="container-inner">
<?php if ( get_option('gpp_welcome') == 'true' || !get_option('gpp_welcome') ) { include (TEMPLATEPATH . '/apps/welcome.php'); } ?>
</div>
<?php } ?>

Now, lets say that you wanted to create you own app, or replace an existing app with your own.  Using the Featured app as an example, you would want to change this on home.php:

<?php if ( get_option('gpp_slider_posts') == 'true' ) { include (TEMPLATEPATH . '/apps/featured.php'); } ?>

With this:

<?php if ( get_option('gpp_featured') == 'true' || !get_option('gpp_featured') ) { include ('featured.php'); } ?>

Important

Notice that we have removed TEMPLATEPATH, the dot (.), and also /apps/ from the statement.  Assuming that you have added this newly customized home.php file into your child theme folder, this tells WordPress to look for the featured.php file right next to your new home.php file located in your child theme.  If you wanted to adhere to the same folder structure as seen in Modularity, you could do this instead:

<?php if ( get_option('gpp_featured') == 'true' || !get_option('gpp_featured') ) { include ('apps/featured.php'); } ?>

And make sure you put featured inside a folder called apps located in your child theme folder.  Either way is fine. It’s your code, so do whatever you prefer.  I like to keep all child theme files on the top level in my child themes because the files are more directly accessible.

Now that we are telling WordPress to use our own featured.php app, we need to create on.  Here is the example featured.php file:

<?php
$featured_category = get_option('gpp_featured_cat');
if($featured_category=="") {$featured_category = "Latest";}
$featured_category_ID = get_cat_ID($featured_category);
?>

<div class="span-24 last">

<h3 class="sub"><?php echo "$featured_category"; ?></h3>

	<?php $my_query = new WP_Query("cat='$featured_category_ID'&showposts=9"); ?>
	<?php $i = 0; ?>
	<?php while ($my_query->have_posts()) : $my_query->the_post(); $do_not_duplicate = $post->ID; $i++;  ?>

			<div class="span-8<?php if (($i%3)==0) { ?> last<?php } ?>">
			<div class="post-<?php the_ID(); ?> portfolio-image-wrapper">

			<?php get_the_image( array( 'custom_key' => array( 'photo-310x150' ), 'default_size' => '310x150', 'width' => '310', 'height' => '150', 'image_class' => 'thumbnail-310x150' ) ); ?>

			<p><?php if (the_category(', '))  the_category(); ?></p>
			<h6 class="title-overlay"><a href="<?php the_permalink() ?>" rel="bookmark" title="Permanent Link to <?php the_title_attribute(); ?>"><?php the_title() ?></a></h6>
			</div>
			<div class="clear"></div>
			</div>

	<?php endwhile; wp_reset_query(); ?>
</div>

<hr />

This new feature.php file, which we also refer to as the “Featured” app, is a three column grid of thumbnails, where each thumbnail represents a separate post.

Archive.php

Now, lets say that you wanted to change the way your category archives page looks.  You want a 950 pixel wide, three column grid of thumbnails that represents each post.  Because the archive.php file is part of WordPress’ template hierarchy, you can simply create a file called archive.php, paste the code below, and drop it into your child theme folder. Here is the code:

<?php get_header(); rewind_posts(); $i=0; ?>

<div class="span-24 last">

		<?php 
		query_posts($query_string.'&posts_per_page=24');
		$default_thumb = get_bloginfo('template_url') . "/images/default-thumb.jpg";
		if (have_posts()) : ?>

 	  <?php $post = $posts[0]; // Hack. Set $post so that the_date() works. ?>
 	  <?php /* If this is a category archive */ if (is_category()) { ?>
		<h3 class="sub"><?php single_cat_title(); ?></h3>
 	  <?php /* If this is a tag archive */ } elseif( is_tag() ) { ?>
		<h3 class="sub">Posts Tagged &#8216;<?php single_tag_title(); ?>&#8217;</h3>
 	  <?php /* If this is a daily archive */ } elseif (is_day()) { ?>
		<h3 class="sub">Archive for <?php the_time('F jS, Y'); ?></h3>
 	  <?php /* If this is a monthly archive */ } elseif (is_month()) { ?>
		<h3 class="sub">Archive for <?php the_time('F, Y'); ?></h3>
 	  <?php /* If this is a yearly archive */ } elseif (is_year()) { ?>
		<h3 class="sub">Archive for <?php the_time('Y'); ?></h3>
	  <?php /* If this is an author archive */ } elseif (is_author()) { ?>
		<h3 class="sub">Author Archive</h3>
 	  <?php /* If this is a paged archive */ } elseif (isset($_GET['paged']) && !empty($_GET['paged'])) { ?>
		<h3 class="sub">Blog Archives</h3>
 	  <?php } ?>

<?php while (have_posts()) : the_post(); $i++; ?>
	<div class="span-8<?php if (($i%3)==0) { ?> last<?php } ?>">
		<div class="post-<?php the_ID(); ?> portfolio-image-wrapper">
			<?php get_the_image( array( 'custom_key' => array( 'photo-310x150' ), 'default_size' => '310x150', 'width' => '310', 'height' => '150', 'image_class' => 'thumbnail-310x150' ) ); ?>
			<div class="title-overlay">
				<h6><a href="<?php the_permalink() ?>" rel="bookmark" title="Permanent Link to <?php the_title_attribute(); ?>"><?php the_title() ?></a></h6>
				<p><?php if (the_category(', '))  the_category(); ?></p>
			</div>
		</div>
	</div>
<?php endwhile; ?>

<div class="clear"></div>

<div class="nav-interior">
			<div class="prev"><?php next_posts_link('&laquo; Older Entries') ?></div>
			<div class="next"><?php previous_posts_link('Newer Entries &raquo;') ?></div>
		</div>
<div class="clear"></div>

	<?php else : ?>

		<h2 class="center">Not Found</h2>
		<?php get_search_form(); ?>

	<?php endif; ?>
</div>

<!-- Begin Footer -->
<?php get_footer(); ?>

You can download the child theme that we just build above right here:

Download Child Theme

If you found this tutorial helpful, considering signing up for a Graph Paper Press membership to watch over two hours of video tutorials, receive support from developers, and download any of our themes and plugins.

Newsletter
Join over 280,000 independent website owners

The next person to join our monthly newsletter gets a 25% off coupon!

We guarantee 100% privacy. Your information will not be shared.

This entry was posted in Blog. Bookmark the permalink.

Posted by , at Graph Paper Press

Thad is the founder of Theme.Works and Graph Paper Press. Previously, he produced online multimedia and documentary projects for USA Today including the inauguration of President Barack Obama and many others. He lives in Brooklyn, NY with his wife Abby.

  • Google
  • Blog
  • Instagram

20 thoughts on “How to create child themes for our Modularity theme for WordPress”

  1. Nice post and a ton of tutorial to go with it. It seems the nav.php file contains a large number of lines of code,for what it does. IMHO.
    Thx
    will

  2. Can you make a child of a child? For example, if I only want to make some tweaks to F8, but don’t want to edit the files within F8 (and F8 is a child of Modularity), can I create a child of F8 and have everything work?

  3. I am somewhat of a newbie when it comes to child themes. I understand that in a framework such as this, it’s smart to add any of my desired changes to the child theme instead of the parent. However, your instructions don’t state what to do with the child theme after I’ve downloaded it. I see it comes in a zip. Do i just upload it in the “install themes” panel of WordPress? How will WordPress know it is a child theme of Modularity and not some other graphpaper press theme?
    Do I have to do any changes right off the bat to make it work?

  4. Ridiculous tutorial, honestly. “This might be tough to grasp at first.  If so, re-read the paragraph above until it sticks.”  Nice touch, there.This might be tough to grasp at first.  If so, re-read the paragraph above until it sticks.”  Nice touch, there.

  5. Someone please explain to me how I can do to integrate in the app FEATURED the plugin WP_PAGENAVI for excellent pagination!?

    Like this!!
    h**p://img703.imageshack.us/img703/6940/bdf6e1298a9e46188cd61ed.png

Leave a Reply to Maggie Shnayerson Cancel reply