mirror of
git://develop.git.wordpress.org/
synced 2025-02-07 08:04:27 +01:00
Menus: Remove .menu-item-has-children
on wp_nav_menu
last level menu items when $depth
arg is used.
This changeset prevents `wp_nav_menu` last level menu items from having the `.menu-item-has-children` class when the `$depth` argument is used. It adds a loop in `wp_nav_menu()` to calculate the depth of each menu item with children to make sure the class is added only when applicable. Props slobodanmanic, kucrut, iCaspar, mdgl, petitphp, audrasjb, costdev. Fixes #28620. git-svn-id: https://develop.svn.wordpress.org/trunk@54478 602fd350-edb4-49c9-b593-d223f7449a82
This commit is contained in:
parent
d136e57d63
commit
2414439208
@ -196,24 +196,38 @@ function wp_nav_menu( $args = array() ) {
|
||||
_wp_menu_item_classes_by_context( $menu_items );
|
||||
|
||||
$sorted_menu_items = array();
|
||||
$menu_items_tree = array();
|
||||
$menu_items_with_children = array();
|
||||
foreach ( (array) $menu_items as $menu_item ) {
|
||||
$sorted_menu_items[ $menu_item->menu_order ] = $menu_item;
|
||||
$menu_items_tree[ $menu_item->ID ] = $menu_item->menu_item_parent;
|
||||
if ( $menu_item->menu_item_parent ) {
|
||||
$menu_items_with_children[ $menu_item->menu_item_parent ] = true;
|
||||
$menu_items_with_children[ $menu_item->menu_item_parent ] = 1;
|
||||
}
|
||||
|
||||
// Calculate the depth of each menu item with children
|
||||
foreach ( $menu_items_with_children as $menu_item_key => &$menu_item_depth ) {
|
||||
$menu_item_parent = $menu_items_tree[ $menu_item_key ];
|
||||
while ( $menu_item_parent ) {
|
||||
$menu_item_depth = $menu_item_depth + 1;
|
||||
$menu_item_parent = $menu_items_tree[ $menu_item_parent ];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Add the menu-item-has-children class where applicable.
|
||||
if ( $menu_items_with_children ) {
|
||||
foreach ( $sorted_menu_items as &$menu_item ) {
|
||||
if ( isset( $menu_items_with_children[ $menu_item->ID ] ) ) {
|
||||
if (
|
||||
isset( $menu_items_with_children[ $menu_item->ID ] ) &&
|
||||
( $args->depth <= 0 || $menu_items_with_children[ $menu_item->ID ] < $args->depth )
|
||||
) {
|
||||
$menu_item->classes[] = 'menu-item-has-children';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
unset( $menu_items, $menu_item );
|
||||
unset( $menu_items_tree, $menu_items_with_children, $menu_items, $menu_item );
|
||||
|
||||
/**
|
||||
* Filters the sorted list of menu item objects before generating the menu's HTML.
|
||||
|
173
tests/phpunit/tests/menu/wp-nav-menu.php
Normal file
173
tests/phpunit/tests/menu/wp-nav-menu.php
Normal file
@ -0,0 +1,173 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @group menu
|
||||
*
|
||||
* @covers ::wp_nav_menu
|
||||
*/
|
||||
class Tests_Menu_wpNavMenu extends WP_UnitTestCase {
|
||||
|
||||
static $menu_id = 0;
|
||||
static $lvl0_menu_item = 0;
|
||||
static $lvl1_menu_item = 0;
|
||||
static $lvl2_menu_item = 0;
|
||||
|
||||
public static function set_up_before_class() {
|
||||
parent::set_up_before_class();
|
||||
|
||||
// Create nav menu.
|
||||
self::$menu_id = wp_create_nav_menu( 'test' );
|
||||
|
||||
// Create lvl0 menu item.
|
||||
self::$lvl0_menu_item = wp_update_nav_menu_item(
|
||||
self::$menu_id,
|
||||
0,
|
||||
array(
|
||||
'menu-item-title' => 'Root menu item',
|
||||
'menu-item-url' => '#',
|
||||
'menu-item-status' => 'publish',
|
||||
)
|
||||
);
|
||||
|
||||
// Create lvl1 menu item.
|
||||
self::$lvl1_menu_item = wp_update_nav_menu_item(
|
||||
self::$menu_id,
|
||||
0,
|
||||
array(
|
||||
'menu-item-title' => 'Lvl1 menu item',
|
||||
'menu-item-url' => '#',
|
||||
'menu-item-parent-id' => self::$lvl0_menu_item,
|
||||
'menu-item-status' => 'publish',
|
||||
)
|
||||
);
|
||||
|
||||
// Create lvl2 menu item.
|
||||
self::$lvl2_menu_item = wp_update_nav_menu_item(
|
||||
self::$menu_id,
|
||||
0,
|
||||
array(
|
||||
'menu-item-title' => 'Lvl2 menu item',
|
||||
'menu-item-url' => '#',
|
||||
'menu-item-parent-id' => self::$lvl1_menu_item,
|
||||
'menu-item-status' => 'publish',
|
||||
)
|
||||
);
|
||||
|
||||
/**
|
||||
* This filter is used to prevent reusing a menu item ID more that once. It cause the tests to failed
|
||||
* after the first one since the IDs are missing from the HTML generated by `wp_nav_menu`.
|
||||
*
|
||||
* To allow the tests to pass, we remove the filter before running them and add it back after
|
||||
* they ran ({@see Tests_Menu_wpNavMenu::tear_down_after_class()}).
|
||||
*/
|
||||
remove_filter( 'nav_menu_item_id', '_nav_menu_item_id_use_once' );
|
||||
}
|
||||
|
||||
public static function tear_down_after_class() {
|
||||
wp_delete_nav_menu( self::$menu_id );
|
||||
|
||||
/**
|
||||
* This filter was removed to let the tests pass and need to be added back ({@see Tests_Menu_wpNavMenu::set_up_before_class}).
|
||||
*/
|
||||
add_filter( 'nav_menu_item_id', '_nav_menu_item_id_use_once', 10, 2 );
|
||||
|
||||
parent::tear_down_after_class();
|
||||
}
|
||||
|
||||
/**
|
||||
* Test all menu items containing children have the CSS class `menu-item-has-children` when displaying the menu
|
||||
* without specifying a custom depth.
|
||||
*
|
||||
* @ticket 28620
|
||||
*/
|
||||
public function test_wp_nav_menu_should_have_has_children_class_without_custom_depth() {
|
||||
|
||||
// Render the menu with all its hierarchy.
|
||||
$menu_html = wp_nav_menu(
|
||||
array(
|
||||
'menu' => self::$menu_id,
|
||||
'echo' => false,
|
||||
)
|
||||
);
|
||||
|
||||
// Level 0 should be present in the HTML output and have the `menu-item-has-children` class.
|
||||
$this->assertStringContainsString(
|
||||
sprintf(
|
||||
'<li id="menu-item-%1$d" class="menu-item menu-item-type-custom menu-item-object-custom menu-item-has-children menu-item-%1$d">',
|
||||
self::$lvl0_menu_item
|
||||
),
|
||||
$menu_html,
|
||||
'Level 0 should be present in the HTML output and have the menu-item-has-children class'
|
||||
);
|
||||
|
||||
// Level 1 should be present in the HTML output and have the `menu-item-has-children` class.
|
||||
$this->assertStringContainsString(
|
||||
sprintf(
|
||||
'<li id="menu-item-%1$d" class="menu-item menu-item-type-custom menu-item-object-custom menu-item-has-children menu-item-%1$d">',
|
||||
self::$lvl1_menu_item
|
||||
),
|
||||
$menu_html,
|
||||
'Level 1 should be present in the HTML output and have the menu-item-has-children class'
|
||||
);
|
||||
|
||||
// Level 2 should be present in the HTML output and not have the `menu-item-has-children` class since it has no
|
||||
// children.
|
||||
$this->assertStringContainsString(
|
||||
sprintf(
|
||||
'<li id="menu-item-%1$d" class="menu-item menu-item-type-custom menu-item-object-custom menu-item-%1$d">',
|
||||
self::$lvl2_menu_item
|
||||
),
|
||||
$menu_html,
|
||||
'Level 2 should be present in the HTML output and not have the `menu-item-has-children` class since it has no children'
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that when displaying a menu with a custom depth, the last menu item doesn't have the CSS class
|
||||
* `menu-item-has-children` even if it's the case when displaying the full menu.
|
||||
*
|
||||
* @ticket 28620
|
||||
*/
|
||||
public function test_wp_nav_menu_should_not_have_has_children_class_with_custom_depth() {
|
||||
|
||||
// Render the menu limited to 1 level of hierarchy (Lvl0 + Lvl1).
|
||||
$menu_html = wp_nav_menu(
|
||||
array(
|
||||
'menu' => self::$menu_id,
|
||||
'depth' => 2,
|
||||
'echo' => false,
|
||||
)
|
||||
);
|
||||
|
||||
// Level 0 should be present in the HTML output and have the `menu-item-has-children` class.
|
||||
$this->assertStringContainsString(
|
||||
sprintf(
|
||||
'<li id="menu-item-%1$d" class="menu-item menu-item-type-custom menu-item-object-custom menu-item-has-children menu-item-%1$d">',
|
||||
self::$lvl0_menu_item
|
||||
),
|
||||
$menu_html,
|
||||
'Level 0 should be present in the HTML output and have the menu-item-has-children class'
|
||||
);
|
||||
|
||||
// Level 1 should be present in the HTML output and not have the `menu-item-has-children` class since its the
|
||||
// last item to be rendered.
|
||||
$this->assertStringContainsString(
|
||||
sprintf(
|
||||
'<li id="menu-item-%1$d" class="menu-item menu-item-type-custom menu-item-object-custom menu-item-%1$d">',
|
||||
self::$lvl1_menu_item
|
||||
),
|
||||
$menu_html,
|
||||
'Level 1 should be present in the HTML output and not have the `menu-item-has-children` class since its the last item to be rendered'
|
||||
);
|
||||
|
||||
// Level 2 should not be present in the HTML output.
|
||||
$this->assertStringNotContainsString(
|
||||
sprintf(
|
||||
'<li id="menu-item-%d"',
|
||||
self::$lvl2_menu_item
|
||||
),
|
||||
$menu_html,
|
||||
'Level 2 should not be present in the HTML output'
|
||||
);
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user