Make WordPress Core


Ignore:
Timestamp:
12/16/2022 02:38:10 AM (4 years ago)
Author:
peterwilsoncc
Message:

Menus: Prevent infinite loop in menus.

This modifies how the menu-item-has-children class is removed from bottom level menu items. Instead of removing the class within wp_nav_menu() a filter is applied to the nav_menu_css_class hook to remove the class as required.

Introduces wp_nav_menu_remove_menu_item_has_children_class() for removing the class.

Reverts source code changes in [54478,54801], the tests are retained.

Props davidbinda, SergeyBiryukov, mhkuu, JeffPaul, jmdodd, priethor, desrosj, hellofromTonya, azaozz, peterwilsoncc.
Fixes #56926.
See #28620.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/wp-includes/nav-menu-template.php

    r54973 r54999  
    197197
    198198        $sorted_menu_items        = array();
    199         $menu_items_tree          = array();
    200199        $menu_items_with_children = array();
    201200        foreach ( (array) $menu_items as $menu_item ) {
     
    206205
    207206                $sorted_menu_items[ $menu_item->menu_order ] = $menu_item;
    208                 $menu_items_tree[ $menu_item->ID ]           = $menu_item->menu_item_parent;
    209207                if ( $menu_item->menu_item_parent ) {
    210                         $menu_items_with_children[ $menu_item->menu_item_parent ] = 1;
    211                 }
    212         }
    213 
    214         // Calculate the depth of each menu item with children.
    215         foreach ( $menu_items_with_children as $menu_item_key => &$menu_item_depth ) {
    216                 $menu_item_parent = $menu_items_tree[ $menu_item_key ];
    217                 while ( $menu_item_parent ) {
    218                         $menu_item_depth  = $menu_item_depth + 1;
    219                         $menu_item_parent = $menu_items_tree[ $menu_item_parent ];
     208                        $menu_items_with_children[ $menu_item->menu_item_parent ] = true;
    220209                }
    221210        }
     
    224213        if ( $menu_items_with_children ) {
    225214                foreach ( $sorted_menu_items as &$menu_item ) {
    226                         if (
    227                                 isset( $menu_items_with_children[ $menu_item->ID ] ) &&
    228                                 ( $args->depth <= 0 || $menu_items_with_children[ $menu_item->ID ] < $args->depth )
    229                         ) {
     215                        if ( isset( $menu_items_with_children[ $menu_item->ID ] ) ) {
    230216                                $menu_item->classes[] = 'menu-item-has-children';
    231217                        }
     
    233219        }
    234220
    235         unset( $menu_items_tree, $menu_items_with_children, $menu_items, $menu_item );
     221        unset( $menu_items, $menu_item );
    236222
    237223        /**
     
    649635        return $id;
    650636}
     637
     638/**
     639 * Remove the `menu-item-has-children` class from bottom level menu items.
     640 *
     641 * @since 6.1.2
     642 *
     643 * @param string[] $classes   Array of the CSS classes that are applied to the menu item's `<li>` element.
     644 * @param WP_Post  $menu_item The current menu item object.
     645 * @param stdClass $args      An object of wp_nav_menu() arguments.
     646 * @param int      $depth     Depth of menu item.
     647 * @return string[] Modified nav menu classes.
     648 */
     649function wp_nav_menu_remove_menu_item_has_children_class( $classes, $menu_item, $args, $depth ) {
     650        // Max-depth is 1-based.
     651        $max_depth = isset( $args->depth ) ? (int) $args->depth : 0;
     652        // Depth is 0-based so needs to be increased by one.
     653        $depth = $depth + 1;
     654
     655        // Complete menu tree is displayed.
     656        if ( 0 === $max_depth ) {
     657                return $classes;
     658        }
     659
     660        /*
     661         * Remove the `menu-item-has-children` class from bottom level menu items.
     662         * -1 is used to display all menu items in one level so the class should
     663         * be removed from all menu items.
     664         */
     665        if ( -1 === $max_depth || $depth >= $max_depth ) {
     666                $classes = array_diff( $classes, array( 'menu-item-has-children' ) );
     667        }
     668
     669        return $classes;
     670}
Note: See TracChangeset for help on using the changeset viewer.