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 get_header()
and <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
content
folder (save an extra copy of index.php
).
-
Open each file, and delete all of the structural code. If you’re following along with Twenty Ten, save only what’s inside the
#content
element (but not the #content
element itself).
-
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 header.php
and 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.
Now that 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 header.php
to head.php
).
Creating a Header Module
-
Cut the page header (everything from the
body
tag down), and paste it into index.php
right under the call to get_header()
.
-
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 header/index.php
.
-
In
index.php
, add <?php get_template_module('header'); ?>
where you just cut the content (inside #header
).
Creating a Footer Module
The footer is similar to the header—it’s part stucture, part content. We’ll do almost the same thing:
-
In
index.php
delete get_footer()
(we won’t need it anymore) and replace it with the code in footer.php
.
-
Cut the contents of the
#footer
element and paste them into footer/index.php
.
-
In
index.php
add <?php get_template_module('footer'); ?>
where you just cut the content (inside #footer
).
-
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 index.php
:
<?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 body
element.
Let’s run down where our code is now located:
- header.php: Dedicated to the
head
tag. Opens the html
tag.
- index.php: Dedicated to the
body
tag and theme structure. Loads the other modules. Closes the html
tag.
- the “content” directory: Contains our original template hierarchy files, without the structure. Parent element:
#content
.
- header/index.php: Contains header content. Parent element:
#header
.
- footer/index.php: Contains footer content. Parent element:
#footer
.
- footer.php: Doesn’t exist anymore!
Wrapping Up
More generally, this development pattern dedicates the root template hierarchy to theme structure, and the content
, header
, and 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_content_module()
, get_header_module()
, get_footer_module()
could load modules from the content
, header
, and 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 get_sidebar_module()
.
On the <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.
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.
Modular Themes:
Trac Ticket | Part 1: Why? | Part 2: Theme Organization | Download | Performance
Stef 4:42 pm on April 19, 2010 Permalink |
Really awesome patch!
Is there any way to make it plug-able so we can use it until it gets included in a core release?
Daryl 6:29 pm on April 21, 2010 Permalink |
Thanks! And yes, but it will require duplicating a bunch of core WP code. You’re the second person to ask, so when I have a bit of free time I’ll convert it to a self-contained file/plugin.
Konstantin 2:50 pm on May 18, 2010 Permalink |
Make it three, I would really appreciate it!
Daniel 6:01 am on May 27, 2010 Permalink |
An here’s number 4 … sounds great Daryl. Keep things coming.
Will Norris 5:55 pm on July 14, 2010 Permalink |
I’ve converted your patch into a plugin, available at http://github.com/willnorris/template-modules. As soon as my plugin request is approved, I’ll add it to the plugin directory as well at http://wordpress.org/extend/plugins/template-modules/.
Daryl 1:54 am on July 21, 2010 Permalink |
Will, this is awesome. Thank you!
Ramoonus 9:27 am on August 8, 2010 Permalink |
the plugin link isn`t working