Make WordPress Core

Ticket #28620: 28620-alt.3.diff

File 28620-alt.3.diff, 6.0 KB (added by petitphp, 4 years ago)

Add unit tests for the change

  • src/wp-includes/nav-menu-template.php

    diff --git src/wp-includes/nav-menu-template.php src/wp-includes/nav-menu-template.php
    index 592522878f..4b31148632 100644
    function wp_nav_menu( $args = array() ) {  
    196196        _wp_menu_item_classes_by_context( $menu_items );
    197197
    198198        $sorted_menu_items        = array();
     199        $menu_items_tree          = array();
    199200        $menu_items_with_children = array();
    200201        foreach ( (array) $menu_items as $menu_item ) {
    201202                $sorted_menu_items[ $menu_item->menu_order ] = $menu_item;
     203                $menu_items_tree[ $menu_item->ID ]           = $menu_item->menu_item_parent;
    202204                if ( $menu_item->menu_item_parent ) {
    203                         $menu_items_with_children[ $menu_item->menu_item_parent ] = true;
     205                        $menu_items_with_children[ $menu_item->menu_item_parent ] = 1;
     206                }
     207        }
     208
     209        // Calculate the depth of each menu item with children
     210        foreach ( $menu_items_with_children as $menu_item_key => &$menu_item_depth ) {
     211                $menu_item_parent = $menu_items_tree[ $menu_item_key ];
     212                while ( $menu_item_parent ) {
     213                        $menu_item_depth  = $menu_item_depth + 1;
     214                        $menu_item_parent = $menu_items_tree[ $menu_item_parent ];
    204215                }
    205216        }
    206217
    207218        // Add the menu-item-has-children class where applicable.
    208219        if ( $menu_items_with_children ) {
    209220                foreach ( $sorted_menu_items as &$menu_item ) {
    210                         if ( isset( $menu_items_with_children[ $menu_item->ID ] ) ) {
     221                        if ( isset( $menu_items_with_children[ $menu_item->ID ] ) && ( $args->depth <= 0 || $menu_items_with_children[ $menu_item->ID ] < $args->depth ) ) {
    211222                                $menu_item->classes[] = 'menu-item-has-children';
    212223                        }
    213224                }
    214225        }
    215226
    216         unset( $menu_items, $menu_item );
     227        unset( $menu_items_tree, $menu_items_with_children, $menu_items, $menu_item );
    217228
    218229        /**
    219230         * Filters the sorted list of menu item objects before generating the menu's HTML.
  • new file tests/phpunit/tests/menu/wp-nav-menu.php

    diff --git tests/phpunit/tests/menu/wp-nav-menu.php tests/phpunit/tests/menu/wp-nav-menu.php
    new file mode 100644
    index 0000000000..9b5bee99f8
    - +  
     1<?php
     2
     3class Test_Wp_Nav_Menu extends WP_UnitTestCase {
     4
     5        protected $menu_id        = 0;
     6        protected $lvl0_menu_item = 0;
     7        protected $lvl1_menu_item = 0;
     8        protected $lvl2_menu_item = 0;
     9
     10        public function set_up() {
     11                parent::set_up();
     12
     13                // Create nav menu.
     14                $this->menu_id = wp_create_nav_menu( 'test' );
     15
     16                // Create lvl0 menu item.
     17                $this->lvl0_menu_item = wp_update_nav_menu_item(
     18                        $this->menu_id,
     19                        0,
     20                        array(
     21                                'menu-item-title'  => 'Root menu item',
     22                                'menu-item-url'    => '#',
     23                                'menu-item-status' => 'publish',
     24                        )
     25                );
     26
     27                // Create lvl1 menu item.
     28                $this->lvl1_menu_item = wp_update_nav_menu_item(
     29                        $this->menu_id,
     30                        0,
     31                        array(
     32                                'menu-item-title'     => 'Lvl1 menu item',
     33                                'menu-item-url'       => '#',
     34                                'menu-item-parent-id' => $this->lvl0_menu_item,
     35                                'menu-item-status'    => 'publish',
     36                        )
     37                );
     38
     39                // Create lvl2 menu item.
     40                $this->lvl2_menu_item = wp_update_nav_menu_item(
     41                        $this->menu_id,
     42                        0,
     43                        array(
     44                                'menu-item-title'     => 'Lvl2 menu item',
     45                                'menu-item-url'       => '#',
     46                                'menu-item-parent-id' => $this->lvl1_menu_item,
     47                                'menu-item-status'    => 'publish',
     48                        )
     49                );
     50        }
     51
     52        public function tear_down() {
     53                wp_delete_nav_menu( $this->menu_id );
     54                parent::tear_down();
     55        }
     56
     57        /**
     58         * Test all menu items containing children have the CSS class `menu-item-has-children` when displaying the menu
     59         * without specifying a custom depth.
     60         *
     61         * @ticket 28620
     62         */
     63        public function test_wp_nav_menu_all_depth() {
     64
     65                // Render the menu with all its hierarchy.
     66                $menu_html = wp_nav_menu(
     67                        array(
     68                                'menu' => $this->menu_id,
     69                                'echo' => false,
     70                        )
     71                );
     72
     73                // Level 0 should be present in the HTML output and have the `menu-item-has-children` class.
     74                $this->assertStringContainsString(
     75                        sprintf(
     76                                '<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">',
     77                                $this->lvl0_menu_item
     78                        ),
     79                        $menu_html
     80                );
     81
     82                // Level 1 should be present in the HTML output and have the `menu-item-has-children` class.
     83                $this->assertStringContainsString(
     84                        sprintf(
     85                                '<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">',
     86                                $this->lvl1_menu_item
     87                        ),
     88                        $menu_html
     89                );
     90
     91                // Level 2 should be present in the HTML output and not have the `menu-item-has-children` class since it has no
     92                // children.
     93                $this->assertStringContainsString(
     94                        sprintf(
     95                                '<li id="menu-item-%1$d" class="menu-item menu-item-type-custom menu-item-object-custom menu-item-%1$d">',
     96                                $this->lvl2_menu_item
     97                        ),
     98                        $menu_html
     99                );
     100        }
     101
     102        /**
     103         * Test when displaying a menu with a custom depth, the last menu item doesn't have the CSS class
     104         * `menu-item-has-children` even if it's the case when displaying the full menu.
     105         *
     106         * @ticket 28620
     107         */
     108        public function test_wp_nav_menu_custom_depth() {
     109
     110                // Render the menu limited to 1 level of hierarchy (Lvl0 + Lvl1).
     111                $menu_html = wp_nav_menu(
     112                        array(
     113                                'menu'  => $this->menu_id,
     114                                'depth' => 2,
     115                                'echo'  => false,
     116                        )
     117                );
     118
     119                // Level 0 should be present in the HTML output and have the `menu-item-has-children` class.
     120                $this->assertStringContainsString(
     121                        sprintf(
     122                                '<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">',
     123                                $this->lvl0_menu_item
     124                        ),
     125                        $menu_html
     126                );
     127
     128                // Level 1 should be present in the HTML output and not have the `menu-item-has-children` class since its the
     129                // last item to be rendered.
     130                $this->assertStringContainsString(
     131                        sprintf(
     132                                '<li id="menu-item-%1$d" class="menu-item menu-item-type-custom menu-item-object-custom menu-item-%1$d">',
     133                                $this->lvl1_menu_item
     134                        ),
     135                        $menu_html
     136                );
     137
     138                // Level 2 should not be present in the HTML output.
     139                $this->assertStringNotContainsString(
     140                        sprintf(
     141                                '<li id="menu-item-%d"',
     142                                $this->lvl2_menu_item
     143                        ),
     144                        $menu_html
     145                );
     146        }
     147}
     148