When we first had Standard accepted into the WordPress.com marketplace, one of the number one priorities that the Theme Team suggested was to use WP_Query in place of raw queries or in place of query_posts.
And for the work we were doing, they were right.
For what it’s worth, I’m all for using
WP_Query. Generally speaking, if there’s an API available that allows me to interact with the data layer rather than using raw queries, I am for it regardless of the framework. That’s exactly the case with
Straight from the Codex:
The wp-blog-header.php (or the WP class in Version 2.0) gives the $wp_query object information defining the current request, and then $wp_query determines what type of query it’s dealing with (possibly a category archive, dated archive, feed, or search), and fetches the requested posts. It retains a lot of information on the request, which can be pulled at a later date.
Sounds awesome, right? And it is.
But in all of the WordPress work I’ve done over the past couple years, I had to resort to using a raw query in a recent project and had a decent case for when not to use
Or so I thought.
What’s the problem?
In this particular project (that I’ll cover in more detail in a few days), I’m storing a single piece of post meta data. Strictly speaking, I’m storing a unique key with the ID of a single category.
The sample code looks like this:
add_post_meta( $post_id, 'sticky_key', $category->cat_ID );
On the first page of any archive index, I needed to pull back the post associated with this meta data regardless of where it falls in the list of archived posts.
But trying something such as:
$sticky_query = new WP_Query( 'orderby=date&order=asc&meta_key=sticky_key&meta_value=' . get_query_var( 'cat' ) );
Didn’t work. Instead, it lead to the following
In case it’s unclear, that’s PHP memory allocation error:
Fatal error: Allowed memory size of 33554432 bytes exhausted (tried to allocate 523800 bytes)
Granted, I could increase the amount of memory allocated to WordPress, but this isn’t something that’s necessarily easy to do across the shared web hosts so it’s not really a feasible option.
So what’s left to do?
After all was said and done – and this includes trying various actions, filters, storing it creatively in private attributes, etc., you name it – I ended up falling back to
$wpdb and doing a direct query to pull back just the post ID.
global $wpdb; $post_id = $wpdb->get_var( $wpdb->prepare( "SELECT post_id FROM $wpdb->postmeta WHERE meta_key = %s AND meta_value = %s ORDER BY meta_id ASC LIMIT 1", 'sticky_post', $category->cat_ID ) );
And it works and it works fast. Then again, there’s very little overhead when trying to pull back a single value from the database, right?
As Konstantin points out in the comments, this query still isn’t optimal – though it retrieves the post idea for the conditions, it doesn’t discriminate against post drafts, password protected posts, and so on. Thus, you’d technically be left with a post ID being returned that may compromise what the user was actually hoping to display.
So what’s the resulting call to
WP_Query that I ended up using?
$sticky_query = new WP_Query( array( 'fields' => 'ids', 'post_type' => 'post', 'posts_per_page' => '1', 'meta_query' => array( array( 'key' => 'sticky_post', 'value' => $category->cat_ID, ) ) ) );
And a h/t to Kovshenin for the gist.
Raw Queries To The Rescue?
So here’s the thing: Attempting to pull back a single value from the database feels more like a job for
$wpdb than using
But after a conversation that went from the comments into Skype, it’s more of a matter of truly understanding
WP_Query and a deeper level – territory I’m still definitely still exploring.
All that to say, we often hear to “WP_Query all the things!” and until recently, I was skeptical. It seemed that the API was better suited to some situations rather than others.
But that’s not necessarily accurate.
Definitely feel free to share any additional thoughts or questions on
WP_Query - surely I’m not the only one who could benefit from all of this .