No, these are not something nailed to the door of the Wittenberg church. This is the number of queries generated on every page load on a lagging WordPress site I’ve been trying to speed up. The hosting is adequate and they are using a caching plugin and a CDN. They’ve done everything right but something is still very wrong.
A complicated theme will use extra queries and this is acceptable if you need extra loops or recent comments or other special items. However, the key issue in this case is a theme framework with its significant overhead coupled with a sidebar employing 10 widget sections and over 30 different widgets.
I don’t want to sound like a broken record, but themes that allow the user to change settings within the WordPress interface generate overhead. Widgets generate additional overhead. For a high traffic site or even a significant burst of traffic, this can bring a site to its knees.
</body> tag, load a page from your site and view the source to see how many queries were required to generate the page:
<?php echo $wpdb->num_queries; ?>
<?php _e('queries'); ?>.
<?php timer_stop(1); ?>
<?php _e('seconds'); ?>
Keep in mind that a bare bones vanilla template with no overhead and no widgets and nothing in it at all still yields a baseline of 12 queries.
How can you fix this problem? Well, optimally, you recode the entire template so it doesn’t use any widgets or settings stored in the database. Is this painful, expensive and unreasonable? Yes, yes and no. What if you are not currently in a place where recoding the template is reasonable? Well, then you try to optimize what you can and get the query count as low as possible.
Most themes store settings in the WordPress options table and access them using the get_option() function. The theme set I’m trying to salvage uses get_option() 162 times. Finding a way to reduce the impact of these calls is probably a good place to start. Simply getting all the theme options in a single query and using cached values instead of reading them when needed should help reduce the number of total queries on each page.
To do this, first we need to figure out how to identify the theme specific options. Usually there will be a prefix on each option name, so I’ve created a new function in functions.php that reads all the options with that prefix and then I call it:
function theme_cache_options($prefix) {
global $wpdb;
global $theme_cached_options;
$sql = "SELECT option_name, option_value FROM ".$wpdb->prefix."options ".
"WHERE option_name LIKE '%s' AND blog_id = %d";
$prepared_sql = $wpdb->prepare($sql, $prefix.'%', get_current_blog_id() );
$theme_cached_options = $wpdb->get_results($prepared_sql, OBJECT_K);
}
theme_cache_options(‘cow_’);
Second, we need a function that lets us read the cached option value:
function get_cached_option($key) {
global $theme_cached_options;
$result = isset($theme_cached_options[$key]) ?
$result = $theme_cached_options[$key]->option_value : '';
return $result;
}
Finally, we need to go through the theme itself, and change every get_option() call that references a theme setting to get_cached_option(). Be sure not to change any option requests that do not start with the prefix specified in the theme_cache_option() call.
Does this help? Well, it helps a little. With the site I’m working on, I’m seeing roughly a 10% reduction in the number of queries. Worth it? I think so.
Final note for theme developers: If you are going to store theme options in the options table, there is a fourth parameter for the add_option() function that you should really be aware of. If you set $autoload to ‘yes’, then WordPress will automatically load and cache that option when it fires up. This means that get_option() calls for any option that was created with $autoload set to ‘yes’ will not generate any additional queries.



