Underlying the entire WordPress template hierarchy is the locate_template function. locate_template
pretty easy one to understand: it checks the child theme for the template, then the parent theme and either returns the template path it found or loads it for you.
The idea is you pass it an array of template names with the more specific template names at the beginning. For instance, WordPress creates the array ["single-{$post->post_type}.php", "single.php"]
when it loads single templates.
What’s a Shortcode Anyway?
Shortcodes are a way to pull blocks of content (or whatever you want) into post content. We’ll make an imaginary shortcode that renders pulls in a little feature box for another post. You might use it like
[pmg_post_snippet id="123"]
and get something back like…
The code for this is pretty simple. We’ll wrap it up in a class to keep the hooks into init
and callbacks for add_shortcode
close by.
This small example exposes a big weakness to this approach: it’s nearly impossible for an end user to modify the content of the shortcode. Even if that end user will only ever be you, some flexibility is a good thing to build.
A way around this would be to add a filter that lets a user short circuit the display part of the shortcode callback.
This isn’t bad, but I think there’s a better approach that makes it easy for theme developers to integrate with third party shortcodes and make them look good.
Using Locate Template
Rather than hard coding the HTML into the shortcode, use locate_template
to look for a template in the theme to render the shortcode content. Fall back to your own template if one isn’t found in the themes.
Now all a theme developer has to do is drop a pmg-post-snippet.php
template in their theme to customize the output. As a nice side effect, it’s a great way to separate the view part of your shortcode from the logic aspect(s) — like checking to see if a post is published, etc.
The only thing of note in the example above is the safeInclude
static method that’s used to avoid giving the included template access to the objects $this
variable or any of the other variables in the showSnippet
method.
Why Not get_template_part?
Because we want to control the context passed to the included template. In the example above, I wanted to give the template access only to the $post
variable, not the usual set of the global variables that load_template sets up.
get_template_part
also doesn’t allow additional context (other variables) to be passed in. This isn’t a big deal in this example, but becomes more important with complicated shortcodes.
Other Applications
This same pattern works great for hiding re-usable theme components behind a function and when get_template_part
won’t suffice for the reasons outlined above.
For example, we wrote a small abstractions around loading a template to render a grid of posts this week for a client.
The custom query object meant get_template_part
was not going to work without messing with the global $wp_query
variable.