Even Smarter Post Formats

Dougal Campbell published an article the other day suggesting that the way many themes are handling the new Post Formats feature is wrong. While I completely agree that Post Formats shouldn’t be handled with giant if/else blocks, I’m not sure the proposed solution is the best option either. Here’s why.

What Dougal suggests is that theme developers instead dynamically include another template file to handle the post format. I’ve seen a similar idea suggested in a Trac ticket, and the issue I saw (but neglected to comment on) there is the same one I see here. Including PHP files is a relatively expensive operation.

Now, admittedly, including files isn’t the worst thing you can do, and WordPress already includes dozens of files for every page request. Still, that doesn’t mean you shouldn’t try to get as much performance out of your theme as possible. On an average page load on an average website, using the get_template_part() method for Post Formats will cause 10 additional includes, but what happens if the blog admin decides they want to display 50 posts per page? The solution doesn’t scale very well.

The alternate solution I propose is to dynamically call functions via call_user_func. When the name of a function is passed to call_user_func, that function is invoked. Incidentally, that’s actually how WordPress does function callbacks for its actions and filters.

Here’s how the code might look.

First, in your functions.php file, define functions for the Post Formats you wish to support. You could also place them in a separate file (like formats.php for example) and include that from your functions.php. That way you can keep your logic separated from your display, while only adding one additional include instead of ten.

1
2
3
4
5
6
7
8
9
function format_aside() {
// Code to display an aside post
}
function format_gallery() {
// Code to display a gallery post
}
function format_standard() {
// Code to display a standard post
}

Next, in your template, use the post format to determine which function to call. To make your theme more robust, make sure the post format is supported before you try to call the function. If it isn’t, call your backup “default” format function.

1
2
3
4
5
6
7
8
while ( the_loop() ):
$format = get_post_format();
if ( function_exists( 'format_' . $format ) ) {
call_user_func( 'format_' . $format );
} else {
call_user_func( 'format_standard' );
}
endwhile;

