Underscorefunk Design

Design, Illustration, Interaction, and Artistic Direction

Action driven WordPress themes without templates

One of the things that drives me a bit nuts with WordPress is having all of the template files living under the theme root. I think the true power of WordPress can be found in approaching it as an application platform. If we want to fully commit to this approach we’ll need to think about each request as a ‘request’ and not a ‘template’.

Let’s put conditional display logic as a control before loading partials/output instead of needing to filter template_include or anything more complex or opaque.

There are some really major benefits in doing this:

  • It’s pretty easy to get major components (or any component for that matter) of the site as an AJAX response because all output is created via actions that call get_template_part. You can capture buffers with ob_start() and ob_get_clean()
  • Conditional statements now happen before ‘get_template_part’ which creates a really nice separation of concerns. We no longer care about if something should display when we’re coding output.
  • We get better profiling because we can add time stamps before and after specific actions to measure the efficiency of output.
  • We can capture buffers and cache the output of the template action.

Some caveats:

  • You’ll still need to have a header.php and footer.php in the theme’s root so that other plugin’s custom templates remain compliant with your theme. They may have templates of their own that do things the traditional way, calling get_header(); and get_footer();

I’ve written about loading template parts with actions, but I haven’t touched on how to free yourself from WordPress’ default templates. We’re going to use the same engine room approach but with a few tweaks.

You’ll notice a few things that I do here to keep everything straight:

  • Prefix actions that are called from the theme using ‘theme_’. This makes it much easier to integrate other plugins (i.e. a plugin can hook theme_singular_header, etc). Plugin actions would be prefixed with a plugin prefix like ‘my_awesome_plugin_’ because there are multiple plugins. There is only one theme so I opt to go with something generic.
  • Actions are suffixed with their object and/or context. This makes it easy to see which level I’m working on; am I performing an action for the whole site or for a specific part of the site.

This might seem a little overwhelming but it will make sense if you keep in mind that we’re just repeating this process:

call an action*hook the action with a callback function that loads a template part→have partial generate output that either calls an action (repeating the loop)* which we’ll call container components, or generate output, which we’ll call content component.

Your theme file structure

Your theme will look something like this. I am including this early to give you a roadmap of where we’re going. This list of files isn’t exhaustive and intended to help you visualize your site’s structure with this new approach.

You’ll have additional folders in there and sub folders for ‘partials’ and ‘structure’ that contain actions and their corresponding output partials for other components.

Main Template (/index.php)

Here’s the file that will handle all of our requests.

Site Header (content component example)

/header.php – Header action call. This file is loaded by get_header();

/includes/structure/hooks.php – Header action hook

/includes/structure/site/header.php – Header action callback

/partials/site/header.php – Header output (the header is a content component)

Site Body (special case – container component example)

/body.php – Site body action call. The site body is one of the few cases where theme output might live outside of a partial. The reason we’re not using do_action( ‘theme_site_body’ ) in index.php is because its partial would need to call do_action( ‘theme_site_body’ ), creating a loop of actions calling themselves.

Singular (container component example)

Here’s our first true example of replacing a WordPress template with our new approach.

/includes/structure/hooks.php – Singular action hook

/includes/structure/singular/singular.php – Singular action callback

/partials/singular/singular.php – Singular output

Engine Room (/includes/structure/_hooks.php)

Here’s a better view of the structure hooks.

To summarize, here’s the pattern


add_permastruct with a struct containing %post_id% is creating endpoint rewrites, even when I specify EP_NONE

Why rewrite… why!?…

This had me vexed for a while until I followed everything all the way up to where rewrite rules are being generated. It turns out that if you include the rewrite tag %post_id% in your permastruct, WordPress will assume you’re making a permastruct for the ‘post’ post_type and will add all of the endpoints (talkbacks, comments, attachments, etc)… even if you said not to by passing EP_NONE in the add_permastruct args.

Here’s a comment from class-wp-rewrite.php around line 1070, highlighting the exact spot.

“Check to see if this dir is permalink-level: i.e. the structure specifies an individual post. Do this by checking it contains at least one of 1) post name, 2) post ID, 3) page name, 4) timestamp (year, month, day, hour, second and minute all present). Set these flags now as we need them for the endpoints.”

It basically does this check and then creates all of the endpoints. Lovely isn’t it? :/

If we take a look at the global $wp_rewrite object, you’ll see that $wp_rewrite->rewritecode contains all of the tags. There’s only one post_id like item, which is %post_id%.

The bottom line

Update: Here’s the solution I went with.

Use %p% now instead of %post_id% in your permastruct and everything should work fine.

Just thought you should know…

Using engine rooms to create WordPress partials output runtime

Caveat: I mix a lot of metaphors here. They’re nautical in nature. 🙁

On a ship, the engine room is literally where the engine lives–the great contraption that propels our vessel through water. For our purposes we’re going to think of engines as smaller contraptions that drive specific parts of our website. In practice they look more like a series of connections, almost more like a control room. See ‘hook.php’ below for an example of what you might find in an engine room file. This might not make a ton of sense right now but it will once you’re done reading this article.

