The WP Query class can be used to make almost any imaginable query to the WP database. It’s amazing.
But it’s also used when WordPress is loaded, to run the main query for the current page request.
A common practice is to use wp_reset_query() and/or wp_reset_postdata()
But it’s unclear when to use one or the other, or if they must be used at all. And I don’t want to use them just in case but only when they are really needed.
So I would like to know what is the correct way to use the power of WP Query without breaking the main query.
Answers:
Thank you for visiting the Q&A section on Magenaut. Please note that all the answers may not help you solve the issue immediately. So please treat them as advisements. If you found the post helpful (or not), leave a comment & I’ll get back to you as soon as possible.
Method 1
it’s unclear when to use one or the other, or if they must be used at
all
-
If you’ve modified the global
$wp_queryvariable (e.g. usingquery_posts()which should NOT actually be used), then usewp_reset_query()to restore the variable back to the main query, i.e. so that the variable references or points to the main query again, and for example when you callhave_posts(), it would check against the main query (whether it contains any posts) and not some other/custom query.// This (should NOT be done and it) modifies the $wp_query global. query_posts( 'posts_per_page=2' ); while ( have_posts() ) { the_post(); the_title( '<h3>', '</h3>' ); } // This restores the $wp_query global back to the main query. wp_reset_query(); -
If you’ve modified the global
$postvariable (e.g. usingsetup_postdata()or by calling thethe_post()method in a secondary/customWP_Queryinstance), then usewp_reset_postdata()to restore the variable back to the current post in the main query, so that for example callingthe_title()would display the title of the second post in the main query and not the last post in a secondary query.// Case 1: Calling the the_post() method in a custom WP_Query instance. $query = new WP_Query( 'posts_per_page=2' ); while ( $query->have_posts() ) { // This modifies the $post global. $query->the_post(); the_title( '<h3>', '</h3>' ); } // Restore the $post global back to the current post in the main query. wp_reset_postdata(); // Case 2: Using setup_postdata(). global $post; $posts = get_posts( 'posts_per_page=2' ); foreach ( $posts as $post ) { // This modifies the $post global. setup_postdata( $post ); the_title( '<h3>', '</h3>' ); } // Restore the $post global back to the current post in the main query. wp_reset_postdata();So in the two examples above, we only called
wp_reset_postdata()and there’s no need to callwp_reset_query()because neither of the two queries modified the main query (or the global$wp_queryvariable).
Therefore, if the $wp_query global is not modified, then no need to call wp_reset_query(), and if the $post global is not modified, then no need to call wp_reset_postdata(). I.e. Call just one of them.
Additional Notes
-
query_posts()will change the main query and is not recommended. Only use if absolutely necessary. Creating a new instance ofWP_Queryorget_posts()is preferred for secondary loops. If you would like to modify the main query, use thepre_get_postsaction. -
In a
pre_get_postshook, you can use theis_main_query()method in the passed query object, to check whether the current query is the main query. Same goes with hooks likeposts_orderbywhich passes (if requested) the query object to the hook callbacks. -
The hooks in
WP_Queryalso fires on the admin side (wp-admin), so you can useis_admin()to avoid changing the main query on the admin, unless of course if that is something you intended to do.
And I’m not exactly sure the main points in your question (or the exact kind of answer that you’re looking for), but I hope this answer helps. 🙂
All methods was sourced from stackoverflow.com or stackexchange.com, is licensed under cc by-sa 2.5, cc by-sa 3.0 and cc by-sa 4.0