Get post content by ID

This post was originally published in November 2012, but was (accidentally) discarded during a migration. I used the wayback machine to retrieve the content and re-post it again.

As you may know the WordPress functions the_content() and get_the_content(), unlike their get_the_title() counterpart, cannot be used outside the loop. Naively ‘in the loop’ means just making sure the $post variable is global and points to the desired post.

So when someone asked why their code wasn’t working when they had used get_the_title() without passing it a post ID or declaring $post as global, the answer was simple.

What they said next threw me.

I find it extremely strange that the_content() works and that my $post variable is indeed an object full of data just like it should.

That is odd. But it turns out that get_the_content() doesn’t really use the $post global. Inspecting the source we see that it actually uses the $pages global. This stores the post’s content (pages as a post can carry across multiple pages). This is actually set up in: setup_postdata().

So while get_the_title() and co use the $post global, the_content() and get_the_content() rely on setup_postdata(). The upshot is that if using these outside the actual ‘Loop’ be sure to do both:

$posts = get_posts(array(...));
if( $posts ){
   foreach( $posts as $post ){
      global $post;
      setup_postdata();

      //Use the template tags

   }
}
wp_reset_postdata();

Note, while setup_postdata() doesn’t set up the $post global, wp_reset_postdata() does reset it.

Then, while reading this post by Tom McFarlin I thought it might sometimes be useful to be able to retrieve post content by passing the post ID, the same way you can with get_the title()

Get The Content by ID

/**
 * Display the post content. Optinally allows post ID to be passed
 * @uses the_content()
 *
 * @param int $id Optional. Post ID.
 * @param string $more_link_text Optional. Content for when there is more text.
 * @param bool $stripteaser Optional. Strip teaser content before the more text. Default is false.
 */
function sh_the_content_by_id( $post_id=0, $more_link_text = null, $stripteaser = false ){
    global $post;
    $post = &get_post($post_id);
    setup_postdata( $post, $more_link_text, $stripteaser );
    the_content();
    wp_reset_postdata( $post );
}

Example usage:

 sh_the_content_by_id(2283);

4 thoughts on “Get post content by ID

  1. When a developer starts working outside of the standard boundaries of The Loop, I feel like they’re at a point where they really should just be working in a more OOP manner. So rather than querying, setting the post to the loop, using all the loop functions, etc., just handle the WP_Post object directly.

    $post = get_post($id);
    echo apply_filters(‘the_content’, $post->post_content);

    This gives them all the standard post data, and they can do what they need with it. It avoids the overhead of messing with the globals, extra functions, etc..

    Just my thoughts. Obviously the important thing is that it works. :)

Leave a Reply

Your email address will not be published. Required fields are marked *