Why does the_title() filter is also applied in menu title?

I have created below function to hide page title. But when I execute this code, it also hides the menu name.

function wsits_post_page_title( $title ) {
              if( is_admin())

        return $title;

    $selected_type  =   get_option('wsits_page_show_hide');

    if(!is_array($selected_type)) return $title;

    if ( ( in_array(get_post_type(), $selected_type ) ) &&  get_option('wsits_page_show_hide') ) 
    {
        $title = '';
    }
    return $title;
}
add_filter( 'the_title', array($this, 'wsits_post_page_title') );

Related posts

Leave a Reply

6 comments

  1. Nikola is correct:

    Because menu items also have titles and they need to be filtered :).

    To make this only call in the posts, and not in menus, you can add a check for in_the_loop() – if it is true, you’re in a post.

    So change the first line in the function to:

    if( is_admin() || !in_the_loop() )

    and all should be well.

  2. It’s a bit of a hack but you can solve this by adding your action to loop_start.

    function make_custom_title( $title, $id ) {
        // Your Code Here
    }
    
    function set_custom_title() {
       add_filter( 'the_title', 'make_custom_title', 10, 2 );
    }
    
    add_action( 'loop_start', 'set_custom_title' );
    

    By embedding the_title filter inside of a loop_start action, we avoid overwriting the menu title attributes.

  3. You can do something like that :

    In your function.php :

    add_filter( 'the_title', 'ze_title');
    function ze_title($a) {
        global $dontTouch;
        if(!$dontTouch && !is_admin())
            $a = someChange($a);
        return $a;
    }
    

    In your template :

    $dontTouch = 1;
    wp_nav_menu( array('menu' => 'MyMenu') );
    $dontTouch = 0;
    
  4. Posting this answer because it was the search result I ended up clicking on while searching about targeting the filter hook the_title while ignoring the filter effect for navigation items.

    I was working on a section in a theme which I wanted to add buttons to the page title within the heading one tag.

    It looked similar to this:

    <?php echo '<h1>' . apply_filters( 'the_title', $post->post_title ) . '</h1>'.PHP_EOL; ?>
    

    I was then “hooking in” like this:

    add_filter( 'the_title', 'my_callback_function' );
    

    However, the above targets literally everything which calls the_title filter hook, and this includes navigation items.

    I changed the filter hook definition like this:

    <?php echo '<h1>' . apply_filters( 'the_title', $post->post_title, $post->ID, true ) . '</h1>'.PHP_EOL; ?>
    

    Pretty much every call to the_title filter passes parameter 1 as the $post->post_title and parameter 2 as the $post->ID. Search the WordPress core code for apply_filters( 'the_title'* and you’ll see for yourself.

    So I decided to add a third parameter for situations where I want to target specific items which call the_title filter. This way, I can still receive the benefit of all callbacks which apply to the_title filter hook by default, while also having the ability to semi-uniquely target items that use the_title filter hook with the third parameter.

    It’s a simple boolean parameter:

    /**
     * @param String $title
     * @param Int $object_id
     * @param bool $theme
     *
     * @return mixed
     */
    function filter_the_title( String $title = null, Int $object_id = null, Bool $theme = false ) {
    
        if( ! $object_id ){
            return $title;
        }
    
        if( ! $theme ){
            return $title;
        }
    
        // your code here...
    
        return $title;
    
    }
    
    add_filter( 'the_title', 'filter_the_title', 10, 3 );
    

    Label the variables however you want. This is what worked for me, and it does exactly what I need it to do. This answer may not be 100% relevant to the question asked, but this is where I arrived while searching to solve this problem. Hope this helps someone in a similar situation.

  5. The global $dontTouch; solution didn’t work for me for some reason. So I simply removed the filter around the menu thus in header.php:

    remove_filter( 'the_title', 'change_title' );
    get_template_part( 'template-parts/navigation/navigation', 'top' ); 
    add_filter( 'the_title', 'change_title' );
    

    And all is well.

  6. I think you’re looking for this:

    function change_title($title) {
        if( in_the_loop() && !is_archive() ) { // This will skip the menu items and the archive titles
            return $new_title;              
        }    
        return $title;    
    }
    add_filter('the_title', array($this, 'change_title'), 10, 2);