Modular templates provide us with a new way to organize our themes. In this post, we’ll discuss how separating theme structure from theme content reduces repetitive code and makes theme code easier to follow.
The concepts are based on this belief:
When you edit theme content, you shouldn’t have to copy your structure; when you edit theme structure, you shouldn’t have to edit ten files.
These concepts are best conveyed through example, so we’ll take a look at how
get_template_module() can benefit the theme structure in Twenty Ten. However, these concepts (and this example) can apply to any theme.
A note, before we get started:
This is part 2 in a series about Modular Themes.
You should probably take a look at part 1.
Repetitive Code, Revisited
The two glaring examples of repetitive code are the loop and page structure. We’ve already addressed the loop, but things like
<div class="container"> show up in almost every file. In addition, we often see html elements broken across files—definitely not poetic code. You know it’s bad when best practice is to write
</div><!--#container--> because you’d have no idea which
<div> you were closing otherwise.
The initial thought would be to encapsulate the opening and closing structure in two template parts, but the workings of
get_template_module() suggest an even smoother practice. Currently, nearly all changes between theme pages have to do with the presentation of the content on the page, not the header, footer, or sidebars. What if, instead of repeating structure code on every page, we made a content module?
Our Example: Twenty Ten
Ladies and gentlemen, get your (hypothetical) themes ready. I’ll be using Twenty Ten to illustrate. I’ll refer to several of the html elements (such as
#header) within the examples, but they should translate easily for any theme. Here’s a look at Twenty Ten’s structure, and how it’s broken across files:
<!--BEGIN HEADER.PHP--> <html> <head> <!--title, etc go here--> </head> <body> <div id="wrapper" class="hfeed"> <div id="header"> <!--header contents go here--> </div> <!--END HEADER.PHP--> <!--BEGIN INDEX.PHP--> <div id="main"> <div id="container"> <div id="content"> <!--page contents go here--> </div> </div> <!--sidebar goes here--> </div> <!--END INDEX.PHP--> <!--BEGIN FOOTER.PHP--> <div id="footer"> <!--footer contents go here--> </div> </div> </body> </html> <!--END FOOTER.PHP-->
Creating a Content Module
To isolate our structural code, we’ll begin by creating a content module:
- Move all of the template hierarchy files into the
contentfolder (save an extra copy of
- Open each file, and delete all of the structural code. If you’re following along with Twenty Ten, save only what’s inside the
#contentelement (but not the
- Then in our copied
index.php, delete everything inside the structure (for Twenty Ten, everything inside
#content) and replace it with
<?php get_template_module('content'); ?>.
So Twenty Ten’s new
index.php would look something like this:
<?php get_header(); ?> <div id="container"> <div id="content"> <?php get_template_module('content');?> </div><!-- #content --> </div><!-- #container --> <?php get_sidebar(); ?> <?php get_footer(); ?>
This is now the only file where we’ll find the page structure. Want to change it for a specific page? Add a new file (say,
category.php) and edit to your heart’s content.
A Step Further
While we’re no longer repeating structure, we’re still splitting HTML elements across files—namely
footer.php. The header file is a curious beast; it includes both the
head element, and the actual page header, which itself is comprised of a mixture of structure (i.e.
<body>) and content (i.e.
#header, logos, menus, etc.). These two are grouped together as a result of our current system because repeating the page header over and over is considered a form of torture.
index.php is readable (and short!), it makes sense to separate the two parts of
header.php. We’ll use
header.php for only the
head element (if I had my druthers, I’d rename
Creating a Header Module
- Cut the page header (everything from the
bodytag down), and paste it into
index.phpright under the call to
- Then, make your header content a module: cut out the contents of the
<div id="header">element (or your theme’s equivalent), and paste them into
<?php get_template_module('header'); ?>where you just cut the content (inside
Creating a Footer Module
The footer is similar to the header—it’s part stucture, part content. We’ll do almost the same thing:
get_footer()(we won’t need it anymore) and replace it with the code in
- Cut the contents of the
#footerelement and paste them into
<?php get_template_module('footer'); ?>where you just cut the content (inside
- Finally, delete
footer.php; we’ve moved everything!
The Results: Cross-file HTML tags? Only one!
That’s right, it’s the
html tag itself. Let’s take a look at Twenty Ten’s new
<?php get_header(); ?> <body <?php body_class(); ?>> <div id="wrapper" class="hfeed"> <div id="header"> <?php get_template_module('header'); ?> </div><!-- #header --> <div id="main"> <div id="container"> <div id="content"> <?php get_template_module('content');?> </div><!-- #content --> </div><!-- #container --> <?php get_sidebar(); ?> </div><!-- #main --> <div id="footer"> <?php get_template_module('footer'); ?> </div><!-- #footer --> </div><!-- #wrapper --> <?php wp_footer(); ?> </body> </html>
It’s a little longer than before, but now all of the theme structure is located in the same file. If you look up at the overview of Twenty Ten’s structure, you’ll notice that only the opening
html tag and
head element are missing. Now,
header.php contains the entire
head element, while
index.php contains the entire
Let’s run down where our code is now located:
- header.php: Dedicated to the
headtag. Opens the
- index.php: Dedicated to the
bodytag and theme structure. Loads the other modules. Closes the
- the “content” directory: Contains our original template hierarchy files, without the structure. Parent element:
- header/index.php: Contains header content. Parent element:
- footer/index.php: Contains footer content. Parent element:
- footer.php: Doesn’t exist anymore!
More generally, this development pattern dedicates the root template hierarchy to theme structure, and the
footer directories to theme content. Since all folders apply the template hierarchy, themes become incredibly extensible. Code becomes much easier to pinpoint and customize, which is especially helpful when creating a child theme.
It’s important to note that this development pattern does not rid us of repeated code—only a massive file with lots of conditionals can do that. Instead, it attempts to reduce repeated code by separating content from structure. As I wrote earlier: When you edit theme content, you shouldn’t have to copy your structure; when you edit theme structure, you shouldn’t have to edit ten files.
Want to download this post’s example? Download Modular Twenty Ten.
A Few Extra Thoughts
Shortcut functions: Like this development pattern? We could propose shortcut functions to establish a naming convention:
get_footer_module() could load modules from the
footer directories, respectively. Note that these are not part of the current patch.
Performance: I’m sure some of you are wondering about the performance of
get_template_module() and how it affects load speeds. From my tests, it doesn’t.
The function name: I am by no means set on the name
get_template_module; I just needed something to work with! Ptah Dunbar suggested
get_template_file, which is likely a better fit. Any other ideas?
On sidebars: Some of you may be asking why I shied away from modularizing sidebars (in fact, if it helps a theme, I’m all for it). Here’s the issue:
get_sidebar() has an optional parameter that acts like
get_template_part()‘s optional parameter. In cases where
get_sidebar('optional') were called, you’d have to write the following:
if( ! get_template_module('sidebar-optional') ) get_template_module('sidebar');
Of course, that could easily be encapsulated in a function
<html> element: I realize that I could have had zero cross-file tags if I moved the opening
html tag into
index.php, but I think the
DOCTYPE declaration is a natural companion to the
<head> element could be module: Yep, it could! If your theme’s
head could benefit by becoming a module (read: “has a lot of template conditionals”) go for it.
If you’ve made it this far, thank you for reading! I’d love to know what you think.
Trac Ticket | Part 1: Why? | Part 2: Theme Organization | Download | Performance