Get Post Content By ID

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

Comments (2)

Comments are closed.
  1. Just use get_post_field( ‘post_content’, $post_id )

    • Hi Kristian,

      Thanks, I had forgotten about that one! However, that will just return the entire content $post->post_content. Unfortunately (as far as I’m aware) it doesn’t pass it through the_content filter or split the content into pages.

      My understanding was that get_post_field() was more intended for admin-side: editing/saving posts – but its still a handy function nonetheless.

      Thanks for commenting!