Writing Maintainable WordPress Themes: Directories
When it comes to building WordPress themes - as with many other types of things, really - there are right ways and wrong ways to do it. For those of us who want to be professional WordPress developers, for those of us who truly care about the work that we're doing, and for those of us who want our work to last, then we need to be forward-thinking about how we're organizing the files and the code that goes into our theme.
Yes, the WordPress Codex offers a fantastic article on Theme Development, and I believe that it should be required reading for anyone who is getting into building themes - especially premium themes - but there are some strategies that it doesn't cover that I've found to be very helpful as it relates to building, releasing, and maintaining themes over time.
In the next two articles, we're going to take a look at a few strategies that go a little bit deeper into theme development that will help us structure our themes in such a way that they will not only be following the guidelines of the WordPress Codex, but will also make it much easier to maintain, update, and improve not only as WordPress moves forward, but as our theme matures, as well.
A Word About Theme Development Practices
The quality of the organization of the files and of the code that goes into building WordPress themes is somewhat of a hot topic.
To be clear, this is one of those things that developers and designers love to talk about to a point where it has morphed into something that people love to hate. That is to say that others will often comment about poor quality themes that are available for WordPress, and will then use that argument as a reason for why WordPress is a poor platform not only for blogging, but for other reasons, as well.
That's not the point or the argument of what we'll be discussing here, nor is it meant to inspire that type of discussion in the comments. Instead, this two-part series assumes the following:
- you're a WordPress developer who has built or who is looking to build themes,
- you're a WordPress developer who already knows the basics of theme development from the topics covered in the Codex,
- you're a WordPress developer who is looking for ways to improve processes and organizational structures that are already in place to create more robust products.
Of course, we all have our own ways of doing things so the recommendations that are shared throughout this series may not work with your current workflow. Perhaps you don't want to change - and that's fine! - or perhaps you're looking for a change.
Regardless of the case, everything that's shared here is based on experience in building and maintaining premium WordPress themes and has made it much easier to maintain them over time both from a theme-specific standpoint, but from a WordPress compatibility standpoint, as well.
All About Maintainability
One of the hardest parts of building software isn't shipping the initial version (although that is tough in and of itself), but it's maintaining the product after release.
Not only does that entail making sure that the codebase continues to be compatible with the underlying infrastructure - which we'll talk about in the next section - but that the files are organized in such a way that lend themselves to be understood by the development team, that they have a level of cohesion, and that they have a rhyme and reason as to why they are named and placed in the way that they are.
We know from the Codex that there are a number of files that make up the core of the theme. This includes templates, a functions file, and at least one stylesheet.
What happens, though, when your theme gets more complicated? Say that you...
- Introduce some type of CSS pre-processing such as LESS or Sass?
- What about partials - or reusable template parts - that are used throughout the theme?
- Do translations have a particular place to live?
- What about helper functions and other utility functions that are used to help keep the business logic separate from the presentation logic?
- What happens when you bring in third-party libraries?
All of the above can be cleanly organized within a WordPress theme directory. We'll take a look at each of these in a bit more detail and the rationale behind their placement in the theme directory in hopes that this makes theme development cleaner and that this makes maintainability much easier.
Though in many contexts, these can be discussed independently of one another since they are responsible for different things, their organizational structure within a theme is so similar that it makes sense to group them together.
First, assuming that you're not using any type of CSS pre-processor, then there should be a directory for each of these types of files. That is, you should have a
css directory and a
js directory (or perhaps you'll call them
Whatever the case, each file type should reside in its own directory. From there, you can then use
functions.php to register and enqueue the files as needed. If it's a file that's used across the theme, then you'll unconditionally register it.
But if it's a style or a script that's only used on a particular template, a particular post type, or even on part of the dashboard, then you can - and should - enqueue the file conditionally.
But let's say that you are using a preprocessor. At this point, you're going to be left with your pre-processed file and your post-processed files. Depending on the nature of your project, you may or may not have everything reduced to a single file.
I would make recommendation for how to name files; however, the variation in themes, how people build their work, and the problem a given theme is trying to solve matters and that gets us beyond the scope of this particular strategy.
Anyway, if you're going to be using a pre-processor, then I recommend creating a subdirectory in the
js directories called
development or whatever you opt to call it). In this directory, you write all of your pre-processed files, then you let your tool of choice (be it CodeKit, Grunt, or something like that) output the processed file(s) into the root of the
This way, you still have processed, combined, and/or minified code, and you have a directory that contains the source of those files. When it comes time to ship the theme, you not only have the functions.php calling files in their respective directories, but you can also exclude the
dev directory from the final build so that the end user gets a smaller theme package, and gets nothing more than they need to run the theme.
2. Template Parts
Template parts are often referred to as partials (more so in other languages than in WordPress) and are often called by using
get_template_part in WordPress. In short, their purpose is to abstract out repetitive code that can be easily incorporated into multiple templates.
An example of this would be, say, the post meta data. This usually includes the following information:
- the author name
- the date the post was published
- the category and tags under which the post has been filed
- whether or not the post has comments (and, if so, how many comments)
Since this information can exist in multiple templates (think single posts, pages, archives, and so on) then it would make sense to abstract it out into a single file and just reference that one file when you need it.
The thing is, post meta data is not the only type of information that's reused throughout a theme. To that end, identify the core elements that are reused, abstract them into a file, then create a
From there, name each template part something that indicates what it represents (such as
pagination.php, and so on) and then make a call to the partial in the template where it's necessary.
For example, in post, page, and archive templates then you may call
get_template_part( 'partials/post-meta' );. Makes for a much easier read and makes for a single place to make a change rather than in every template.
If you're writing a theme that's internationalized which, if you're releasing it to the public, you should be doing, then there's very clear and clean way to do this.
First, if this is a new topic for you, then I recommend reading the article in the Codex. It will tell you all you need to know about how to prepare strings for translation, available tools, and so on.
Then, I recommend making sure that you have a dedicated place in your theme for your languages. Generally speaking, I recommend creating a directory in your theme named
languages and then dropping the
.mo files into said directory. This is also a generally accepted and expected practice within the WordPress community at large.
Not only does this relegate the translations to their own place within the theme structure, but it also indicates to others where to look for translations and where to look for the files that offer the strings that need to be translated.
Again, it's about cohesion and making sure that things of similar utility are grouped together in a reasonable way.
4. Helper Files and Utility Functions
Depending on your background in development, functions that you use to help get work done and to help separate business logic from presentation logic (or, in many of our cases, straight PHP from HTML), are called helper functions or utility functions.
For the purpose of this series, we'll be referring to them as helper functions, though know that they're all one in the same.
But this raises two questions:
- Shouldn't these live in
- If they don't live in
functions.php, where do they live?
In short, I'm of the mind that helpers and utilities should not live in
functions.php. My rule of thumb is simply this: If the code that I'm writing directly communicates with WordPress such as
add_theme_support, then it belongs in
functions.php. But if there's code that I'm writing that's going to be running a custom query to retrieve information and hand the processed result back to the template (or the template part), then it belongs in a helper function.
Just as WordPress has template tags or template functions that can be called throughout a template, such as
the_content(), treat helper functions in a similar way - you can call them in your templates and in your partials, but they're located in their own file.
Since these helper functions don't live in
functions.php, then they should live in their own file and that file should be referenced somewhere in the theme's codebase, right? On top of that, it's also completely possible that you may further break up your helpers into multiple files to based on the complexity of your theme.
To that end, I recommend introducing an
inc or an
includes directory in the core of your theme. From there, place your helper files in that directory and simple
include_once the helper file at the top of your functions file and the functions will be readily and easily accessible throughout the rest of your theme.
5. Third-Party Libraries
Finally, there are times where we will include third-party libraries into our themes. Simply put, these are tools that are developed by others that are freely available for use and distribution that also make it easy for us to piggyback on the work of others.
libdirectory within your
- Similarly, if you're doing something similar with CSS - such as incorporating icon fonts - then create a
libdirectory within your
cssdirectory. Again, this indicates that you have a CSS library.
- If you're incorporating a PHP library, then I recommend creating a
Of course, I've also seen some developers create a
lib directory and then create
php subdirectories within the
lib directory. It's a bit of an inversion of the tips provided above.
On WordPress Compatibility
Creating an organized directory structure is only part of it. WordPress has a template hierarchy that requires a certain naming convention. Doesn't it logically follow that our custom files should do the same?
Furthermore, what about the naming conventions of functions? Do they
echo data or
return data? On top of that, how we do know we're making proper API function calls and that we're not using deprecated features of WordPress?
In the next article, we'll talk about all of this as well as tools that we can install that help us avoid those pitfalls. We'll also discuss how they work and why they along with function naming conventions matter when building themes.
For now, however, we've covered strategies for file organization which should be enough to keep you busy until the next article in the series is published.
As usual, if you have anything to add, then please do so in the comments!