17 thoughts on “Even Smarter Post Formats

  1. Dougal Campbell

    Good point! My technique sacrifices a little performance for the sake of organization.

    I’m not positive off the top of my head, but I think that an opcode cache like APC or XCache will help mitigate the cost of including the same template multiple times in a view. In other words, once a template is loaded the first time, APC/XCache should cache a compiled version of it, and re-use that the next time it’s called.

    Reply
  2. Will Post author

    Yeah. I really like the simplicity of your solution. When I have a chance, I think I’ll try to do some benchmarking to test my suspicion that the performance difference is negligible. If it is, I’ll probably use your technique ;)

    Reply
  3. Dougal Campbell

    In my case, between APC and W3 Total Cache, I’m only going to take the hit the very first time one of the templates gets loaded. Once my page caching and opcode caching is done, it’s a non-issue :)

    Reply
  4. Edward Caissie

    This method just seems to push the “if/elseif” block of code into functions.php leaving much the same issue being addressed in Dougal’s post.

    Although I do like the use of the ‘call_user_func()’ as you are suggesting, I see it as best for one or two post formats being implemented whereas Dougal’s would be better for organization if “all” of the post formats are implemented.

    Reply
  5. Chip Bennett

    The other problem with this approach is that you lose the Parent/Child Theme template-file hierarchy inherent in get_template_part(), thanks to its call to locate_template_part().

    There’s a lot of awesomeness built into get_template_part() that, IMHO, far offsets any potential PHP performance hit the function incurs.

    Reply
  6. Will Post author

    Yeah, that’s a good point Chip. I thought about the Parent/Child theme issue, and one alternative idea I came up with was to call do_action( ‘format_’ . $filter ), but I scrapped that idea because I couldn’t figure out a good way to “fall back” to a default format handler.

    Reply
  7. Antonio

    Hello Will,

    so do you think is it better to use call_user_func() instead of doing an include?

    Does funcions.php load every time a page is loaded right?

    What do you thing is it better:
    1) To alway load funcions.php of lets say, 30 KB and use call_user_func
    2) To use include and just load the 3 or 4 Kb of a single function

    In terms of performance what do you think is it better, 1) or 2)?

    Thanks

    Reply
  8. Will Post author

    First, call_user_func is a native PHP function, so functions.php isn’t even required there.

    Second, functions.php is loaded for every WordPress page request anyway. If it weren’t, WordPress wouldn’t function (no pun intended) properly.

    Performance has nothing to do with whether functions.php is included. Instead, the question is whether the performance improvements gained by using function calls instead of includes is worth the extra complication it adds.

    Reply
  9. Antonio

    What I mean is that if you add many extra functions to functions.php, as it is usual in WP, your functions.php get bigger and bigger and you’ll finish with a very big html file.

    If you use includeds, you reduce a lot the functions.php. I believe that totla size of html is also a performance issue.

    So, what is better, to run an extra include or to load an extra non-used 30KB in your html??

    Reply
  10. Will Post author

    Ahh, I see what you’re saying. Well, you have a point, but the overhead of opening a file and reading its contents is generally higher than simply interpreting more code from a file that is already open. If you added enough extra data to functions.php, it would eventually become less efficient, but I’m fairly confident it would take more than 30KB, even though that’s an awful lot of code. All 4 of the loop templates included in Twenty Ten only add up to about 17KB, and they include a whole lot more than just the post formats (plus there’s a lot of duplication), so most themes should be a bit less (I’m guessing < 10 KB at the worst).

    Reply
  11. Antonio

    OK, I didn’t know, just asking.

    I am used to have a php include almost for anything :)

    Per instance I have head-end.php, body-begin.php, footer-begin.php and footer-end.php with an “include” at before , after , etc in order to insert the usual tracking and other plugin codes that have to be inserted in that concrete places instead ot manually insert them in every custom template I have.

    From your point of view, it would be better to add all this funcionts to functions.php and use the call_user_function() ??

    Per instance I also include many other parts of code where I have ads, related posts, etc. All this is much better with functions.php??

    Thanks and regards

    Reply
  12. Will Post author

    Possibly.

    What I usually do when I have several components that I want to reuse in multiple templates is to place them in functions in a separate file called “template-tags.php”, then call those functions from my templates. All I have to do then is include “template-tags.php” (once) from my functions.php, and those functions are available. The advantage of putting those functions in a different files is that you only need to include them on the front end. In the admin, they’re unnecessary. Of course, this is true of your method as well.

    In the end, do whatever you have the easiest time maintaining. The performance difference between one method and another, when compared with the entire execution time of a WordPress page request, is for the most part unimportant.

    Reply
  13. Rev. Voodoo

    Well, after reading Lisa Sabin-Wilson’s article first, then Dougal Campbell’s article…and then this article…. I hurt my brain. I’m fairly new to just sitting down, thinking up what I want, and making it happen. I’ve been a theme cut and paster for years….but I’m learning. I wanted to keep my loop template parts viable for child themers, but also implement the formats and have them available to child themers. So my solution was too first off-load all my template loops to loop-xxxx.php. And from loop-xxxx.php to format-xxxx.php. In my mind this gives child themers the ability to over-ride at the loop or the format.
    http://go.rvoodoo.com/WPformats
    Is my attempt. Now that may be a lot of including, but with caching and all, I wasn’t so worried about that end of it…. I was going for maximum child theme functionality. Again, I’m new…. so I have no idea if there are issues with my attempt…. but it seems to do what I was going for.
    So thanks for the read, your article and the other 2 I mentioned got me where I wanted to go!

    Reply
  14. Pingback: Using Post Format for this blog | Apathetic Moon

  15. Mr Opabinia

    Thanks for your insight folks, I’ve been learning WP in the last three months and what i like about it is its potential for modularity. WP has a great architecture and you need to leverage that power.

    Thanks to you all WP bloggers, you make my life so much easier !

    Opabinia

    Reply
  16. Pingback: Creating Post Formats | (Re)Learning Wordpress Development

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>