It is worth noting that I will be presenting the engine room concept in relation to the rendering and output of a template’s content. This approach and the thinking behind it can be applied to other areas of your development as well.

The problem being solved

Traditionally I see a lot of folk with a function definition followed by the function’s hook, like this:

The problem I have with this is that you’ll often have an absolute ton of these declarations in a single file. That much code can make it difficult to see what’s really going on. Ultimately I’m going to have two different sets of needs here; I want a general overview of the course my ship is taking (the runtime of what is happening and in which order), and the ability to really look at what is going on during a specific part of the process.

If I’m editing the specific part, I don’t care about the general view. If I’m looking at the general view, I’m probably not too concerned about the minutia of a specific part. Being conscious of these different concerns will help me stay efficient.

It’s for this reason that I like to split things out. What we’re doing is:

  • Keep all runtime easy to understand in a single hooks.php engine room.
  • Keep all dispatchers that handle which output to load in separate php files.
  • Keep all output in partials and templates files.

The benefits are:

  • High level of clarity–it’s easy to see what is happening and when
  • It’s easy to inject additional content in the runtime
  • Painless incremental template customization
  • It’s very DRY (Do not Repeat Yourself)


I use this approach in object oriented development, calling the method that I named “register_hooks()” in the a plugin’s constructor.

We’re going to take a look at how our pages render and create a structure for the site though a series of actions that call partials either render output or call other actions (or both).

Here’s a quick look at a simplified file structure. Currently it only shows one sub-folder within structure called ‘singular.’ When a whole theme is built out you’d end up with sub folders for each major component. I’ll discuss my approach to implementing this for global templates like archives.php and front-page.php in a later article.

This assumes that you’re including the required php files (hooks.php, singular.php, etc) in your function.php file or somewhere else in the template.

hooks.php (structure engine room)

Our engine room is simple. It’s just a series of actions. The elegance of this is that you can easily see that theme_singular is going to call a header and then a body, and you can easily see that theme_singular_header is going to call a heading.

At this point I hope you can see how easy it would be to add another hook for a featured image banner before the theme_singular_header, or add a footer after the theme_singular_body.

singular.php (hook callback functions)

Here’s a quick look at the callback functions. I like to think of these actions as dispatchers and never put any output in them. Output is always relegated to templates and partials.

I’m adding the post type name to the get_template_part request so that I can override content easily on a needs basis. For example, I can have a heading for my post type ‘book’ by creating a file in partials/singular/heading-book.php. If it exists, that file will be used. If it doesn’t exist, the default partials/singular/heading.php will be used.

I apply a filter to the post type name ($name) which receives the content in which the filter is being called. This allows me to override specific parts for specific post types. This allows me to easily modify the name by another plugin to load custom partials. $name doesn’t always need to be the post type name. It could be ‘book-featured’.

header.php and heading.php (component output/partial)

Sometimes the partials are micro templates of sorts, like the header.php partial. Other times they might just output content, like the heading.

header.php (a container partial)

heading.php (a partial with content)

In use

Using this set of partials would look something like this.

I don’t think it gets much more clear than that.

Styled Components with PHP/CSS in WordPress

Templates and plugins can have a lot of different output components (partials) which are loaded via get_template_part(). It can sometimes be tricky to keep everything straight and organized. I’ve tried a lot of different approaches and settled on one to keep everything organized and clear. This approach requires you to treat each individual component as a completely stand alone block. The beauty of this is that decoupling components creates freedom and clarity for developers! 😀

In an ideal world the development cycle would look like this:

  1. A client requests that I change the way headings for book summaries are output.
  2. I edit the content (PHP) of the book summary heading.
  3. I edit the appearance (CSS) of the book summary heading.
  4. I commit the change to my version control with:
    ‘Add a line break after the first semi-colon and make the font size smaller’ showing 2 edited files:
    /partials/singular-summary-book/heading.php  ← content
    /ui/components/singular-summary-book/_heading.scss ← appearance

It’s easy to see what the change was, where it happened, and reverting to previous versions doesn’t really impact anything else on the site. That sounds pretty stress free to me. Again, we’re aiming for transparency, clarity, and consistency here. I might change ‘components’ to ‘partials’ in the UI folder to be even more consistent. There’s always room for improvement 🙂

Component Output File Structure (PHP)


Each individual output block should be a component and separate file, stored in its parent component, within the partials directory of a theme or plugin.

At this point it’s important to make a few distinctions regarding the naming conventions I employ.

  • singular denotes that a post/post-type object is being viewed as a complete and whole object. (e.g. You’re reading the whole article/post/whatever). It is the focus of the reader/user.
  • singular-summary denotes that a post/post-type object is being summarized and not presented in its entirety. (e.g. You’re reading a teaser which links to the full article).

