apply_filters( ‘the_content’, string $content )

Filters the post content.

Parameters

$contentstring
Content of the current post.

More Information

This filter is used to filter the content of a post after it is retrieved from the database and before it is printed to the screen.

Usage

When using this filter it’s important to check if you’re filtering the content in the main query with the conditionals is_main_query() and in_the_loop(). The main post query can be thought of as the primary post loop that displays the main content for a post, page or archive. Without these conditionals you could unintentionally be filtering the content for custom loops in sidebars, footers, or elsewhere.

add_filter( 'the_content', 'filter_the_content_in_the_main_loop', 1 );

function filter_the_content_in_the_main_loop( $content ) {

// Check if we're inside the main loop in a single Post.
if ( is_singular() && in_the_loop() && is_main_query() ) {
return $content . esc_html__( 'I’m filtering the content inside the main loop', 'wporg');
}

return $content;
}

Source

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

Changelog

VersionDescription
0.71Introduced.

User Contributed Notes

  1. Skip to note 12 content

    You can choose whether $content will have Shortcodes processed before or after your the_content function has executed by setting the Priority in add_filter. The default (10) will process Shortcodes after you have returned $content at the end of your Filter function. A large figure, such as 99, will already have processed Shortcodes before your Filter function is passed $content.

  2. Skip to note 14 content

    Consolidate multiple string replacement filters
    String replacements are a common reason for filtering the_content and with PHP7 you can now consolidate multiple callback functions using preg_replace_callback_array(); if it makes sense to.

    Example:

    add_filter( 'the_content', 'multiple_string_replacements');
    function multiple_string_replacements ( $content ) {
    	if ( is_single() && in_the_loop() && is_main_query() ) {
    		return preg_replace_callback_array([
    			// 1. Removes WordPress injected <p> tags surrounding images in post content.
    			'/<p>\s*(<a .*>)?\s*(<img .* \/>)\s*(<\/a>)?\s*<\/p>/iU' => function ( &$matches ) {
    				return $matches[1] . $matches[2] . $matches[3];
    			},
    			// 2. Adds custom data-attribute to <p> tags providing a paragraph id number.
    			'|<p>|' => function ( &$matches ) {
    				static $i = 1;
    				return sprintf( '<p data-p-id="%d">', $i++ );
    			},
    		], $content );
    	}
    	return $content;
    }
  3. Skip to note 15 content

    the info at the bottom of the hook is wrong for most of the hooks :

    Used by 7 functions | Uses 0 functions (At least it could be 0 function … ah ah ah !)

    HERE is what i have for WP 5.1 :
    * (7 is right, 0 is wrong)
    * and i am not counting apply_filters_ref_array (happily there is no for “the_content” )

    apply_filter
    the_content comment.php 2656
    the_content feed.php 191
    the_content formatting.php 3692
    the_content post-template.php 247
    the_content class-wp-rest-attachments-controller.php 310
    the_content class-wp-rest-posts-controller.php 1532
    the_content class-wp-rest-revisions-controller.php 545
    add_filter
    the_content blocks.php 269
    the_content blocks.php 296
    the_content class-wp-embed.php 32
    the_content class-wp-embed.php 39
    the_content default-filters.php 142
    the_content default-filters.php 172
    the_content default-filters.php 173
    the_content default-filters.php 174
    the_content default-filters.php 175
    the_content default-filters.php 176
    the_content default-filters.php 177
    the_content default-filters.php 178
    the_content default-filters.php 519

    There should be an indication of the WP version.

    my doc (WP 5.1) is available here (https://blog.mailpress.org/hooks/wordpress-5-1/) !

  4. Skip to note 16 content

    This is also a good hook to use if you want to display custom fields from a plugin (including ACF fields).

    The following example is from Jeff Starr’s plugins course.

    // display all custom fields for each post
    function wpdocs_display_all_custom_fields( $content ) {
        $custom_fields = 'Custom Fields';
        $all_custom_fields = get_post_custom();
    
        foreach ( $all_custom_fields as $key => $array ) {
            foreach ( $array as $value ) {
                if ( '_' !== substr( $key, 0, 1 ) ) {
                    $custom_fields .= ''. $key .' =&gt; '. $value .'';
                }
            }
        }
    
        return $content . $custom_fields;
    }
    add_filter( 'the_content', 'wpdocs_display_all_custom_fields' );
  5. Skip to note 17 content

    Using the example to add classes to p tag & h2 tag.

    <?php
    function wpdocs_replace_content( $text_content ) {
    	if ( is_page() ) {
    		$text = array(
    			'<p>' => '<p class="text-danger">',
    			'<h2>' => '<h2 class="h2">',
    		);
    
    		$text_content = str_ireplace( array_keys( $text ), $text, $text_content );
    	}
    
    	return $text_content;
    }
    add_filter( 'the_content', 'wpdocs_replace_content' );
    ?>
  6. Skip to note 18 content

    A useful hook to filter out vulgar words from your site and keep things nice and tidy for your site visitors.

    add_filter( 'the_content', 'wpdocs_filter_vulgar_words' );
    
    function wpdocs_filter_vulgar_words( $content ) {
    	$vulgar_words = array( $vulgar_word1, $vulgar_word2, $vulgar_word3, $vulgar_word4 );
    
    	foreach ( $vulgar_words as $word ) {
    		$hashed_word = substr( $word, 0, 1 ) . str_repeat( '*', strlen( $word ) - 1 );
    		$content = str_replace( $word, $hashed_word, $content );
    	}
    
    	return $content;
    }
  7. Skip to note 19 content

    The usage example is misleading. Unless you’re not interested in pages, it should be

    if ( ( is_single() || is_page() ) && in_the_loop() && is_main_query() ) {
    ...
    }

    You should also add a sufficiently high priority to the filter to hook on the_content before rendering happens:

    add_filter( 'the_content', 'filter_the_content_in_the_main_loop', -1 );
    
    function filter_the_content_in_the_main_loop( $content ) {
        // Check if we're inside the main loop in a post or page.
        if ( ( is_single() || is_page() ) && in_the_loop() && is_main_query() ) {
            return $content . esc_html__("I'm filtering the content inside the main loop", "my-textdomain");
        }
        return $content;
    }

    This should go in functions.php.
    It took me half a day to figure out why my filter was doing nothing.

  8. Skip to note 20 content

    Using the example below verifies that if the ALT attribute of any image inserted in the content is empty, get the file name.

    function wpdocs_replaceALT( $content ) {
    
    	if ( is_single() && in_the_loop() && is_main_query() ) {
    
    		libxml_use_internal_errors( true );
    
    		$post = new DOMDocument();
    		$post->loadHTML( $content );
    
    		$images = $post->getElementsByTagName( 'img' );
    
    		foreach ( $images as $image ) {
    
    			if ( empty( $image->getAttribute( 'alt' ) ) ) {
    
    				$src = $image->getAttribute( 'src' );
    				$alt = pathinfo( $src, PATHINFO_FILENAME );
    
    				$image->setAttribute( 'alt', $alt );
    
    			}
    		}
    
    		$content = $post->saveHTML();
    
    		return $content;
    	}
    }
    add_filter( 'the_content', 'wpdocs_replaceALT' );

You must log in before being able to contribute a note or feedback.