WordPress Template Tags: Understanding the_content() in PHP

WordPress Template Tags: Understanding the_content() in PHP

In WordPress themes, the_content() outputs the main content of a post or page. Call it inside the WordPress Loop, and it displays whatever was entered in the editor:

<?php
while (have_posts()) {
    the_post();
    the_content();
}
?>

This prints the post content with formatting intact—paragraphs, images, shortcodes, all processed and ready for display.

How the_content() Works

Behind the scenes, the_content() does three things:

  1. Retrieves the post content from the global $post object
  2. Applies the the_content filter, which runs formatting, shortcodes, and plugin hooks
  3. Echoes the result directly to the output

That third point is important: the_content() echoes. It doesn't return a value. If you need the content as a variable, use get_the_content() instead.

the_content() vs get_the_content()

WordPress follows a naming convention: functions starting with the_ echo output, functions starting with get_the_ return it.

the_content();          // Echoes the content
$content = get_the_content();  // Returns the content

But there's a catch. get_the_content() returns the raw content without filters. It doesn't process shortcodes, doesn't add paragraph tags, doesn't run plugin hooks. If you need the same output as the_content() but as a variable, you need to apply the filter manually:

$content = apply_filters('the_content', get_the_content());

Or use output buffering:

ob_start();
the_content();
$content = ob_get_clean();

The WordPress Loop

the_content() only works inside the WordPress Loop. The Loop is WordPress's mechanism for iterating over posts:

<?php
if (have_posts()) {
    while (have_posts()) {
        the_post();  // Sets up global post data
        
        the_title();    // Works because we're in the Loop
        the_content();  // Works because we're in the Loop
    }
}
?>

the_post() sets up the global $post variable. Template tags like the_content() rely on it. Call the_content() outside the Loop, and it outputs nothing (or the wrong post's content if $post is set from elsewhere).

Formatting and Filters

The the_content filter is where most of the magic happens. WordPress core applies several transformations:

  • wpautop: Converts line breaks to <p> and <br> tags
  • wptexturize: Converts straight quotes to curly quotes, dashes to em-dashes
  • do_shortcode: Processes shortcodes like [gallery] or [embed]
  • convert_smilies: Turns emoticons into emoji (if enabled)
  • shortcode_unautop: Prevents <p> tags around shortcodes

Plugins add their own filters. SEO plugins might inject schema markup. Social sharing plugins add buttons. Table of contents plugins scan for headings.

This is why get_the_content() without filters gives you raw content—none of these transformations run.

More Link Functionality

the_content() accepts one parameter: the "more" link text:

the_content('Continue reading...');

If you use the <!--more--> tag in the editor, WordPress splits the content. On archive pages, it shows content before the tag and adds a link with your custom text. On single post pages, it shows all content.

// In the post editor:
This is the intro paragraph.

<!--more-->

This is the rest of the post.
// In the theme:
the_content('Read more');

On the blog page, you see "This is the intro paragraph. [Read more]". On the single post page, you see both paragraphs.

Common Use Cases

Standard single post template:

<article>
    <h1><?php the_title(); ?></h1>
    <div class="content">
        <?php the_content(); ?>
    </div>
</article>

Archive page with excerpts:

<?php
while (have_posts()) {
    the_post();
    ?>
    <article>
        <h2><a href="<?php the_permalink(); ?>"><?php the_title(); ?></a></h2>
        <?php the_excerpt(); ?>
    </article>
    <?php
}
?>

Note: archive pages often use the_excerpt() instead of the_content() to show summaries.

Custom Queries

If you're using a custom WP_Query, you need to set up post data manually:

$args = array('post_type' => 'portfolio', 'posts_per_page' => 5);
$query = new WP_Query($args);

if ($query->have_posts()) {
    while ($query->have_posts()) {
        $query->the_post();  // Sets up post data
        the_content();        // Now this works
    }
    wp_reset_postdata();  // Restore original query
}

wp_reset_postdata() is important. It restores the global $post to whatever it was before your custom query. Skip it, and subsequent template tags might show the wrong content.

Gutenberg and Block Editor

With the block editor (Gutenberg), content is stored as HTML comments with block metadata:

<!-- wp:paragraph -->
<p>This is a paragraph.</p>
<!-- /wp:paragraph -->

the_content() still works. It outputs the blocks as they appear in the editor. The the_content filter processes these blocks through do_blocks(), which renders them properly.

If you're building a custom theme or plugin, the_content() handles blocks automatically. You don't need special logic for Gutenberg vs classic editor—WordPress abstracts that.

Performance Considerations

the_content() can be expensive. Shortcodes might query the database. Plugins might fetch external data. On archive pages with many posts, this adds up.

This is why archive pages often use the_excerpt() instead. Excerpts are lighter—either manually written or auto-generated from the first 55 words, with minimal filtering.

If you must use the_content() on archives, consider caching or lazy loading.

Customizing Output

You can filter the_content output in your theme or plugin:

add_filter('the_content', function($content) {
    // Add a custom message after content
    $content .= '<p>Thanks for reading!</p>';
    return $content;
});

This runs after all core filters but before output. Priority matters—use the third parameter to add_filter if you need to run before or after other hooks.

Security

Content from the editor is stored as post data and output by the_content(). WordPress sanitizes input when posts are saved, but the_content() doesn't escape output—it assumes the content is safe.

If you're displaying user-generated content outside the standard post editor, use wp_kses_post() to sanitize it first:

echo wp_kses_post($user_content);

But for content from the_content(), this isn't necessary. WordPress has already handled it.

Further Reading

The WordPress developer reference for the_content() documents parameters and usage in detail.

For understanding the Loop, see the WordPress Loop documentation.

The WordPress filter hooks guide explains how to customize content output with filters.

the_content() is central to WordPress theme development.

Wear the code

Product mockup

<?php the_content(); ?> Developer T-Shirt (PHP Edition — Dark Mode)

£25.00

View product
Product mockup

<?php the_content(); ?> Developer T-Shirt (PHP Edition — Light Mode)

£25.00

View product

0 comments

Leave a comment

Please note, comments need to be approved before they are published.