Enforcing WordPress Image Sizes Within Your Theme
As a designer and programmer here at 10up, I have the unique opportunity to see my design through from the first wireframe to the fin
al product. There’s nothing that makes me grimace more than turning control over to a client only to see the design fall apart with use. Ensuring that as little as possible is “breakable” is on top of my quality assurance list. WordPress’s native, customizable image sizes is a common cause of breakdowns.
How I use image sizes in designs
Nothing disturbs my blank white canvas in Photoshop until I have set the grid and guides that will determine the structure of the layout. As I begin to flesh out the design, image placeholders find their way in, and they’re always made to fit within those guidelines. Common placeholders include a featured slider image, a thumbnail for the main index/search/archive post list view, and a special size for the “image” post format. Most of the time, I want images used within posts and pages to use these same consistent sizes so that the layout stays as clean as possible. Call me OCD, it wouldn’t be the first time. (Editor’s note: all great designers are a bit OCD!)
I could create predefined image sizes for each call to an image attachment (and I often do at least one or two of those), but defining an endless set of sizes has a real performance toll every time an image is uploaded, not to mention the bloating effect on the upload directory. If I define 5 custom sizes, and we add that to the 3 default sizes (thumbnail, medium, and large), we wind up with 9 sizes, counting the original. That’s 9 images generated every time an image is uploaded to the site. I always try to avoid the weight and clutter by using the default image sizes.
Enforcing the image sizes
It may have crossed your mind that this breaks my own OCD rule, as administrators can adjust default image sizes from the Media settings page. But wait – that’s what this post is all about! Let’s get to some code.
First, we need to ensure that the customizable default sizes (thumbnail, medium, large) are set the way we want. You may be tempted to just drop the necessary update_option()
functions into your functions.php file. It’s okay, I did, too, until one of my teammates, Helen, helped me find a better way. We can actually save on performance and only run those functions once by hooking into 'switch_theme'
– which fires when your theme is activated. That’ll look something like this:
add_action( 'switch_theme', 'themename_enforce_image_size_options' ); function themename_enforce_image_size_options() { update_option( 'thumbnail_size_w', 180 ); update_option( 'thumbnail_size_h', 180 ); update_option( 'thumbnail_crop', 1 ); update_option( 'medium_size_w', 390 ); update_option( 'medium_size_h', 390 ); update_option( 'large_size_w', 660 ); update_option( 'large_size_h', 660 ); }
Since this code only runs on activation, we also need to ensure that an administrator won’t override these settings later. To do this, we’ll use a filter that WordPress applies before saving a new option value: 'pre_update_option_{$option}'
. (Props again to my girl, Helen!)
add_filter( 'pre_update_option_thumbnail_size_w', 'themename_filter_thumbnail_size_w' ); function themename_filter_thumbnail_size_w( $newvalue ) { return 180; } add_filter( 'pre_update_option_thumbnail_size_h', 'themename_filter_thumbnail_size_h' ); function themename_filter_thumbnail_size_h( $newvalue ) { return 180; } add_filter( 'pre_update_option_thumbnail_crop', 'themename_filter_thumbnail_crop' ); function themename_filter_thumbnail_crop( $newvalue ) { return 1; } add_filter( 'pre_update_option_medium_size_w', 'themename_filter_medium_size_w' ); function themename_filter_medium_size_w( $newvalue ) { return 390; } add_filter( 'pre_update_option_medium_size_h', 'themename_filter_medium_size_h' ); function themename_filter_medium_size_h( $newvalue ) { return 390; } add_filter( 'pre_update_option_large_size_w', 'themename_filter_large_size_w' ); function themename_filter_large_size_w( $newvalue ) { return 660; } add_filter( 'pre_update_option_large_size_h', 'themename_filter_large_size_h' ); function themename_filter_large_size_h( $newvalue ) { return 660; }
If you’re worried about administrators getting confused when they try and change the option – only to have it pop back to its prior value – you can always hook into admin_enqueue_scripts and add some CSS or JavaScript to hide those input fields.
Conclusion
Using these blocks of code, we can set and enforce these core WordPress options with the smallest performance hit possible. Of course, the 'switch_theme'
hook and the 'pre_update_option_{$option}'
filter can be used together to easily control any option. I’d love to hear about your experiences with image sizes and thoughts on this code, so please leave your feedback in the comments below.
Comments
Brady Vercher on
Hi Tammy, thanks for the thoughts on working with multiple image sizes and code. It’s always felt a little awkward having so many different sizes generated (most of which never get used) when an image is uploaded and it’s something I figured might have been improved by now. In any case, filtering the default image sizes is a nice approach.
Along the same lines, you could also filter these options when they’re requested via
get_option()
and not worry about the initial setup on theme switch. Here’s a slightly modified approach usingcurrent_filter()
to determine which option is being updated so everything can be managed in the same function.Thanks again for sharing!
Jake Goldman on
That’s another performance friendly way to do it! It’s a bit 6 and 1/2 dozen – your approach will actually execute the filter far more often (every page load in fact, when default options are loaded up), whereas Tammy’s described approach only runs when the theme is switched or an update to that option is attempted. But certainly light weight and clean!
Brady Vercher on
Like you mentioned, the differences are negligible in this case–just thought I’d offer up an alternative approach.
For what it’s worth, filtering on read doesn’t actually fire when options are autoloaded, only when the specific option is requested. It short-circuits all the logic performed in get_option(), so I think it “should” be faster when returning hard-coded values like this. For anything more intensive, I’d definitely do it on update like Tammy did.
Hans on
Nice solutions Jake & Brady, just what I was looking for. Both seem efficient, although in the solution of Jake I like that the db is guaranteed to contain the same option value as the presented value.
I find there are a lot of theme’s and plugins that seem to just define their own sizes and do nothing with the default thumbnail sizes, so they are cut/cropped without even being used. Using a retina 2x plugin doubles the number of unused images also.
Some even define several versions of the same size, using semantic / functional names. The disadvantage of that is that external services that optimize the images are fired several times for the image lowering the quality and adding to the cost of that service. So perhaps using the default sizes and redefining them to a size that is more useful for the theme might be a better practice.
Tammy on
Jake is right on the “perform once” logic, but I do like how you combined the functions into one filter. You could apply that to the original pre_update_option_* method.
Devin Price on
Nice write up!
Seems great for a client site, but something to be careful about in a publicly released theme. You’d have to be really clear that you were changing a default, and allow users to opt-in/out.
Jake Goldman on
Good point, Devin. I think you could still get away with it in a public theme depending on its use case (as long as you don’t remove full sized images), but you might want to massage the media settings screen to be clear about the impact.