These components can then be suffixed with their post-type name to create things like singular-movie, or singular-summary-movie, or singular-summary-book.

This yields a structure that is very clear, organized, and allows developers to easily extend components or override them by adding additional files.

We can imagine that singular.php would contain something like this.

… some output here …

ing for this component is now a cake walk.


WordPress sets a series of classes in the <body> tag which can be filtered by the body_class filter. For single post/post-type pages it adds ‘single’ and ‘single-{post-type}’. We’re using ‘singular’ and ‘singular-{post-type}’ to avoid that conflict. Just be aware that when creating partials you’ll need to watch out for conflicts like that, or your styling might cascade in ways that you don’t expect.

Coming soon

  • How I employ this approach to loading archives and other partial types.
  • How I populate the content of these components/partials in a later post.
  • How I create overrides that cascade.

Component Style File Structure (CSS)


Each component has a matching style file that only styles itself. In this example I’m using SCSS files which are processed and joined into one big (but minified) CSS file. This 1:1 relationship is really important and will help you keep the source code organized. I’ve decided to call the folder ‘ui’ instead of ‘styles’ because styles are now closely coupled to user interaction (javascript). With this structure it’s easy to keep everything (css and js) in the same place. Note _heading.js which handles the user interaction for _heading.css.

We can imagine that singular.scss would contain something like this.

In this example I have the presentation of ‘.singular’ changing because of the context ‘.threatre-view’ (a parent object with that class, possibly even in the body tag). For example, let’s say that someone clicks on the ‘theatre view’ button which adds the ‘theatre-view’ class to <body>. As a result we might want to compress the way singular items are being displayed.

One school of thought would argue that all ‘theatre-view’ modifications should exist in a ‘theatre-view’ css file. The problem I have with that is you’ve now separated context from target. In my mind, those two have strong coupling and should live together.

I’ve grown to appreciate what I’ll call a styled-component approach. In the react world, the styles would live with the output. We can’t quite get there with PHP, but this is pretty close


Output components

It’s important to have common language, naming conventions, and a consistent structure for your code. Flexibility is great in a lot of ways but loosely coupled names/meanings can create confusion, sloppy code, or the dreaded mental overhead of trying to pick the perfect name for something.

For this reason I like to force the following rules for naming/organizing files that generate output.

Templates: A file that composes output top to bottom, from outputting file headers to the end of the request response. Loaded through the template_include filter.

Partials: A chunk of output that is not a complete template. Output through the get_template_part() function.

While partials are a template of sorts, I like to make this distinction for the sake of clarity. It’s also encouraged by some of WordPress’ naming conventions. In my mind, the idea of loading a file from /partials through get_template_part() makes a lot of sense. I’m loading a part and it’s in ‘partials’. On the higher order side of things, loading a file from /templates through the template_include filter makes a lot of sense too.

I really wish WordPress would have enforced some structure like this from the get go instead of tossing everything into the theme root folder. I’ll expand on some solutions to force WordPress to be a bit more organized later on, as well as going into detail about how I organize my partials.

Use filters instead of functions

While writing code we should always be striving for clarity and consistency. As time has gone on, I’ve learned to value this over being clever. The resultant code is perhaps not as elegant, but it’s a lot more maintainable.

A lot of WordPress code I’ve seen involves something like:

Why do I think this is problematic?

  • You have to declare the default in advance.
  • There is inherent concern about if the function exists (or if the plugin is activated).
  • Creating overrides is difficult and not very clear. Each function needs to be wrapped in a ‘function_exists’ check and overrides are based on the order of declaration.
  • Changing the plugin (or initial function’s) arguments can break other plugins or implementations of the function.
  • It’s difficult to see where overrides are taking place because overrides are based on the order of declaration.

The solution

I believe using filters to get values instead of most function calls is a betters solution. The resulting code would look like this:

Some of the benefits are:

  • The default value is implied in the filter’s application.
  • The filter doesn’t care if a function is hooked into it.
  • Overrides can be added with priority instead of at run time.
  • Adding additional filter arguments doesn’t break existing implementations.
  • All functions hooked to the filter can be inspected.
  • It’s easy to see what’s happening in plugins that list all of their hooked actions in a block (an engine room of sorts).

Implementation and Extras

Here are a few things I do in implementation to make this all work nicely.

  1. When I hook the base function for a filter, I set it to priority 9, so that it runs before all of the default subsequently hooked filters would run.
  2. I make the assumption that a certain value is required to allow the hooked function to run. If it doesn’t meet this criteria, the function will assume that a hooked function ran before the default one at priority 9. This avoids double processing.
  3. I always prefix filters with my plugin’s name followed by two underscores.
  4. I build everything with OOP these days and often I’ll find myself checking the result of uf_some_plugin__get_instance against if ( $some_plugin_obj instanceof \UF_Some_Plugin ). In this situation I instantiate the plugin as a single variable and then use the filter to get its instance instead of using static classes and singleton nightmares.

Here’s how it looks in practice.