$post->ID not working

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;
    endwhile;

Related posts

Leave a Reply

2 comments

  1. 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'
    ) );
    
    if($the_query->have_posts()){
        while ( $the_query->have_posts() ) {
            $the_query->the_post();
            echo $post->ID;
        }
        wp_reset_postdata();
    }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:

    http://www.slideshare.net/andrewnacin/you-dont-know-query-wordcamp-netherlands-2012

    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.

  2. 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;
    endwhile;
    

    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().