Make WordPress Core

Changeset 54999


Ignore:
Timestamp:
12/16/2022 02:38:10 AM (2 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.

Location:
trunk/src/wp-includes
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/wp-includes/default-filters.php

    r54687 r54999  
    618618// Nav menu.
    619619add_filter( 'nav_menu_item_id', '_nav_menu_item_id_use_once', 10, 2 );
     620add_filter( 'nav_menu_css_class', 'wp_nav_menu_remove_menu_item_has_children_class', 10, 4 );
    620621
    621622// Widgets.
  • 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.