check if FILTER(“the_content”) is being executed in `the_post()`

I want to use

add_filter('the_content',...........)

however, I want that filter only to affect main post’s content. See phseudo-example:

<html>
.......
<meta decsription>.....the_content...</meta>
.......
<left_widget>....the_content...</left_widget> 
.......
<MAIN_POST>....the_content...</MAIN_POST>         <----------------- I want only this to be affected
......

How to achieve? (of course, out-of-question is the category pages, where post_contents are listed)

Solutions Collecting From Web of "check if FILTER(“the_content”) is being executed in `the_post()`"

Found solution here, to use in_the_loop() (but read comment below my answer too):

add_filter( 'the_content', 'custom_content' );

function custom_content( $content ) {
    if ( in_the_loop() ) {
        // ....
    }
    return $content;
}

This method doesn’t work. I leave this answer only as reference.

If I understand correctly, the easier way is to check if you are in the main query inside the filter’s callback:

add_filter( 'the_content', 'cyb_filter_content' );
function cyb_filter_content( $content ) {

    if( is_main_query() ) {

        // Work with $content here

    }

    return $content;

}

But this DOESN’T WORK. Why?

is_main_query() does this:

function is_main_query() {
    global $wp_query;
    return $wp_query->is_main_query();
}

So, it does not check if the query of the current loop is the main query, it checks if the global $wp_query object is the main query; and the global $wp_query object is always the main query unless it has been modified, which is something, let’s say, unusual and often not recommended. So, is_main_query() returns true almost everywhere and everytime.

Problem

Hooking into the_content does not guarantee that we’re in the loop.

Solution

Hook into pre_get_posts to exclude certain queries. Hook into the loop via the_post before hooking the_content.

Details

Add action to pre_get_posts to specifically see if the page is singular.

add_action( 'pre_get_posts', 'wpse_106269_pre_get_posts', 10, 1 );
function wpse_106269_pre_get_posts( $query ) {
  if( is_singular() ) {
    add_action( 'the_post', 'wpse_106269_the_post', 10, 2 );
  }
}

Add an action to the_post. This action hook is fired for each post when we’re in the loop. Once we’re in the_post, we know that we’re in the loop, so we can add a filter to the_content.

function wpse_106269_the_post( $post, $query ) {
  remove_action( 'the_post', 'wpse_106269_the_post', 10, 2 );    
  add_filter( 'the_content', 'wpse_106269_the_content', 10, 1 );
}

To make sure that the_content filter is only fired in the_post, remove it so that it doesn’t get fired in the future unless it’s added again by the_post action hook.

function wpse_106269_the_content( $content ) {
  remove_filter( 'the_content', 'wpse_106269_the_content', 10, 1 );
  //* Do something with $content
  return $content;
}

This is quite simple, see code below.

add_filter( 'the_content', 'my_the_content_filter' );
function my_the_content_filter( $content ){
    // If it is not page named debug, do nothing
    if( $GLOBALS['post']->post_name != 'debug' )
        return $content;

    // do actions...
    $content = 'my super cool new content';
    return $content;
}

This is probably an impossible task. the_content and its friend the_excerpt lack context and it is just impossible to guess the context from looking at the various global variables as they might have been altered.

Some themes provide actions to indicate that they are starting to output the post content but this is far from being standard.

The only way to work with it is to assume other plugin and theme developers are smart and don’t use the_content for anything which do not actually display the post content. (far fetched assumption)