WP Gotcha #2: WP_Query and get_posts() have different defaults

There are the following ways of getting a collection of posts in WordPress:

  1. Using WP_Query.
  2. Using get_posts().
  3. Using query_posts() (but you should probably completely ignore this approach as it alters the main WP loop – the one in charge of displaying whatever the “current page” is supposed to be based on the URL).

What is the difference between WP_Query and get_posts()?

get_posts() actually uses a WP_Query object under the hood. The unexpected thing it does, though, is set up the WP_Query object with a bunch of defaults that alter WP_Query‘s default behavior instead of using WP_Query‘s defaults.

Some notable arguments that get changed by default are described below.

suppress_filters is enabled in get_posts()

If you use a plugin filtering the posts returned by WP using one of the filters below, the filtering is not going to work if you use get_posts(). That is, unless you manually set 'suppress_filters' => false.

  • posts_search
  • posts_search_orderby
  • posts_where
  • comment_feed_join
  • posts_where_paged
  • posts_where_request
  • posts_request
  • posts_results
  • the_posts

This is really important to take into account especially if you plan to restrict access to some posts for some users.

ignore_sticky_posts is enabled in get_posts()

Sticky posts will not be included in the returned list of posts.

no_found_rows is disabled in get_posts()

This is actually a pretty cool optimization. The only problem with this is that you don’t always want this to happen.

By default WordPress adds SQL_CALC_FOUND_ROWS to your SELECT SQL query. When WP asks the database for a list of posts, by default it will not only return the matching posts but it will also include information on how many matching posts in total there are in the database. This is crucial for pagination – knowing how many posts there are allows us to calculate how many post pages there are.

But what if we only want to display the 5 latest posts matching some criteria with no pagination? We don’t need the information on how many matching posts there are in total. This is when we can remove SQL_CALC_FOUND_ROWS from the query, improving our site’s performance.

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.