The WP loop goes like this:
if ( have_posts() ) {
while ( have_posts() ) {
the_post();
...
Why is it preferred over the following?
foreach( (new WP_Query())->get_posts() as $post ) { ... }
To me, it’s more apparent what is going on in the latter. I’m new to PHP and WP and I’m trying to understand why I should be using the former.
What do I gain by using the standard loop
? Is iterating over get_posts()
any less efficient?
2 Answers
Several reasons
1. Filters and Actions
By using the standard loop, you execute various filters and actions that plugins rely on.
Additionally, you set up the_post
correctly, allowing functions such as the_content
etc to work correctly. Some filters can even insert “posts” into the loop
2. Memory Efficiency
By fetching all the posts as an array, you’re forcing WP_Query
to take the data it has and create WP_Post
objects. With a standard post loop these are created as they’re needed
3. PHP Warnings
Your loop doesn’t check if any posts were actually found, so it’s impossible to give a “No posts available” style message. It’ll also generate PHP warnings at times.
4. Overriding WP globals
By using $post
you’re overriding a global variable, which can have unintended consequences, especially if this loop is nested inside another loop you’re unaware of
5. PHP Efficiency and Correctness
Creating an object inside a foreach
condition is bad practice, as is creating and then using an object without error checking.
6. Debugging
A lot of tools and plugins assume you’re using a standard loop and have been built to make life easier. By doing this you’re throwing all of that away
7. There are Better Alternatives
array_walk
A crude but superior option to your foreach might actually be array_walk
:
$q = new WP_Query([ ..args ]);
array_walk( $q->get_posts(), function( $post ) {
//
});
Note that I don’t recommend using array_walk
.
PHP Generators
Now that’s not to say you couldn’t use a different style loop while still having all the advantages.
For example WP Scholar has an article showing a php generator based loop:
if ( have_posts() ) {
foreach ( wp_loop() as $post ) {
echo '<h1>' . esc_html( get_the_title() ) . '</h1>';
}
} else {
echo '<h1>No posts found!</h1>';
}
This has the advantage that it still calls all the functions of a standard loop, but they’ve been abstracted away.
I’m sure there are others, but a standard loop is reliable predictable and readable to all