10 WordPress query_posts tips you probably don’t know

I have written a really brief query_post tutorial before, and it did quite well, but both WordPress and my own skills, have advanced considerably since then. So I thought it would be interesting to revisit the query_posts command and see what has changed.

The query_posts command is one of the most useful in all of WordPress. It is this command that allows all the content to be queried (extracted from the database) and then displayed by the loop. It’s powerful because it gives an incredibly flexible method for retrieving and filtering the posts and pages in pretty much any way you can imagine.

At its most basic you can use query_posts to grab just the single latest post, or to get the latest 100 posts. At its most complex you could select a random collection of the posts that a specific blog author has posted in a collection of site categories with a specific tag – although why you’d want to do that is a mystery to me 🙂

The query_posts page on the codex is a great resource for picking up new ways of doing things but there are probably areas you miss (or skip) when reading it, and below are some of the more interesting features you probably don’t know.

1. Everything changes

The first thing to note is that the best way to use the query_posts command… is not to use it. On the query posts page itself there is this comment:

The query_posts function is intended to be used to modify the main page Loop only. It is not intended as a means to create secondary Loops on the page. If you want to create separate Loops outside of the main one, you should create separate WP_Query objects and use those instead. Use of query_posts on Loops other than the main one can result in your main Loop becoming incorrect and possibly displaying things that you were not expecting.

2. Different Queries

The ‘traditional’ method for using query posts, and the method I have used throughout this tutorial, is to pass the query posts parameters in query string format (eg variable1=value1&variable2=value2&…), however for the last year or two there has been a move towards using arrays for setting the query parameters. This is a method I have been slowly transitioning to over the last year or so and it’s definitely nicer to use, however for quick queries, you can’t beat a string of text 🙂

Clearly which you use is down to personal preference but I feel that the array option is better for a few reasons:

It is easier to read

You can more easily add conditions to the array using if statements to dynamically create queries

Some of the query parameters (albeit less frequently ued ones such as some of the category and Tag parameters) need to have arrays passed to them.

You can pass a function call as a parameter (as demoed in Tip 6 below)

3. order, order

By default posts are sorted by date, and in most cases that’s all you need, but being able to change the order is also quite handy. For instance you can order posts alphabetically by post title or grab a random handful to display in your sidebar. In WordPress 2.9 the ability to order by comment count was introduced, so that makes popular posts easy to display… assuming you don’t want to use the simplest popular posts code ! 🙂

4. Meta Values

Before building WordPress Vote I wasn’t aware these options existed but they ended up being incredibly helpful. On WPVote I store the number of votes using the post meta functions (update_post_meta), so to select the most popular votes I can do:

5. Posts? Pages? Attachments?

Posts are what is queried as standard, but you can filter by post type, which currently lets you looks for posts, pages, and attachments – no doubt this will grow in the future. Of the three I think selecting Attachments could be the most interesting and underused. Using this (and the order parameter above) you could easily build some sort of random media display into your site:

6. Sticky Posts

Sticky Posts were introduced in WordPress 2.7. They are an easy way to keep specific blog posts at the top of the post list, without messing around with post dates. The standard sticky posts behaviour (across all of the query_posts queries) is to add themselves to the front of the list of returned data. There are two things you may want to do with the Sticky Posts filter.

7. Grab all posts

There are a few different ways to select all the post that have ever been published and this would mostly be used for sitemaps and archive pages. These are great for Google, so I would always recommend having one. The parameters you can use are:

<?php
// showposts is the traditional way of doing it, but it's now deprecated so could be removed at any time
// there are still lots of themes that use showposts (including my own) so it's worth switching over as soon as you can just in case
$query = 'showposts=-1';
$queryObject = new WP_Query($query);
// The Loop...
// the new way to do it
$query = 'posts_per_page=-1';
$queryObject = new WP_Query($query);
// The Loop...
// must admit I have never tried this myself but according to the documentation it will work :)
$query = 'nopaging=true';
$queryObject = new WP_Query($query);
// The Loop...
?>

8. Hooks and Filters

One of the lesser known features of the query_posts functionality is that you can hook into the generated queries. This can actually be quite dangerous, but is also incredibly powerful. WordPress has a number of filters for modifying elements of queries.

Grabbed from the Advanced WordPress Filters section of the Filters reference on the Codex, the filters you can apply to your queries are:

post_limits

applied to the LIMIT clause of the query that returns the post array.

posts_distinct

allows a plugin to add a DISTINCTROW clause to the query that returns the post array.

posts_groupby

applied to the GROUP BY clause of the query that returns the post array (normally empty).

posts_join_paged

applied to the JOIN clause of the query that returns the post array, after the paging is calculated (though paging does not affect the JOIN, so this is actually equivalent to posts_join).

posts_orderby

applied to the ORDER BY clause of the query that returns the post array.

posts_request

applied to the entire SQL query that returns the post array, just prior to running the query.

posts_where_paged

applied to the WHERE clause of the query that returns the post array, after the paging is calculated (though paging does not affect the WHERE, so this is actually equivalent to posts_where).

posts_join

applied to the JOIN clause of the query that returns the post array. This is typically used to add a table to the JOIN, in combination with the posts_where filter.

posts_where

applied to the WHERE clause of the query that returns the post array.

The query_posts parameters are so comprehensive that most people won’t need to touch these, but the reason I discovered these is that I was trying to sort a query by its numeric meta_value however the meta value is a string field type (which means the numbers were ordered – 1, 10, 11, 2, 23, 3 etc.). So I wanted to cast the sort order as an int to be able to sort numerically… and this is what I ended up with:

10. Exclude posts from showing (hide duplicate content)

This next (and final) tip is actually something written by Ronalfy on WebLogToolsCollection a couple of years ago – and I now use it in all of my themes (Elemental, and Mimbo Pro both have it built in).

