Check return value of get_posts

From previous questions, I know you would want optimize your queries. There is no need to change WP_Query into get_posts for perfomance. As I stated in a another post, yes, get_posts() is faster than WP_Query because get_posts() legally breaks pagination, but what get_posts() do can be done with WP_Query.

To really understand what get_posts() does, lets look at the source code. In essence, get_posts() does the following: (lets forget about the useless parameters in get_posts())

$args = [
    'no_found_rows'       => true,
    'ignore_sticky_posts' => 1
    // Any other user passed arguments
];
$r = new WP_Query( $args );
return $r->posts;

WHAT DOES IT ALL MEAN

  • get_posts() just returns the $posts property from the query object. $posts holds an array of posts

  • 'no_found_rows' => true is what legally breaks pagination, and is one of the reasons why you should not use get_posts for paginated queries. This is also why get_posts() is faster than a normal WP_Query as by default no_found_rows is set to false.

Because get_posts() only returns an array of posts, and not the query object, you must use a normal foreach loop to loop through the posts. Another thing to note, because the query object is not returned, the template tags like the_content() is not available because the $post global is not set to the current post. In a normal loop, the_post() sets up postdata which makes template tags available. For get_posts(), we need to do this manually by using setup_postdata( $post ) in our foreach loop

To properly loop through get_posts(), we need to do something like this

$posts_array = get_posts( $args );
if ( $posts_array ) { // Make sure we have posts before we attempt to loop through them
    foreach ( $posts_array as $post ) {
        setup_postdata( $post );

        // Now we can use template tags
        the_title();
        the_content();
    }
    wp_reset_postdata(); // VERY VERY IMPORTANT
}

I would not go through all of this to change existing WP_Query instances in order to optimize them. Simply add 'no_found_rows' => true to your WP_Query arguments, and viola, you are doing exatly what get_posts() is doing