0
votes

I apologise for this post being so long. The REASON for me asking such a stupid question as the topic suggests is BECAUSE there is just so many different things going wrong that I need to provide details of WHY I am asking this question.

Please bear with me...

I am busy creating a custom theme for my personal use have a LOT of slug-based pages and I use WP_query a lot(!) for many things from a custom news ticker to procedurally generating my navbar to mention but a few.

I was under the impression that creating a custom WP_Query means the content inside the results will not interfere with the operation of the main Loop and yet, I get very strange behaviour...

All my custom slug-based pages always work perfectly fine but when I use this in my navagation.php template part:

$query = new WP_Query($args);
if ($query->have_posts()) : while ($query->have_posts()) : $query->the_post();
//do my stuff here
endwhile; endif;

...this results in pages and posts loading just fine during the Loop but when I get to the product I am trying to view it always shows the same product no matter what link I follow. Eventually I added this to the product page:

if (have_posts()) {
    the_post();
    rewind_posts();
}

...and that made the products load up just fine. Yeay! No idea WHY I have to do it but it works. Strangely enough, though, in the template, just before it loads the template part that does the product layout, I print the name of the post currently in the global $post and then watch as it prints the wrong name above the right product after starting the Loop. (!?)

So then I find out about get_posts() and I like the fact that it gives me an array rather than an object that contains an array and so I swap over to using get_posts() in my navigation.php header template part and now my header section still works perfectly and my products display perfectly... but all posts and pages now show the same content. All posts and pages now show the same WooCommerce product. (!?) What's more confusing is that I do 3 WP_Query calls in navigation.php and the Loop in my posts and pages all show the first entry from the FIRST query, not the last...

After much struggling I decided it wasn't worth the aggravation so I swapped back to using WP_Query. Now things are all messed up in ways I can't even begin to understand... Now my posts and pages work just fine (so does my custom menu) but my products now all show the same product while in the loop. I tried doing this:

global $post;
$current = $post;
//do my query and loop over it
$post = $current;

Somehow that code turns the $post (which is just a pointer into the array) into an array itself (or something) because the product template now first displays the same product on every page I go to and then it displays the $post product it was supposed to directly below it. If I set $post to null directly after I set $current then setting $post back to $current afterwards results in only the wrong page showing up.

Somehow I managed to get it to stop showing the wrong product and now, instead, only my slug-based pages work because anything that uses the Loop (post, page and product) just tells me this:

Fatal error: Uncaught Error: Cannot use object of type WP_Query as array in D:\xampp\wordpress\htdocs\wp-includes\class-wp-query.php:3071 Stack trace: #0 D:\xampp\wordpress\htdocs\wp-includes\class-wp-query.php(3099): WP_Query->next_post() #1 D:\xampp\wordpress\htdocs\wp-includes\query.php(805): WP_Query->the_post()  

..and tracking the stack trace to where that occurs seems to indicate that (apparently) I am trying to use a WP_query as an array when I say this during the Loop:

if (have_posts()) : while (have_posts()) : the_post()

How is THAT code wrong? It's straight from the manual! :O According to the Codex, even though get_posts() also uses WP_Query it allows you to have multiple Loops and it says that you should use the restore_post_data() (I think) IF you updated the main Loop contents. But I am NOT trying to modify the main Loop at all. I want to do a query, have the results in a variable, run over that result and then discard the variable before going into the Loop and showing the page content as normal. I want my queries to run independently of the Loop and NOT in any way interfere with the operation of the Loop at all.

So:

  • why the heck does my custom WP_Query calls interfere with that I am seeing in the Loop and
  • why the heck do I get the error about trying to pass a WP_Query object as an array when calling the default, vanilla Loop
  • why do my products display correctly but my posts and pages do not
  • or why does my post and pages show correctly while my products show two different products

How the heck can my fully functional site get THIS broken just by going from $posts = get_posts($args) to $query = new WP_Query($args) ???? In a separate job completely outside the Loop, no less!

It makes absolutely no sense and since it makes no sense I have no idea where to start when trying to implement a fix. So what am I not seeing here? rewinding the posts, restoring the post data... nothing helps. I am completely dumbfounded.

Am I not using the Loop correctly? All I want to do is this:

  1. Load a page that does a custom WP_query and displays the content
  2. Load the template part that performs the Loop (i.e. single-product)
  3. Display the template part that page loads (i.e. content-single-product) and have it be the right content

It shouldn't be this hard, should it?

1
Are you resetting your custom query after the loop? wp_reset_query()zipkundan
No I'm not. The issue is that my queries run before and after the Loop (header and footer) and they all worked fine. The actual Loop was the problem. Inside my custom queries I did try using both $query->reset_postdata() and $query->rewind_posts(). I haven't tried calling wp_reset_query() after running my custom queries,no. I will pop that in there and see if that does anything. Thanks for the suggestion! EDIT: (From the docs) Calling wp_reset_query is not necessary after using WP_Query or get_posts as these don't modify the main query object. Instead use wp_reset_postdatauser10535901
Progress... Sort of... I changed this: if (have_posts()) : while (have_posts()) : the_post(); /*display the post*/ endwhile; endif; to this: if (have_posts()) : while (have_posts()) : /*display the post*/ the_post(); endwhile; endif; And now the page actually shows. Seems my fears were justified about the_post() skipping over the first entry. Okay, so now I see the post displayed but as soon as I call the_post() I am back to receiving the error about the_post using a WP_Query as an array. Sigh :(user10535901
I asked myself: "Why does the page.php page even DO a loop? It's not an archive, it's a single page I want to show." So I simply removed the call to the_post() inside the loop in page.php and single.php and now all my posts and pages work perfectly. All my archives still still throw an error when I call the_post() though... Calling wp_reset_postdata() doesn't seem to help with that at all :(user10535901
This is driving me insane! If I loop over $wp_query directly I can see all the posts are in there but if I call the_post() or $wp_query->the_post() both tell me that I "Cannot use object of type WP_Query as array". WHY!? Why is the_post() not working!?user10535901

1 Answers

0
votes

Such a simple little thing to cause such a massive amount of grief... :( Inside my navigation template part when I made the switch back from get_posts() to WP_Query I stored one query in $posts and the other in $query. Seems $posts is a reserved variable in WordPress because the moment I changed $posts to $query also everything worked 100% perfectly again!

I was aware of $post but not $posts. Now I know. Special thanks to @zipkundan for pointing me towards wp_reset_postdata(). That page taught me that custom queries DO in fact affect the global Loop (News to me!) and showed how to work around it.

So basically, the problem with my posts not showing what they were supposed to was due to me not calling wp_reset_postdata() after running through my custom loop and the reason for all the inexplicable weird page anomalies was due to me saving my custom query to a reserved variable name.

Mystery solved.