The idea is that the code will stop duplicate posts from being linked when you use multiple WordPress loops on a single page. For example I use it on the homepage of this site so that I can show the latest posts, and then display my categories without worrying about if the latest posts will display again. This means that more different posts will show on the homepage.

My code has evolved from the original code so I will leave the example there for explanation of how it works and post my sample below so you can see what I have done:

Then to use this you would do your loop as normal, and call ‘bm_ignorePost($post->ID);’ for each post you want to ignore. The following example uses the same query twice, but will display totally different posts on each output.

I used query_posts quite a bit when I first started with WP, it’s only in the last year or so that I did it “properly”. And yes – I’ve had a number of issues with query_posts that prompted me to start doing it properly. Most of the issues revolved around widgets and such that would pull up the data for other posts – and then trying to access the actual current post content.

I was using WP_Query in a function called from the sidebar. Later in the sidebar there are calls to next_post_link and previous_post_link, and these would return the wrong links after calling WP_Query, as if there was some interaction between my query (using $queryObj) and whatever else WordPress does in the background.

It’s very possible I could have been doing other things wrong, but I was pretty stuck and grabbed on to the get_posts rope when it was offered. 🙂

I have a quick question about the posts_per_page parameter. I’ve created a custom query. I’ve made it so that if an event has expired, then it’s not displayed in the query. My problem is that the posts_per_page parameter is counting my “expired” events. Therefore, If I set the parameter to 3 and 1 event is expired, the query actually only shows 2 events. How can I trick the query or fix this issue? If you want, I can send you the code that I’ve done. Thanks!

Fantastic list of awesome query_post tips, and very well-explained man. Thanks so much. I was struggling with getting WP-Coda to behave and playing with the query_posts parameters saved the day! Rock on!

But I want to reorder the posts according to what the user clicks on.
If there are posts on a “services” category page and under them are “residential” and commercial and “real estate”. If the user (elsewhere on the site) clicks a link for residential I want to go to the services page but the residential post to go to the top.

This all depends how your theme is coded. The link itself makes no difference, it’s where it links to that is important. If you want to have a page that links to different content then I would have three pages that display things differently.

I would like to access WP_Query and loop back through the posts from within a plugin. Do you have to have a separate loop code block within the plugin as well.

In other words when wordpress loads it runs through the loop within its index file. To loop through the posts and modify them , I am thinking of rewinding the posts, then instantiating a new WP_Query object and looping through them again , within the plugin making modifications as I go. Does this make sense?

Hello, thank you for the list! On #4 Meta Values you mentioned that you store votes in custom meta values. Will it be more efficient if you store votes in a separate database table? The postmeta table carries a lot of data. I ask because I’m developing a personal voting plugin and it’s pretty complicated querying and ordering from custom tables. Your method seems easier but I’m concerned about query speed issues.

To be honest I think this is a judgement call you will have to make. I did everything in post_meta because I could use the build in WordPress functions but if you plan to use the table a lot then you may be better off creating a brand new table designed for your project. I think both approaches have merit so you just have to plan as much as possible and make the decision based upon that.

Nice!! I was looking for a way to change the order of my posts. It can get quite frustrating to see the same written articles always at the top of your blog. This is a great way to show readers, different posts.

you save my day really i spent the whole night in fixing
widget and ALL in one SEO PLUGIN conflict.
i just change the query_posts way that is mentioned above in your post.
and it worked very well still dont understand how it is fixed.
i simple changed the way of query posts n tha’t
any ways again thnkx buddy. 🙂
one thing more how i can subscribe on your blog using email .

I want to display all posts by category order but am struggling to find how. Following this post I have implemented WP_Query and have tried various orderby options with no success. Have scoured the codex and everywhere else with little success. Hope you can help.

I’m using the Query Post plugin and it’s great, but I need to use it more than once. I have other categories i want in a separate widget. For instance, my first one is posts about writing, the second i want to do is posts about Relationships. How do i implement the use of this plugin more than once?

I have a quick question about the posts_per_page parameter. I’ve created a custom query. I’ve made it so that if an event has expired, then it’s not displayed in the query. My problem is that the posts_per_page parameter is counting my “expired” events. Therefore, If I set the parameter to 3 and 1 event is expired, the query actually only shows 2 events. How can I trick the query or fix this issue? If you want, I can send you the code that I’ve done. Thanks!

My code…

= time()-3600) {
?>

The query is working but as posts expire, this list gets shorter because the numberposts=9 is sill counting expired posts!
Is there any way of excluding posts that have expired from the loop so they are not counted?
Any help would be much appreciated!
Cheers,
Mark.

How would I use this to hide a specific post, using the id from all post query pages. My scenario is I’ve made a post and have featured it on my homepage. On the bottom of the homepage it pulls all of the latest posts. I don’t want it listed there. I also have another page that lists this post type and I don’t want it to show there either.

You need to use 2 loops I think.
1. A loop to get the posts that have that custom value , the eons you don’t want.
2. The second loop using the post_not_in argument , using the returned ids from the first loop.

Thanks Barbio,
I’m quite stuck with this. Can I ask/hire you to write this query?
The custom field name is ‘city’ and the value would be ‘Melbourne’.
So I need to exclude all posts with the ‘city’ custom field value of ‘Melbourne’.

No problem Matt, if you can send me the php code you did till now for this part so it’s easier to adapt it.
Please send me the details to may email. My email is my_name at gmail.com . And my name is barbio .

1. You don’t need to do any casting as integer/float any more : 'orderby' => 'meta_value_num' now works to get the sort order you’d expect for int/float values instead of strings in meta fields. Tested on integers only for my site.

2. Ignoring sticky posts is easier and more readable with 'ignore_sticky_posts' => true available now.