I have the following code and while get_the_ID() works, $post->ID does not, why?

    $the_query = new WP_Query( array(
        'post_type' => 'custompost',
    ) );

    while ( $the_query->have_posts() ) : $the_query->the_post();
        echo $post->ID;

Your WP_Query loop is incomplete. Your not checking if any posts were actually found before looping, nor are you presenting a message to show none were found, nor are you cleaning up afterwards. You're also using the 'other' syntax that breaks brace matching in IDEs, making your life harder.

Try adding global $post; like this:

global $post;
$the_query = new WP_Query( array(
    'post_type' => 'custompost'
) );

    while ( $the_query->have_posts() ) {
        echo $post->ID;
}else {
    echo 'no posts found';

When writing queries it's important to be consistent and to get things right. So I recommend reading these slides by Andrew Nacin, a WordPress Core developer at Auttomatic:


This will tell you where each type of query is appropriate, how they should be used, and why.

In the code above, I added an if statement to check if any posts were returned, and I added wp_reset_postdata which would allow you to continue using the main query by cleaning up after the custom loop.

  • Thanks the global did the trick then, how does that work? And what does wp_reset_postdata() do exactly? Is it always needed? – urok93 Aug 23 '12 at 15:22
  • I guess $post was just out of scope, as for wp_reset_postdata(), when you start running through your loop, the $post variable is modified, so wp_reset_postdata() is like an undo on that, so you can use multiple loops within your main query without breaking it. – Tom J Nowell Aug 23 '12 at 15:35
  • You should look at these slides: slideshare.net/andrewnacin/… It's an incredibly useful set of slides on making queries by Nacin one of the core devs, it explains everything – Tom J Nowell Aug 23 '12 at 15:36
  • I agree with everything except the "other" syntax comment. Most of the time we're going to be outputting html inside of the while loop, so the "other" syntax is usually more appropriate. Link to the alternative syntax documentation incase anyone is interested - php.net/manual/en/control-structures.alternative-syntax.php – John_911 Mar 4 '17 at 6:16
  • If you disagree I suggest you write a blog post or ask a new question, but you'll need something better than it being 'more appropriate', claims need to be backed up – Tom J Nowell Mar 5 '17 at 23:02

The trick, as identified by Tom Nowell, is to add a reference to global $post.

When you run the_query->the_post(), WordPress loads the first result of the query into a global $post object. This is how it sets things up for all of the regular template tags:

  • the_title()
  • the_content()
  • the_excerpt()
  • etc ...

You see that we don't pass anything in to these functions. We just call them. Each of these functions will internally reference the global $post object in order to parse, prepare, and print the desired output.

Inside your loop, you call the_post() just fine to populate the data, but you don't have a reference to the data itself within the scope of your loop. If you wanted to avoid referencing the global $post object, you could instead use get_the_ID().

Like the other template tags I've referenced above, get_the_ID() summons data from the global $post object internally, so you don't have to do it yourself.

But if you do want to do this yourself, just add a global reference before you try to use $post:

$the_query = new WP_Query( array(
    'post_type' => 'custompost',
) );

while ( $the_query->have_posts() ) : $the_query->the_post();
    global $post;  // Add this line and you're golden
    echo $post->ID;

What is wp_reset_postdata()?

If you're building multiple loops, (i.e. you have a large post loop, but call some secondary loop inside of it), you can call wp_reset_postdata() to reset things.

Basically, the_post() will set the global $post object to have the data for the requested query. the_query->the_post() will overwrite $post with data from the_query. wp_reset_postdata() will reset $post to the original query.

So if you're using nested or multiple loops, wp_reset_postdata() is a way to get back to the loop and $post object you had available before you called your secondary the_query->the_post().

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.