Modular Themes, Part 1: Why?
Have you ever wanted to change a class in the loop? You’re likely going to have to edit upwards of five files. The worst part? Most of the code you’re editing is identical.
A note, before we get started:
If you already know about get_template_part(), you’ll probably want to skip down to the section entitled “Using get_template_part() to Simulate the Template Hierarchy”.If you’ve seen my session at WordCamp Ireland, this will seem very familiar.
What causes repetitive code?
As theme developers, our needs and our development pattern form a paradox: We need the ability to completely change any page, but most of the time we only change small sections and want to keep the rest in sync.
The problem lies in how our code is organized. In the current system, each file represents a page within the template hierarchy. However, we often don’t want to change the entire page, but a small section of code. As a result, we copy large chunks of code to a new page.
The system does not provide us with a viable way to manage code blocks below the page-level scope. At the moment, we have three alternatives:
- Copy code, and create a new page.
- Use template conditionals such as
is_archive(). - Encapsulate your code in a separate function.
While template conditionals have their place, they must be used in moderation. Otherwise, files quickly become bloated and unreadable. Functions are a little trickier: at first glance, they seem to be an ideal solution. Combined with template conditionals, they can produce the desired results without swelling template files. The problem? PHP functions cannot be overridden.
When you define a function in a parent theme, it cannot be changed in a child theme. To tweak the code found in parent_page_title(), a child theme will have to copy parent_page_title() into a new function, child_page_title(), and then copy every theme file that calls parent_page_title() and replace it with child_page_title(). That’s like the Grand Poobah of repetitive code.
The First Step: get_template_part()
Okay, so if you’re using the latest beta (or trunk, if you’re awesome), the current system has a treat for you. In WP 3.0, theme devs get new function for their toolbox: get_template_part(). In the words of the documentation:
get_template_part()“makes it easy for a theme to reuse sections of code in an easy to overload way for child themes.”
Sounds good, I’ll take two. This function is just what we needed—now we can call get_template_part('page-title') and WordPress will load page-title.php, and even check the child theme first.
get_template_part() has an optional second argument that will first look for a specific version of the template. So if we were to call get_template_part('page-title', 'special'), WordPress would first check for page-title-special.php, and if that’s not found, look for page-title.php.
Using get_template_part() to Simulate the Template Hierarchy
As the new default theme on the block, Twenty Ten sets a good example for theme developers everywhere. Let’s look at how Twenty Ten uses get_template_part():
- In archive.php:
get_template_part('loop','archive'); - In author.php:
get_template_part('loop','author'); - In category.php:
get_template_part('loop','category'); - In index.php:
get_template_part('loop','index'); - In search.php:
get_template_part('loop','search'); - In tag.php:
get_template_part('loop','tag');
As you can tell, Twenty Ten uses get_template_part() to load the loop. While doing so, Twenty Ten loads custom versions of the loop in a fashion identical to the template hierarchy. Note that Twenty Ten only defines loop.php; it anticipates that child themes will use the more specific files.
I think that taking the template hierarchy into consideration when creating template parts is a fantastic idea, but I have a few problems with this implementation:
- The burden is on the user to implement the template hierarchy. What if the theme only defines archive.php? If the author wants to include a category-specific template part, they’re back to template conditionals or copy/paste.
- There is no naming convention. Yes, Twenty Ten follows the template hierarchy’s naming conventions, but what if a theme references “cats” instead of “category”, or ”archives” instead of “archive”? There is no way to know without inspecting the theme files.
- Only part of the template hierarchy is implemented. In a Twenty Ten child theme, what if a user defines
loop-date.phporloop-category-news.php? Their code will never be called, and again, they won’t know why until they read through the theme files. Developers who aren’t familiar with PHP will likely end up bewildered. Silently failing is bad.
This begs the question:
Instead of simulating parts of the template hierarchy, what if we just applied the template hierarchy to template parts?
Modular Themes
Well, we can. I’ve proposed a function get_template_module() that loads the best match in the template hierarchy from a given folder. While get_template_part() still has its place, get_template_module() is ideal in situations where a theme developer wants to vary a block of code depending on the template hierarchy.
Using Twenty Ten as an example, we would move loop.php to loop/index.php, and replace all calls to get_template_part() with get_template_module('loop').
When you’re viewing the “News” category, with category-id 4, get_template_module('loop') checks for the following and loads the first match:
loop/category-news.php→loop/category-4.php→loop/category.php→loop/archive.php→loop/index.php
Not Just for the Loop
get_template_module() has a whole bunch of uses, including potentially changing the way we organize our themes (which, incidentally, is the subject of my next post). Want to see get_template_module() in core? Read the trac ticket.
Modular Themes:
Trac Ticket | Part 1: Why? | Part 2: Theme Organization | Download | Performance
Alexandre Simard 10:24 pm on May 1, 2010 Permalink |
Hey Daryl! I remember talking to you in the bar after the Day 1 of WordCamp NYC. I had seen your presentation of Elastic. My impression was that you had a ton of great ideas, but that your project was perhaps too ambitious for its own good. You were talking about pretty much rewriting from scratch the WordPress template engine.
I’m happy to see you’ve come around to appreciate the default engine for what it provides. Your proposed additions are very simple, yet they open up a world of possibilities, not just for Elastic, while staying true to the spirit of WordPress’s template engine.
I think you’ll find a lot better support from other developers for your new ideas. I, for one, am very enthusiastic about them and can see myself contributing to them much more easily than with the previous Elastic incarnation.
Keep up the good work!
Themes and WordPress 3.0 some important changes | WPLover 11:12 am on May 3, 2010 Permalink |
[...] About get_template_part (previously linked to here). [...]
R'phael Spindel 7:20 pm on May 29, 2010 Permalink |
I agree.. much better approach. I’ve waited for get_template_part to be included in WP, and now, I will wait for get_template_module!!!
Template Changes/Tags for Wordpress 3.0 10:18 pm on June 2, 2010 Permalink |
[...] More Information read article on Modular Templates by Daryl Koopersmith ( Part 1 and Part 2 ) and by [...]
Personalizar la presentación de lista por categoría | Sin orden ni concierto 10:35 am on July 21, 2010 Permalink |
[...] por Google, encuentro una explicación de cómo funciona esto en parte de un artículo de Daryl Koopersmith. El fichero category.php contiene una línea con la siguiente [...]