A while back, a common question in the WordPress community was involving WP_Query, get_posts() and query_posts() and which one we should prefer for our queries. And while this excellent answer on StackOverflow settles that we should never use query_posts(), there seems to be some inconclusiveness about the benefits of WP_Query over get_posts() and vice versa. Those two seem to be equally valid and no performance benefit seems to be gained if you pick one over the other. So, which one should you prefer for a simple query of, let’s say, our latest 5 posts?
For some time I used to cast my vote on get_posts() because of its simplicity and the fact that it gave me an array of items which was easier to manipulate compared to the slightly bigger hassle of writing a new WP_Query. With get_posts() you do this:
$my_posts = get_posts([ 'posts_per_page' => 5 ]);
and $my_posts contain all the data that you need, ready to be manipulated with a simple
foreach loop. With WP_Query, on the other hand, you have a
while loop, which is slightly more difficult to remember. Plus, you also have to remember restoring the original postdata using
wp_reset_postdata(). It’s no big deal, but if they both do the job, why bother?
Well, the reason that you might want to use WP_Query instead of get_posts() is because it allows you to better organize your code. If the output of the loop’s entries contains a large amount of code and complex HTML structure, you might want to move it to a separate file which you will call with get_template_part(). This is something that you can’t do with get_posts(), because there is no easy way to transfer variables from one php file to another.
Update: Since WordPress 5.5, you can pass arguments to template files. This is a notable feature, but still, WP_Query is probably better if you want to break the contents of your query to multiple files.
So, if you want to use the same HTML markup for different loops, you should probably prefer WP_Query. In fact, I tend to prefer it even if this is not the case, because I can never know how I will have to extend my code in the future.