WordPress.org

Make WordPress Core

Opened 6 months ago

Last modified 6 months ago

#49332 new defect (bug)

method Walker_Nav_Menu::start_el should not call filter the_title on non post menu items

Reported by: erwinbr Owned by:
Milestone: Awaiting Review Priority: normal
Severity: normal Version: 5.3.2
Component: Menus Keywords:
Focuses: Cc:

Description

I am working on a site with a.o:

  • WP 5.3.2
  • WPML 4.3.6
  • Estatik-pro 3.8.1
  • Divi 3.29.1

And am seeing the following notices in the debug log:

PHP Notice: Trying to get property 'post_type' of non-object in .\wp-content\plugins\estatik-pro_3.8.1\functions.php on line 386
PHP Stack trace:
PHP 1. {main}() .\index.php:0
PHP 2. require() .\index.php:17
PHP 3. require_once() .\wp-blog-header.php:19
PHP 4. include() .\wp-includes\template-loader.php:98
PHP 5. get_header() .\wp-content\themes\Divi\single.php:3
PHP 6. locate_template() .\wp-includes\general-template.php:41
PHP 7. load_template() .\wp-includes\template.php:671
PHP 8. require_once() .\wp-includes\template.php:722
PHP 9. wp_nav_menu() .\wp-content\themes\Divi\header.php:263
PHP 10. walk_nav_menu_tree() .\wp-includes\nav-menu-template.php:217
PHP 11. Walker_Nav_Menu->walk() .\wp-includes\nav-menu-template.php:583
PHP 12. Walker_Nav_Menu->display_element() .\wp-includes\class-wp-walker.php:244
PHP 13. Walker_Nav_Menu->display_element() .\wp-includes\class-wp-walker.php:156
PHP 14. Walker_Nav_Menu->start_el() .\wp-includes\class-wp-walker.php:144
PHP 15. apply_filters() .\wp-includes\class-walker-nav-menu.php:213
PHP 16. WP_Hook->apply_filters() .\wp-includes\plugin.php:206
PHP 17. es_the_title_filter() .\wp-includes\class-wp-hook.php:288
(If you want, I can post a stack trace with variable info.)

Diving into this problem I noticed that:

  • The main nav menu does not only contain items that are a post, but also the language switcher flags (added by WPML)
  • On line 213 of file wp-includes/class-walker-nav-menu.php, Walker_Nav_Menu->start_el() calls
    apply_filters( 'the_title', $item->title, $item->ID );
    
    for all items in the menu, be it posts or other items.
  • Estatik-pro hooks into this filter and calls get_post() on the given ID which is not a post ID:
    <?php
    function es_the_title_filter( $title, $id = null ) {
            global $es_settings;
            $post = get_post( $id );
            if ( is_single() && $post->post_type == Es_Property::get_post_type_name() ) {
                    ...
            }
    
            return $title;
    }
    add_filter( 'the_title', 'es_the_title_filter', 10, 2 );
    

Who is wrong?

  • WPML: by adding non-posts to menu's.
  • Estatik-pro for not checking that the filter is called for non-posts?
  • Walker_Nav_Menu->start_el() for unconditionally calling the filter 'the_title' on all menu-items?

IMO:

  • Menu-items can be other things than posts, and WPML shows that this is indeed possible.
  • The filter 'the_title' seems to be explicitly for altering a post title, not titles of images, non-post menu-items, or whatever. So Estatik-pro should not have to check that the given ID is indeed from a post.
  • Walker_Nav_Menu->start_el() calls its own filter 'nav_menu_item_title' directly after calling the 'the_title' filter (though still documenting $item as a WP_Post).

Based on the above, my conclusion is: Walker_Nav_Menu->start_el() should check if the item is a WP_Post before calling the 'the_title' filter.

If you agree, solving this should be easy, surround line 213 with

if ( $item instanceof WP_Post ) { ... }

However, in a lot of places it is documented that a menu-item is a WP_Post and changing that may take considerably more work.

Change History (1)

#1 @SergeyBiryukov
6 months ago

  • Component changed from General to Menus
Note: See TracTickets for help on using tickets.