WordPress.org

Make WordPress Core

Ticket #12718: 12718.4.diff

File 12718.4.diff, 80.0 KB (added by scribu, 2 years ago)
  • wp-admin/admin.php

    diff --git wp-admin/admin.php wp-admin/admin.php
    index 6db6e32..5a3384f 100644
    if ( isset( $_REQUEST['taxonomy'] ) && taxonomy_exists( $_REQUEST['taxonomy'] ) 
    9898else 
    9999        $taxnow = ''; 
    100100 
     101require(ABSPATH . 'wp-admin/includes/class-wp-admin-menu.php'); 
     102 
    101103if ( WP_NETWORK_ADMIN ) 
    102104        require(ABSPATH . 'wp-admin/network/menu.php'); 
    103105elseif ( WP_USER_ADMIN ) 
  • new file wp-admin/includes/class-wp-admin-menu.php

    diff --git wp-admin/includes/class-wp-admin-menu.php wp-admin/includes/class-wp-admin-menu.php
    new file mode 100644
    index 0000000..4c1b11e
    - +  
     1<?php 
     2 
     3/** 
     4 * A single menu item, with children 
     5 */ 
     6class WP_Admin_Menu_Item { 
     7 
     8        protected $children; 
     9 
     10        function __construct( $payload ) { 
     11 
     12                if ( !isset( $payload['id'] ) ) 
     13                        $payload['id'] = $payload['slug']; 
     14 
     15                if ( isset( $payload['cap'] ) ) 
     16                        $payload['cap'] = $this->convert_caps( $payload['cap'] ); 
     17 
     18                foreach ( $payload as $key => $value ) 
     19                        $this->$key = $value; 
     20 
     21                $this->children = array(); 
     22        } 
     23 
     24        protected function prepare_item( $payload ) { 
     25                if ( is_a( $payload, __CLASS__ ) ) 
     26                        return $payload; 
     27 
     28                return new WP_Admin_Menu_Item( $payload ); 
     29        } 
     30 
     31        // Return the first cap that the user has or last cap 
     32        protected function convert_caps( $caps ) { 
     33                foreach ( (array) $caps as $cap ) { 
     34                        if ( current_user_can( $cap ) ) 
     35                                break; 
     36                } 
     37 
     38                return $cap; 
     39        } 
     40 
     41        function append( $payload ) { 
     42                $item = $this->prepare_item( $payload ); 
     43 
     44                if ( isset( $this->children[ $item->id ] ) ) 
     45                        return false; 
     46 
     47                $this->children[ $item->id ] = $item; 
     48 
     49                return true; 
     50        } 
     51 
     52        function insert_before( $ref_id, $payload ) { 
     53                if ( !isset( $this->children[ $ref_id ] ) ) 
     54                        return false; 
     55 
     56                $new_array = array(); 
     57 
     58                $item = $this->prepare_item( $payload ); 
     59 
     60                foreach ( $this->children as $key => $value ) { 
     61                        if ( $key == $ref_id ) { 
     62                                $new_array[ $item->id ] = $item; 
     63                        } 
     64 
     65                        $new_array[ $key ] = $value; 
     66                } 
     67 
     68                $this->children = $new_array; 
     69 
     70                return true; 
     71        } 
     72 
     73        function insert_after( $ref_id, $payload ) { 
     74                if ( !isset( $this->children[ $ref_id ] ) ) 
     75                        return false; 
     76 
     77                $new_array = array(); 
     78 
     79                $item = $this->prepare_item( $payload ); 
     80 
     81                foreach ( $this->children as $key => $value ) { 
     82                        $new_array[ $key ] = $value; 
     83 
     84                        if ( $key == $ref_id ) { 
     85                                $new_array[ $item->id ] = $item; 
     86                        } 
     87                } 
     88 
     89                $this->children = $new_array; 
     90 
     91                return true; 
     92        } 
     93 
     94        function replace( $ref_id, $payload ) { 
     95                if ( !$this->insert_after( $ref_id, $payload ) ) 
     96                        return false; 
     97 
     98                $this->remove( $ref_id ); 
     99        } 
     100 
     101        function contains( $id ) { 
     102                return isset( $this->children[ $id ] ); 
     103        } 
     104 
     105        function get( $id, $field = 'id' ) { 
     106                if ( 'id' != $field ) { 
     107                        $items = $this->get_children( array( $field => $id ) ); 
     108                        if ( empty( $items ) ) 
     109                                return false; 
     110 
     111                        return reset( $items ); 
     112                } 
     113 
     114                if ( !isset( $this->children[ $id ] ) ) 
     115                        return false; 
     116 
     117                return $this->children[ $id ]; 
     118        } 
     119 
     120        function has_children() { 
     121                return !empty( $this->children ); 
     122        } 
     123 
     124        function get_children( $args = array() ) { 
     125                return wp_list_filter( $this->children, $args ); 
     126        } 
     127 
     128        function remove( $id ) { 
     129                if ( !isset( $this->children[ $id ] ) ) 
     130                        return false; 
     131 
     132                unset( $this->children[ $id ] ); 
     133 
     134                return true; 
     135        } 
     136} 
     137 
     138 
     139/** 
     140 * The root menu item, with some convenience methods 
     141 */ 
     142class WP_Admin_Menu extends WP_Admin_Menu_Item { 
     143 
     144        function __construct() { 
     145                $this->children = array(); 
     146        } 
     147 
     148        function append( $payload ) { 
     149                $payload = wp_parse_args( $payload, array( 
     150                        'icon' => 'div' 
     151                ) ); 
     152 
     153                if ( !isset( $payload['class'] ) ) { 
     154                        $payload['class'] = 'menu-icon-' . $payload['id']; 
     155                } 
     156 
     157                parent::append( $payload ); 
     158        } 
     159 
     160        // Convenience method 
     161        function add_submenu( $parent_id, $payload ) { 
     162                $parent = $this->get( $parent_id ); 
     163 
     164                if ( ! $parent ) 
     165                        return false; 
     166 
     167                return $parent->append( $payload ); 
     168        } 
     169 
     170        // Super-convenience method 
     171        function add_first_submenu( $parent_id, $title ) { 
     172                $parent = $this->get( $parent_id ); 
     173 
     174                if ( ! $parent ) 
     175                        return false; 
     176 
     177                return $parent->append( array( 
     178                        'title' => $title, 
     179                        'cap' => $parent->cap, 
     180                        'slug' => $parent->slug, 
     181                ) ); 
     182        } 
     183 
     184        /** @private */ 
     185        function _add_post_type_menus() { 
     186                $cpt_list = get_post_types( array( 
     187                        'show_ui' => true, 
     188                        '_builtin' => false, 
     189                        'show_in_menu' => true 
     190                ) ); 
     191 
     192                foreach ( $cpt_list as $ptype ) { 
     193                        $ptype_obj = get_post_type_object( $ptype ); 
     194 
     195                        if ( true !== $ptype_obj->show_in_menu ) 
     196                                continue; // handled in _add_post_type_submenus() 
     197 
     198                        $ptype_for_id = sanitize_html_class( $ptype ); 
     199 
     200                        if ( is_string( $ptype_obj->menu_icon ) ) { 
     201                                $admin_menu_icon = esc_url( $ptype_obj->menu_icon ); 
     202                                $ptype_class = $ptype_for_id; 
     203                        } else { 
     204                                $admin_menu_icon = 'div'; 
     205                                $ptype_class = 'post'; 
     206                        } 
     207 
     208                        $args = array( 
     209                                'title' => esc_attr( $ptype_obj->labels->menu_name ), 
     210                                'cap' => $ptype_obj->cap->edit_posts, 
     211                                'class' => 'menu-icon-' . $ptype_class, 
     212                                'id' => 'posts-' . $ptype_for_id, 
     213                                'slug' => "edit.php?post_type=$ptype", 
     214                                'icon' => $admin_menu_icon, 
     215                        ); 
     216 
     217                        if ( $ptype_obj->menu_position ) { 
     218                                $before = $ptype_obj->menu_position; 
     219                        } else { 
     220                                $before = 'separator2'; 
     221                        } 
     222 
     223                        $this->insert_before( $before, $args ); 
     224 
     225                        $this->add_first_submenu( 'posts-' . $ptype_for_id, $ptype_obj->labels->all_items ); 
     226 
     227                        $this->add_submenu( 'posts-' . $ptype_for_id, array( 
     228                                'title' => $ptype_obj->labels->add_new, 
     229                                'cap' => $ptype_obj->cap->edit_posts, 
     230                                'slug' => "post-new.php?post_type=$ptype", 
     231                        ) ); 
     232 
     233                        $this->_add_tax_submenus( 'posts-' . $ptype_for_id, $ptype ); 
     234                } 
     235        } 
     236 
     237        /** @private */ 
     238        function _add_post_type_submenus() { 
     239                foreach ( get_post_types( array( 'show_ui' => true ) ) as $ptype ) { 
     240                        $ptype_obj = get_post_type_object( $ptype ); 
     241 
     242                        // Submenus only. 
     243                        if ( ! $ptype_obj->show_in_menu || $ptype_obj->show_in_menu === true ) 
     244                                continue; 
     245 
     246                        add_submenu_page( $ptype_obj->show_in_menu, $ptype_obj->labels->name, $ptype_obj->labels->all_items, $ptype_obj->cap->edit_posts, "edit.php?post_type=$ptype" ); 
     247                } 
     248        } 
     249 
     250        /** @private */ 
     251        function _add_tax_submenus( $parent_id, $ptype ) { 
     252                foreach ( get_taxonomies( array(), 'objects' ) as $tax ) { 
     253                        if ( ! $tax->show_ui || ! in_array($ptype, (array) $tax->object_type, true) ) 
     254                                continue; 
     255 
     256                        $slug = 'edit-tags.php?taxonomy=' . $tax->name; 
     257 
     258                        if ( 'post' != $ptype ) 
     259                                $slug .= '&amp;post_type=' . $ptype; 
     260 
     261                        $this->add_submenu( $parent_id, array( 
     262                                'title' => esc_attr( $tax->labels->menu_name ), 
     263                                'cap' => $tax->cap->manage_terms, 
     264                                'slug' => $slug, 
     265                        ) ); 
     266                } 
     267        } 
     268 
     269        /** @private */ 
     270        function _loop( $callback ) { 
     271                foreach ( $this->get_children() as $item ) { 
     272                        if ( !isset( $item->slug ) ) 
     273                                continue; 
     274 
     275                        call_user_func( $callback, $item, $this ); 
     276                } 
     277        } 
     278} 
     279 
     280 
     281// TODO: use in admin bar? 
     282/** @private */ 
     283function _admin_menu_comment_count( $awaiting_mod ) { 
     284        $count = sprintf( 
     285                "<span class='awaiting-mod count-%s'><span class='pending-count'>%s</span></span>", 
     286                $awaiting_mod, 
     287                number_format_i18n( $awaiting_mod ) 
     288        ); 
     289 
     290        return sprintf( __('Comments %s'), $count ); 
     291} 
     292 
     293/** @private */ 
     294function _admin_menu_update_count( $update_data ) { 
     295        $count = sprintf( 
     296                "<span class='update-plugins count-%s' title='%s'><span class='update-count'>%s</span></span>", 
     297                $update_data['counts']['total'], 
     298                $update_data['title'], 
     299                number_format_i18n( $update_data['counts']['total'] ) 
     300        ); 
     301 
     302        return sprintf( __( 'Updates %s' ), $count ); 
     303} 
     304 
     305/** @private */ 
     306function _admin_menu_plugin_update_count( $update_data ) { 
     307        $count = sprintf( 
     308                "<span class='update-plugins count-%s'><span class='plugin-count'>%s</span></span>", 
     309                $update_data['counts']['plugins'], 
     310                number_format_i18n( $update_data['counts']['plugins'] ) 
     311        ); 
     312 
     313        return sprintf( __( 'Plugins %s' ), $count ); 
     314} 
     315 
     316/** @private */ 
     317function _admin_menu_theme_update_count( $update_data ) { 
     318        $count = sprintf( 
     319                "<span class='update-plugins count-%s'><span class='theme-count'>%s</span></span>", 
     320                $update_data['counts']['themes'], 
     321                number_format_i18n( $update_data['counts']['themes'] ) 
     322        ); 
     323 
     324        return sprintf( __( 'Themes %s' ), $count ); 
     325} 
     326 
  • wp-admin/includes/menu.php

    diff --git wp-admin/includes/menu.php wp-admin/includes/menu.php
    index 14cadfa..5d61b64 100644
    elseif ( is_user_admin() ) 
    1414else 
    1515        do_action('_admin_menu'); 
    1616 
     17$_wp_submenu_nopriv = array(); 
     18$_wp_menu_nopriv = array(); 
     19 
     20$admin_menu->_loop( '_generate_admin_page_hooks' ); 
     21$admin_menu->_loop( '_check_admin_submenu_privs' ); 
     22 
    1723// Create list of page plugin hook names. 
    18 foreach ($menu as $menu_page) { 
    19         if ( false !== $pos = strpos($menu_page[2], '?') ) { 
     24function _generate_admin_page_hooks( $menu_item, $admin_menu ) { 
     25        global $admin_page_hooks; 
     26 
     27        if ( false !== $pos = strpos($menu_item->slug, '?') ) { 
    2028                // Handle post_type=post|page|foo pages. 
    21                 $hook_name = substr($menu_page[2], 0, $pos); 
    22                 $hook_args = substr($menu_page[2], $pos + 1); 
     29                $hook_name = substr($menu_item->slug, 0, $pos); 
     30                $hook_args = substr($menu_item->slug, $pos + 1); 
    2331                wp_parse_str($hook_args, $hook_args); 
    2432                // Set the hook name to be the post type. 
    2533                if ( isset($hook_args['post_type']) ) 
    foreach ($menu as $menu_page) { 
    2836                        $hook_name = basename($hook_name, '.php'); 
    2937                unset($hook_args); 
    3038        } else { 
    31                 $hook_name = basename($menu_page[2], '.php'); 
     39                $hook_name = basename($menu_item->slug, '.php'); 
    3240        } 
    3341        $hook_name = sanitize_title($hook_name); 
    3442 
    foreach ($menu as $menu_page) { 
    3745        elseif ( !$hook_name ) 
    3846                continue; 
    3947 
    40         $admin_page_hooks[$menu_page[2]] = $hook_name; 
     48        $admin_page_hooks[$menu_item->slug] = $hook_name; 
    4149} 
    42 unset($menu_page, $compat); 
    4350 
    44 $_wp_submenu_nopriv = array(); 
    45 $_wp_menu_nopriv = array(); 
    46 // Loop over submenus and remove pages for which the user does not have privs. 
    47 foreach ( array( 'submenu' ) as $sub_loop ) { 
    48         foreach ($$sub_loop as $parent => $sub) { 
    49                 foreach ($sub as $index => $data) { 
    50                         if ( ! current_user_can($data[1]) ) { 
    51                                 unset(${$sub_loop}[$parent][$index]); 
    52                                 $_wp_submenu_nopriv[$parent][$data[2]] = true; 
    53                         } 
    54                 } 
    55                 unset($index, $data); 
     51function _check_admin_submenu_privs( $menu_item, $admin_menu ) { 
     52        global $_wp_submenu_nopriv; 
    5653 
    57                 if ( empty(${$sub_loop}[$parent]) ) 
    58                         unset(${$sub_loop}[$parent]); 
     54        // Loop over submenus and remove items for which the user does not have privs. 
     55        foreach ( $menu_item->get_children() as $submenu ) { 
     56                if ( !current_user_can( $submenu->cap ) ) { 
     57                        $menu_item->remove( $submenu->id ); 
     58                        $_wp_submenu_nopriv[$menu_item->slug][$submenu->slug] = true; 
     59                } 
    5960        } 
    60         unset($sub, $parent); 
    61 } 
    62 unset($sub_loop); 
    6361 
    64 // Loop over the top-level menu. 
    65 // Menus for which the original parent is not accessible due to lack of privs will have the next 
    66 // submenu in line be assigned as the new menu parent. 
    67 foreach ( $menu as $id => $data ) { 
    68         if ( empty($submenu[$data[2]]) ) 
    69                 continue; 
    70         $subs = $submenu[$data[2]]; 
    71         $first_sub = array_shift($subs); 
    72         $old_parent = $data[2]; 
    73         $new_parent = $first_sub[2]; 
    74         // If the first submenu is not the same as the assigned parent, 
    75         // make the first submenu the new parent. 
    76         if ( $new_parent != $old_parent ) { 
    77                 $_wp_real_parent_file[$old_parent] = $new_parent; 
    78                 $menu[$id][2] = $new_parent; 
     62        // Menus for which the original parent is not accessible due to lack of privs 
     63        // will have the next submenu in line be assigned as the new menu parent. 
     64        $subs = $menu_item->get_children(); 
     65 
     66        if ( empty( $subs ) ) 
     67                return; 
     68 
     69        $first_sub = array_shift( $subs ); 
    7970 
    80                 foreach ($submenu[$old_parent] as $index => $data) { 
    81                         $submenu[$new_parent][$index] = $submenu[$old_parent][$index]; 
    82                         unset($submenu[$old_parent][$index]); 
     71        $old_parent = $menu_item->slug; 
     72        $new_parent = $first_sub->slug; 
     73 
     74        if ( $new_parent != $old_parent ) { 
     75                foreach ( $subs as $sub ) { 
     76                        $first_sub->append( $sub ); 
    8377                } 
    84                 unset($submenu[$old_parent], $index); 
     78 
     79                $admin_menu->replace( $menu_item->id, $first_sub ); 
     80 
     81                $_wp_real_parent_file[$old_parent] = $new_parent; 
    8582 
    8683                if ( isset($_wp_submenu_nopriv[$old_parent]) ) 
    8784                        $_wp_submenu_nopriv[$new_parent] = $_wp_submenu_nopriv[$old_parent]; 
    8885        } 
    8986} 
    90 unset($id, $data, $subs, $first_sub, $old_parent, $new_parent); 
    9187 
    9288if ( is_network_admin() ) 
    9389        do_action('network_admin_menu', ''); 
    elseif ( is_user_admin() ) 
    9692else 
    9793        do_action('admin_menu', ''); 
    9894 
    99 // Remove menus that have no accessible submenus and require privs that the user does not have. 
    100 // Run re-parent loop again. 
    101 foreach ( $menu as $id => $data ) { 
    102         if ( ! current_user_can($data[1]) ) 
    103                 $_wp_menu_nopriv[$data[2]] = true; 
     95$admin_menu->_loop( '_check_admin_menu_privs' ); 
     96 
     97// Remove menus that have no accessible submenus 
     98// and require privs that the user does not have. 
     99function _check_admin_menu_privs( $menu_item, $admin_menu ) { 
     100        global $_wp_menu_nopriv; 
     101 
     102        if ( ! current_user_can( $menu_item->cap ) ) 
     103                $_wp_menu_nopriv[$menu_item->slug] = true; 
     104 
     105        $subs = $menu_item->get_children(); 
    104106 
    105107        // If there is only one submenu and it is has same destination as the parent, 
    106108        // remove the submenu. 
    107         if ( ! empty( $submenu[$data[2]] ) && 1 == count ( $submenu[$data[2]] ) ) { 
    108                 $subs = $submenu[$data[2]]; 
    109                 $first_sub = array_shift($subs); 
    110                 if ( $data[2] == $first_sub[2] ) 
    111                         unset( $submenu[$data[2]] ); 
     109        if ( ! empty( $subs ) && 1 == count( $subs ) ) { 
     110                $first_sub = array_shift( $subs ); 
     111                if ( $menu_item->slug == $first_sub->slug ) 
     112                        $menu_item->remove( $first_sub->id ); 
    112113        } 
    113114 
    114115        // If submenu is empty... 
    115         if ( empty($submenu[$data[2]]) ) { 
     116        if ( !$menu_item->has_children() ) { 
    116117                // And user doesn't have privs, remove menu. 
    117                 if ( isset( $_wp_menu_nopriv[$data[2]] ) ) { 
    118                         unset($menu[$id]); 
     118                if ( isset( $_wp_menu_nopriv[$menu_item->slug] ) ) { 
     119                        $admin_menu->remove( $menu_item->id ); 
    119120                } 
    120121        } 
    121122} 
    122 unset($id, $data, $subs, $first_sub); 
    123123 
    124124// Remove any duplicated separators 
    125125$separator_found = false; 
    126 foreach ( $menu as $id => $data ) { 
    127         if ( 0 == strcmp('wp-menu-separator', $data[4] ) ) { 
    128                 if (false == $separator_found) { 
     126foreach ( $admin_menu->get_children() as $menu_item ) { 
     127        if ( 'wp-menu-separator' == $menu_item->class ) { 
     128                if ( !$separator_found ) { 
    129129                        $separator_found = true; 
    130130                } else { 
    131                         unset($menu[$id]); 
     131                        $admin_menu->remove( $menu_item->id ); 
    132132                        $separator_found = false; 
    133133                } 
    134134        } else { 
    135135                $separator_found = false; 
    136136        } 
    137137} 
    138 unset($id, $data); 
    139  
    140 function add_cssclass($add, $class) { 
    141         $class = empty($class) ? $add : $class .= ' ' . $add; 
    142         return $class; 
    143 } 
    144  
    145 function add_menu_classes($menu) { 
    146  
    147         $first = $lastorder = false; 
    148         $i = 0; 
    149         $mc = count($menu); 
    150         foreach ( $menu as $order => $top ) { 
    151                 $i++; 
    152  
    153                 if ( 0 == $order ) { // dashboard is always shown/single 
    154                         $menu[0][4] = add_cssclass('menu-top-first', $top[4]); 
    155                         $lastorder = 0; 
    156                         continue; 
    157                 } 
    158  
    159                 if ( 0 === strpos($top[2], 'separator') ) { // if separator 
    160                         $first = true; 
    161                         $c = $menu[$lastorder][4]; 
    162                         $menu[$lastorder][4] = add_cssclass('menu-top-last', $c); 
    163                         continue; 
    164                 } 
    165  
    166                 if ( $first ) { 
    167                         $c = $menu[$order][4]; 
    168                         $menu[$order][4] = add_cssclass('menu-top-first', $c); 
    169                         $first = false; 
    170                 } 
    171  
    172                 if ( $mc == $i ) { // last item 
    173                         $c = $menu[$order][4]; 
    174                         $menu[$order][4] = add_cssclass('menu-top-last', $c); 
    175                 } 
    176  
    177                 $lastorder = $order; 
    178         } 
    179  
    180         return apply_filters( 'add_menu_classes', $menu ); 
    181 } 
    182  
    183 uksort($menu, "strnatcasecmp"); // make it all pretty 
    184  
    185 if ( apply_filters('custom_menu_order', false) ) { 
    186         $menu_order = array(); 
    187         foreach ( $menu as $menu_item ) { 
    188                 $menu_order[] = $menu_item[2]; 
    189         } 
    190         unset($menu_item); 
    191         $default_menu_order = $menu_order; 
    192         $menu_order = apply_filters('menu_order', $menu_order); 
    193         $menu_order = array_flip($menu_order); 
    194         $default_menu_order = array_flip($default_menu_order); 
    195  
    196         function sort_menu($a, $b) { 
    197                 global $menu_order, $default_menu_order; 
    198                 $a = $a[2]; 
    199                 $b = $b[2]; 
    200                 if ( isset($menu_order[$a]) && !isset($menu_order[$b]) ) { 
    201                         return -1; 
    202                 } elseif ( !isset($menu_order[$a]) && isset($menu_order[$b]) ) { 
    203                         return 1; 
    204                 } elseif ( isset($menu_order[$a]) && isset($menu_order[$b]) ) { 
    205                         if ( $menu_order[$a] == $menu_order[$b] ) 
    206                                 return 0; 
    207                         return ($menu_order[$a] < $menu_order[$b]) ? -1 : 1; 
    208                 } else { 
    209                         return ($default_menu_order[$a] <= $default_menu_order[$b]) ? -1 : 1; 
    210                 } 
    211         } 
    212  
    213         usort($menu, 'sort_menu'); 
    214         unset($menu_order, $default_menu_order); 
    215 } 
    216  
    217 // Remove the last menu item if it is a separator. 
    218 $last_menu_key = array_keys( $menu ); 
    219 $last_menu_key = array_pop( $last_menu_key ); 
    220 if ( !empty( $menu ) && 'wp-menu-separator' == $menu[ $last_menu_key ][ 4 ] ) 
    221         unset( $menu[ $last_menu_key ] ); 
    222 unset( $last_menu_key ); 
     138unset($separator_found, $menu_item); 
    223139 
    224140if ( !user_can_access_admin_page() ) { 
    225141        do_action('admin_page_access_denied'); 
    226142        wp_die( __('You do not have sufficient permissions to access this page.') ); 
    227143} 
    228144 
    229 $menu = add_menu_classes($menu); 
  • wp-admin/includes/plugin.php

    diff --git wp-admin/includes/plugin.php wp-admin/includes/plugin.php
    index 941f545..4f97259 100644
    function uninstall_plugin($plugin) { 
    885885 * @param string $menu_slug The slug name to refer to this menu by (should be unique for this menu) 
    886886 * @param callback $function The function to be called to output the content for this page. 
    887887 * @param string $icon_url The url to the icon to be used for this menu 
    888  * @param int $position The position in the menu order this one should appear 
     888 * @param string $before The menu item before which this one should appear 
    889889 * 
    890890 * @return string The resulting page's hook_suffix 
    891891 */ 
    892 function add_menu_page( $page_title, $menu_title, $capability, $menu_slug, $function = '', $icon_url = '', $position = null ) { 
    893         global $menu, $admin_page_hooks, $_registered_pages, $_parent_pages; 
     892function add_menu_page( $page_title, $menu_title, $capability, $menu_slug, $function = '', $icon_url = '', $before = null ) { 
     893        global $admin_menu, $admin_page_hooks, $_registered_pages, $_parent_pages; 
    894894 
    895         $menu_slug = plugin_basename( $menu_slug ); 
     895        if ( is_numeric( $before ) ) { 
     896                _deprecated_argument( __FUNCTION__, '3.5', __( 'Numeric menu positions are deprecated. Use menu ids instead.' ) ); 
     897                $before = null; 
     898        } 
    896899 
    897         $admin_page_hooks[$menu_slug] = sanitize_title( $menu_title ); 
     900        $menu_slug = plugin_basename( $menu_slug ); 
    898901 
    899902        $hookname = get_plugin_page_hookname( $menu_slug, '' ); 
    900903 
    901904        if ( !empty( $function ) && !empty( $hookname ) && current_user_can( $capability ) ) 
    902905                add_action( $hookname, $function ); 
    903906 
     907        $admin_page_hooks[$menu_slug] = sanitize_title( $menu_title ); 
     908 
     909        $_registered_pages[$hookname] = true; 
     910 
     911        // No parent as top level 
     912        $_parent_pages[$menu_slug] = false; 
     913 
    904914        if ( empty($icon_url) ) 
    905915                $icon_url = esc_url( admin_url( 'images/generic.png' ) ); 
    906916        elseif ( is_ssl() && 0 === strpos($icon_url, 'http://') ) 
    907917                $icon_url = 'https://' . substr($icon_url, 7); 
    908918 
    909         $new_menu = array( $menu_title, $capability, $menu_slug, $page_title, 'menu-top ' . $hookname, $hookname, $icon_url ); 
     919        $menu_args = array( 
     920                'title' => $menu_title, 
     921                'cap' => $capability, 
     922                'slug' => $menu_slug, 
     923                'class' => 'menu-top ' . $hookname, 
     924                'icon' => $icon_url 
     925        ); 
    910926 
    911         if ( null === $position ) 
    912                 $menu[] = $new_menu; 
     927        if ( null === $before ) 
     928                $admin_menu->append( $args ); 
    913929        else 
    914                 $menu[$position] = $new_menu; 
    915  
    916         $_registered_pages[$hookname] = true; 
    917  
    918         // No parent as top level 
    919         $_parent_pages[$menu_slug] = false; 
     930                $admin_menu->insert_before( $before, $args ); 
    920931 
    921932        return $hookname; 
    922933} 
    function add_menu_page( $page_title, $menu_title, $capability, $menu_slug, $func 
    940951 * @return string The resulting page's hook_suffix 
    941952 */ 
    942953function add_object_page( $page_title, $menu_title, $capability, $menu_slug, $function = '', $icon_url = '') { 
    943         global $_wp_last_object_menu; 
    944  
    945         $_wp_last_object_menu++; 
    946  
    947         return add_menu_page($page_title, $menu_title, $capability, $menu_slug, $function, $icon_url, $_wp_last_object_menu); 
     954        return add_menu_page( $page_title, $menu_title, $capability, $menu_slug, $function, $icon_url, 'separator2' ); 
    948955} 
    949956 
    950957/** 
    function add_object_page( $page_title, $menu_title, $capability, $menu_slug, $fu 
    966973 * @return string The resulting page's hook_suffix 
    967974 */ 
    968975function add_utility_page( $page_title, $menu_title, $capability, $menu_slug, $function = '', $icon_url = '') { 
    969         global $_wp_last_utility_menu; 
    970  
    971         $_wp_last_utility_menu++; 
    972  
    973         return add_menu_page($page_title, $menu_title, $capability, $menu_slug, $function, $icon_url, $_wp_last_utility_menu); 
     976        return add_menu_page( $page_title, $menu_title, $capability, $menu_slug, $function, $icon_url, 'separator-last' ); 
    974977} 
    975978 
    976979/** 
    function add_utility_page( $page_title, $menu_title, $capability, $menu_slug, $f 
    989992 * @param string $menu_slug The slug name to refer to this menu by (should be unique for this menu) 
    990993 * @param callback $function The function to be called to output the content for this page. 
    991994 * 
    992  * @return string|bool The resulting page's hook_suffix, or false if the user does not have the capability required. 
     995 * @return string|bool The resulting page's hook_suffix, or false on failure 
    993996 */ 
    994997function add_submenu_page( $parent_slug, $page_title, $menu_title, $capability, $menu_slug, $function = '' ) { 
    995         global $submenu; 
    996         global $menu; 
     998        global $admin_menu; 
    997999        global $_wp_real_parent_file; 
    9981000        global $_wp_submenu_nopriv; 
    9991001        global $_registered_pages; 
    10001002        global $_parent_pages; 
    10011003 
    10021004        $menu_slug = plugin_basename( $menu_slug ); 
    1003         $parent_slug = plugin_basename( $parent_slug); 
     1005        $parent_slug = plugin_basename( $parent_slug ); 
    10041006 
    1005         if ( isset( $_wp_real_parent_file[$parent_slug] ) ) 
     1007        if ( isset( $_wp_real_parent_file[$parent_slug] ) ) { 
    10061008                $parent_slug = $_wp_real_parent_file[$parent_slug]; 
     1009        } 
    10071010 
    10081011        if ( !current_user_can( $capability ) ) { 
    10091012                $_wp_submenu_nopriv[$parent_slug][$menu_slug] = true; 
    10101013                return false; 
    10111014        } 
    10121015 
     1016        $parent_menu = $admin_menu->get( $parent_slug, 'slug' ); 
     1017        if ( !$parent_menu ) { 
     1018                return false; 
     1019        } 
     1020 
    10131021        // If the parent doesn't already have a submenu, add a link to the parent 
    10141022        // as the first item in the submenu. If the submenu file is the same as the 
    10151023        // parent file someone is trying to link back to the parent manually. In 
    10161024        // this case, don't automatically add a link back to avoid duplication. 
    1017         if (!isset( $submenu[$parent_slug] ) && $menu_slug != $parent_slug ) { 
    1018                 foreach ( (array)$menu as $parent_menu ) { 
    1019                         if ( $parent_menu[2] == $parent_slug && current_user_can( $parent_menu[1] ) ) 
    1020                                 $submenu[$parent_slug][] = $parent_menu; 
    1021                 } 
     1025        if ( !$parent_menu->has_children() && $menu_slug != $parent_slug ) { 
     1026                $admin_menu->add_first_submenu( $parent_menu->id, $parent_menu->title ); 
    10221027        } 
    10231028 
    1024         $submenu[$parent_slug][] = array ( $menu_title, $capability, $menu_slug, $page_title ); 
     1029        $parent_menu->append( array( 
     1030                'title' => $menu_title, 
     1031                'cap' => $capability, 
     1032                'slug' => $menu_slug, 
     1033                'page_title' => $page_title // TODO: why is this stored here? 
     1034        ) ); 
    10251035 
    10261036        $hookname = get_plugin_page_hookname( $menu_slug, $parent_slug); 
     1037 
    10271038        if (!empty ( $function ) && !empty ( $hookname )) 
    10281039                add_action( $hookname, $function ); 
    10291040 
    10301041        $_registered_pages[$hookname] = true; 
     1042 
    10311043        // backwards-compatibility for plugins using add_management page. See wp-admin/admin.php for redirect from edit.php to tools.php 
    1032         if ( 'tools.php' == $parent_slug ) 
    1033                 $_registered_pages[get_plugin_page_hookname( $menu_slug, 'edit.php')] = true; 
     1044        if ( 'tools.php' == $parent_slug ) { 
     1045                $compat_hookname = get_plugin_page_hookname( $menu_slug, 'edit.php' ); 
     1046 
     1047                $_registered_pages[ $compat_hookname ] = true; 
     1048        } 
    10341049 
    10351050        // No parent as top level 
    10361051        $_parent_pages[$menu_slug] = $parent_slug; 
    function add_comments_page( $page_title, $menu_title, $capability, $menu_slug, $ 
    12771292 * 
    12781293 * @since 3.1.0 
    12791294 * 
    1280  * @param string $menu_slug The slug of the menu 
     1295 * @param string $menu_url The url of the menu 
    12811296 * @return array|bool The removed menu on success, False if not found 
    12821297 */ 
    1283 function remove_menu_page( $menu_slug ) { 
    1284         global $menu; 
     1298function remove_menu_page( $menu_url ) { 
     1299        global $admin_menu; 
    12851300 
    1286         foreach ( $menu as $i => $item ) { 
    1287                 if ( $menu_slug == $item[2] ) { 
    1288                         unset( $menu[$i] ); 
    1289                         return $item; 
    1290                 } 
    1291         } 
     1301        $item = $admin_menu->get( $menu_url, 'slug' ); 
     1302        if ( !$item ) 
     1303                return false; 
    12921304 
    1293         return false; 
     1305        $admin_menu->remove( $item->id ); 
     1306 
     1307        // TODO: return legacy numeric array 
     1308 
     1309        return true; 
    12941310} 
    12951311 
    12961312/** 
    function remove_menu_page( $menu_slug ) { 
    12981314 * 
    12991315 * @since 3.1.0 
    13001316 * 
    1301  * @param string $menu_slug The slug for the parent menu 
    1302  * @param string $submenu_slug The slug of the submenu 
     1317 * @param string $menu_url The url for the parent menu 
     1318 * @param string $submenu_url The url of the submenu 
    13031319 * @return array|bool The removed submenu on success, False if not found 
    13041320 */ 
    1305 function remove_submenu_page( $menu_slug, $submenu_slug ) { 
    1306         global $submenu; 
     1321function remove_submenu_page( $menu_url, $submenu_url ) { 
     1322        global $admin_menu; 
    13071323 
    1308         if ( !isset( $submenu[$menu_slug] ) ) 
     1324        $item = $admin_menu->get( $menu_url, 'slug' ); 
     1325        if ( !$item ) 
    13091326                return false; 
    13101327 
    1311         foreach ( $submenu[$menu_slug] as $i => $item ) { 
    1312                 if ( $submenu_slug == $item[2] ) { 
    1313                         unset( $submenu[$menu_slug][$i] ); 
    1314                         return $item; 
    1315                 } 
    1316         } 
     1328        $submenu = $item->get( $submenu_url, 'slug' ); 
     1329        if ( !$submenu ) 
     1330                return false; 
    13171331 
    1318         return false; 
     1332        $item->remove( $submenu->id ); 
     1333 
     1334        // TODO: return legacy numeric array 
     1335 
     1336        return true; 
    13191337} 
    13201338 
    13211339/** 
    function menu_page_url($menu_slug, $echo = true) { 
    13571375 
    13581376function get_admin_page_parent( $parent = '' ) { 
    13591377        global $parent_file; 
    1360         global $menu; 
    1361         global $submenu; 
     1378        global $admin_menu; 
    13621379        global $pagenow; 
    13631380        global $typenow; 
    13641381        global $plugin_page; 
    function get_admin_page_parent( $parent = '' ) { 
    13721389                return $parent; 
    13731390        } 
    13741391 
    1375         /* 
    1376         if ( !empty ( $parent_file ) ) { 
    1377                 if ( isset( $_wp_real_parent_file[$parent_file] ) ) 
    1378                         $parent_file = $_wp_real_parent_file[$parent_file]; 
    1379  
    1380                 return $parent_file; 
    1381         } 
    1382         */ 
    1383  
    13841392        if ( $pagenow == 'admin.php' && isset( $plugin_page ) ) { 
    1385                 foreach ( (array)$menu as $parent_menu ) { 
    1386                         if ( $parent_menu[2] == $plugin_page ) { 
    1387                                 $parent_file = $plugin_page; 
    1388                                 if ( isset( $_wp_real_parent_file[$parent_file] ) ) 
    1389                                         $parent_file = $_wp_real_parent_file[$parent_file]; 
    1390                                 return $parent_file; 
    1391                         } 
     1393                $current_item = $admin_menu->get( $plugin_page, 'slug' ); 
     1394                if ( $current_item ) { 
     1395                        $parent_file = $plugin_page; 
     1396                        if ( isset( $_wp_real_parent_file[$parent_file] ) ) 
     1397                                $parent_file = $_wp_real_parent_file[$parent_file]; 
     1398                        return $parent_file; 
    13921399                } 
     1400 
    13931401                if ( isset( $_wp_menu_nopriv[$plugin_page] ) ) { 
    13941402                        $parent_file = $plugin_page; 
    13951403                        if ( isset( $_wp_real_parent_file[$parent_file] ) ) 
    function get_admin_page_parent( $parent = '' ) { 
    14051413                return $parent_file; 
    14061414        } 
    14071415 
    1408         foreach (array_keys( (array)$submenu ) as $parent) { 
    1409                 foreach ( $submenu[$parent] as $submenu_array ) { 
    1410                         if ( isset( $_wp_real_parent_file[$parent] ) ) 
    1411                                 $parent = $_wp_real_parent_file[$parent]; 
    1412                         if ( !empty($typenow) && ($submenu_array[2] == "$pagenow?post_type=$typenow") ) { 
     1416        foreach ( $admin_menu->get_children() as $menu_item ) { 
     1417                if ( !isset( $menu_item->slug ) ) 
     1418                        continue; 
     1419 
     1420                $parent = $menu_item->slug; 
     1421                if ( isset( $_wp_real_parent_file[$parent] ) ) 
     1422                        $parent = $_wp_real_parent_file[$parent]; 
     1423 
     1424                foreach ( $menu_item->get_children() as $submenu ) { 
     1425                        if ( !empty($typenow) && $submenu->slug == "$pagenow?post_type=$typenow" ) { 
    14131426                                $parent_file = $parent; 
    14141427                                return $parent; 
    1415                         } elseif ( $submenu_array[2] == $pagenow && empty($typenow) && ( empty($parent_file) || false === strpos($parent_file, '?') ) ) { 
     1428                        } 
     1429 
     1430                        if ( $submenu->slug == $pagenow && empty($typenow) && ( empty($parent_file) || false === strpos($parent_file, '?') ) ) { 
    14161431                                $parent_file = $parent; 
    14171432                                return $parent; 
    1418                         } else 
    1419                                 if ( isset( $plugin_page ) && ($plugin_page == $submenu_array[2] ) ) { 
    1420                                         $parent_file = $parent; 
    1421                                         return $parent; 
    1422                                 } 
     1433                        } 
     1434 
     1435                        if ( isset( $plugin_page ) && $plugin_page == $submenu->slug ) { 
     1436                                $parent_file = $parent; 
     1437                                return $parent; 
     1438                        } 
    14231439                } 
    14241440        } 
    14251441 
    function get_admin_page_parent( $parent = '' ) { 
    14301446 
    14311447function get_admin_page_title() { 
    14321448        global $title; 
    1433         global $menu; 
    1434         global $submenu; 
     1449        global $admin_menu; 
    14351450        global $pagenow; 
    14361451        global $plugin_page; 
    14371452        global $typenow; 
    function get_admin_page_title() { 
    14411456 
    14421457        $hook = get_plugin_page_hook( $plugin_page, $pagenow ); 
    14431458 
    1444         $parent = $parent1 = get_admin_page_parent(); 
    1445  
    1446         if ( empty ( $parent) ) { 
    1447                 foreach ( (array)$menu as $menu_array ) { 
    1448                         if ( isset( $menu_array[3] ) ) { 
    1449                                 if ( $menu_array[2] == $pagenow ) { 
    1450                                         $title = $menu_array[3]; 
    1451                                         return $menu_array[3]; 
    1452                                 } else 
    1453                                         if ( isset( $plugin_page ) && ($plugin_page == $menu_array[2] ) && ($hook == $menu_array[3] ) ) { 
    1454                                                 $title = $menu_array[3]; 
    1455                                                 return $menu_array[3]; 
    1456                                         } 
    1457                         } else { 
    1458                                 $title = $menu_array[0]; 
    1459                                 return $title; 
     1459        $parent = get_admin_page_parent(); 
     1460 
     1461        if ( empty($parent) ) { 
     1462                if ( isset( $menu_item->page_title ) ) { 
     1463                        if ( $menu_item->slug == $pagenow ) { 
     1464                                $title = $menu_item->page_title; 
     1465                                return $menu_item->page_title; 
     1466                        } elseif ( isset( $plugin_page ) && $plugin_page == $menu_item->slug && $hook == $menu_item->page_title ) { 
     1467                                $title = $menu_item->page_title; 
     1468                                return $menu_item->page_title; 
    14601469                        } 
     1470                } else { 
     1471                        $title = $menu_item->title; 
     1472                        return $title; 
    14611473                } 
    1462         } else { 
    1463                 foreach ( array_keys( $submenu ) as $parent ) { 
    1464                         foreach ( $submenu[$parent] as $submenu_array ) { 
    1465                                 if ( isset( $plugin_page ) && 
    1466                                         ( $plugin_page == $submenu_array[2] ) && 
    1467                                         ( 
    1468                                                 ( $parent == $pagenow ) || 
    1469                                                 ( $parent == $plugin_page ) || 
    1470                                                 ( $plugin_page == $hook ) || 
    1471                                                 ( $pagenow == 'admin.php' && $parent1 != $submenu_array[2] ) || 
    1472                                                 ( !empty($typenow) && $parent == $pagenow . '?post_type=' . $typenow) 
    1473                                         ) 
    1474                                         ) { 
    1475                                                 $title = $submenu_array[3]; 
    1476                                                 return $submenu_array[3]; 
    1477                                         } 
     1474        } 
    14781475 
    1479                                 if ( $submenu_array[2] != $pagenow || isset( $_GET['page'] ) ) // not the current page 
    1480                                         continue; 
     1476        $menu_item = $admin_menu->get( $parent, 'slug' ); 
     1477 
     1478        foreach ( $menu_item->get_children() as $submenu ) { 
     1479                if ( isset( $plugin_page ) && 
     1480                        $plugin_page == $submenu->slug && ( 
     1481                                ( $parent == $pagenow ) || 
     1482                                ( $parent == $plugin_page ) || 
     1483                                ( $plugin_page == $hook ) || 
     1484                                ( $pagenow == 'admin.php' && $parent != $submenu->slug ) || 
     1485                                ( !empty($typenow) && $parent == $pagenow . '?post_type=' . $typenow) 
     1486                        ) 
     1487                ) { 
     1488                        $title = $submenu->page_title; 
     1489                        return $submenu->page_title; 
     1490                } 
    14811491 
    1482                                 if ( isset( $submenu_array[3] ) ) { 
    1483                                         $title = $submenu_array[3]; 
    1484                                         return $submenu_array[3]; 
    1485                                 } else { 
    1486                                         $title = $submenu_array[0]; 
    1487                                         return $title; 
    1488                                 } 
    1489                         } 
     1492                if ( $submenu->slug != $pagenow || isset( $_GET['page'] ) ) // not the current page 
     1493                        continue; 
     1494 
     1495                if ( isset( $submenu->page_title ) ) { 
     1496                        $title = $submenu->page_title; 
     1497                        return $submenu->page_title; 
     1498                } else { 
     1499                        $title = $submenu->title; 
     1500                        return $title; 
    14901501                } 
    1491                 if ( empty ( $title ) ) { 
    1492                         foreach ( $menu as $menu_array ) { 
    1493                                 if ( isset( $plugin_page ) && 
    1494                                         ( $plugin_page == $menu_array[2] ) && 
    1495                                         ( $pagenow == 'admin.php' ) && 
    1496                                         ( $parent1 == $menu_array[2] ) ) 
    1497                                         { 
    1498                                                 $title = $menu_array[3]; 
    1499                                                 return $menu_array[3]; 
    1500                                         } 
    1501                         } 
     1502        } 
     1503 
     1504        if ( empty ( $title ) ) { 
     1505                if ( isset( $plugin_page ) && 
     1506                        ( $plugin_page == $menu_item->slug ) && 
     1507                        ( $pagenow == 'admin.php' ) && 
     1508                        ( $parent == $menu_item->slug ) ) 
     1509                { 
     1510                        $title = $menu_item->page_title; 
     1511                        return $menu_item->page_title; 
    15021512                } 
    15031513        } 
    15041514 
    function get_plugin_page_hookname( $plugin_page, $parent_page ) { 
    15361546 
    15371547function user_can_access_admin_page() { 
    15381548        global $pagenow; 
    1539         global $menu; 
    1540         global $submenu; 
     1549        global $admin_menu; 
    15411550        global $_wp_menu_nopriv; 
    15421551        global $_wp_submenu_nopriv; 
    15431552        global $plugin_page; 
    function user_can_access_admin_page() { 
    15791588        if ( isset( $plugin_page ) && ( $plugin_page == $parent ) && isset( $_wp_menu_nopriv[$plugin_page] ) ) 
    15801589                return false; 
    15811590 
    1582         if ( isset( $submenu[$parent] ) ) { 
    1583                 foreach ( $submenu[$parent] as $submenu_array ) { 
    1584                         if ( isset( $plugin_page ) && ( $submenu_array[2] == $plugin_page ) ) { 
    1585                                 if ( current_user_can( $submenu_array[1] )) 
    1586                                         return true; 
    1587                                 else 
    1588                                         return false; 
    1589                         } else if ( $submenu_array[2] == $pagenow ) { 
    1590                                 if ( current_user_can( $submenu_array[1] )) 
    1591                                         return true; 
    1592                                 else 
    1593                                         return false; 
    1594                         } 
    1595                 } 
    1596         } 
     1591        $curret_item = $admin_menu->get( $parent, 'slug' ); 
     1592        if ( !$curret_item ) 
     1593                return true; 
    15971594 
    1598         foreach ( $menu as $menu_array ) { 
    1599                 if ( $menu_array[2] == $parent) { 
    1600                         if ( current_user_can( $menu_array[1] )) 
    1601                                 return true; 
    1602                         else 
    1603                                 return false; 
     1595        foreach ( $curret_item->get_children() as $submenu ) { 
     1596                if ( isset( $plugin_page ) && $submenu->slug == $plugin_page ) { 
     1597                        return current_user_can( $submenu->cap ); 
     1598                } else if ( $submenu->slug == $pagenow ) { 
     1599                        return current_user_can( $submenu->cap ); 
    16041600                } 
    16051601        } 
    16061602 
    1607         return true; 
     1603        return current_user_can( $curret_item->cap ); 
    16081604} 
    16091605 
    16101606/* Whitelist functions */ 
  • wp-admin/menu-header.php

    diff --git wp-admin/menu-header.php wp-admin/menu-header.php
    index ab51cbc..e77e767 100644
    $self = preg_replace('|^.*/wp-admin/|i', '', $self); 
    1818$self = preg_replace('|^.*/plugins/|i', '', $self); 
    1919$self = preg_replace('|^.*/mu-plugins/|i', '', $self); 
    2020 
    21 global $menu, $submenu, $parent_file; //For when admin-header is included from within a function. 
     21global $admin_menu, $parent_file; //For when admin-header is included from within a function. 
    2222$parent_file = apply_filters("parent_file", $parent_file); // For plugins to move submenu tabs around. 
    2323 
    2424get_admin_page_parent(); 
    2525 
     26function _admin_menu_get_menu_file( $item ) { 
     27        $menu_file = $item->slug; 
     28 
     29        if ( false !== ( $pos = strpos( $menu_file, '?' ) ) ) 
     30                $menu_file = substr($menu_file, 0, $pos); 
     31 
     32        return $menu_file; 
     33} 
     34 
     35function _admin_menu_get_url( $menu_hook, $item, &$admin_is_parent ) { 
     36        $menu_file = _admin_menu_get_menu_file( $item ); 
     37 
     38        if ( 
     39                !empty( $menu_hook ) || 
     40                ( 'index.php' != $item->slug && file_exists( WP_PLUGIN_DIR . "/$menu_file" ) ) 
     41        ) { 
     42                $admin_is_parent = true; 
     43                $url = 'admin.php?page=' . $item->slug; 
     44        } else { 
     45                $url = $item->slug; 
     46        } 
     47 
     48        return $url; 
     49} 
     50 
     51function _admin_menu_is_current( $item ) { 
     52        global $self, $typenow, $parent_file; 
     53 
     54        if ( $parent_file && $item->slug == $parent_file ) 
     55                return true; 
     56 
     57        if ( empty($typenow) && $self == $item->slug ) 
     58                return true; 
     59 
     60        return false; 
     61} 
     62 
     63function _admin_submenu_is_current( $sub_item, $item ) { 
     64        global $self, $typenow, $submenu_file, $plugin_page; 
     65 
     66        if ( isset( $submenu_file ) && $submenu_file == $sub_item->slug ) 
     67                return true; 
     68 
     69        if ( !isset( $plugin_page ) && $self == $sub_item->slug ) 
     70                return true; 
     71 
     72        // Handle current for post_type=post|page|foo pages, which won't match $self. 
     73        $self_type = ! empty( $typenow ) ? $self . '?post_type=' . $typenow : 'nothing'; 
     74 
     75        // If plugin_page is set the parent must either match the current page or not physically exist. 
     76        // This allows plugin pages with the same hook to exist under different parents. 
     77        if ( 
     78                isset( $plugin_page ) && 
     79                $plugin_page == $sub_item->slug && 
     80                ( 
     81                        $item->slug == $self_type || 
     82                        $item->slug == $self || 
     83                        !file_exists( $menu_file ) 
     84                ) 
     85        ) 
     86                return true; 
     87 
     88        return false; 
     89} 
     90 
     91function _admin_submenu_get_url( $sub_item, $item, $admin_is_parent ) { 
     92        $menu_file = _admin_menu_get_menu_file( $item ); 
     93 
     94        $menu_hook = get_plugin_page_hook( $sub_item->slug, $item->slug ); 
     95 
     96        $sub_file = _admin_menu_get_menu_file( $sub_item ); 
     97 
     98        if ( !empty( $menu_hook ) || ( 'index.php' != $sub_item->slug && file_exists( WP_PLUGIN_DIR . "/$sub_file" ) ) ) { 
     99                if ( 
     100                        ( !$admin_is_parent && file_exists( WP_PLUGIN_DIR . "/$menu_file" ) && !is_dir( WP_PLUGIN_DIR . "/{$item->slug}" ) ) 
     101                        || file_exists( $menu_file ) 
     102                ) { 
     103                        $base = $item->slug; 
     104                } else { 
     105                        $base = 'admin.php'; 
     106                } 
     107 
     108                return add_query_arg( 'page', $sub_item->slug, $base ); 
     109        } 
     110 
     111        return $sub_item->slug; 
     112} 
     113 
     114function add_cssclass($add, $class) { 
     115        $class = empty($class) ? $add : $class .= ' ' . $add; 
     116        return $class; 
     117} 
     118 
     119function _add_admin_menu_classes( $admin_menu ) { 
     120        $items = array_values( $admin_menu->get_children() ); 
     121 
     122        // Remove the last menu item if it is a separator. 
     123        $last = end( $items ); 
     124        if ( 'wp-menu-separator' == $last->class ) { 
     125                $admin_menu->remove( $last->id ); 
     126                array_pop( $items ); 
     127        } 
     128 
     129        $first = false; 
     130 
     131        foreach ( $items as $i => $menu_item ) { 
     132                if ( 'dashboard' == $menu_item->id ) { // dashboard is always shown/single 
     133                        $menu_item->class = add_cssclass( 'menu-top-first', $menu_item->class ); 
     134                        continue; 
     135                } 
     136 
     137                if ( 'wp-menu-separator' == $menu_item->class ) { 
     138                        $first = true; 
     139                        $previous = $items[$i-1]; 
     140                        $previous->class = add_cssclass( 'menu-top-last', $previous->class ); 
     141                        continue; 
     142                } 
     143 
     144                if ( $first ) { 
     145                        $menu_item->class = add_cssclass( 'menu-top-first', $menu_item->class ); 
     146                        $first = false; 
     147                } 
     148        } 
     149 
     150        $last = end( $items ); 
     151 
     152        $last->class = add_cssclass( 'menu-top-last', $last->class ); 
     153} 
     154 
    26155/** 
    27156 * Display menu. 
    28157 * 
    get_admin_page_parent(); 
    33162 * @param array $submenu 
    34163 * @param bool $submenu_as_parent 
    35164 */ 
    36 function _wp_menu_output( $menu, $submenu, $submenu_as_parent = true ) { 
    37         global $self, $parent_file, $submenu_file, $plugin_page, $pagenow, $typenow; 
    38  
     165function _wp_menu_output( $menu, $submenu_as_parent = true ) { 
    39166        $first = true; 
    40         // 0 = name, 1 = capability, 2 = file, 3 = class, 4 = id, 5 = icon src 
    41         foreach ( $menu as $key => $item ) { 
     167        foreach ( $menu->get_children() as $item ) { 
     168 
     169                if ( 'wp-menu-separator' == $item->class ) { 
     170                        echo "\n\t<li class='wp-menu-separator' id='menu-$item->id'>"; 
     171                        echo '<div class="separator"></div>'; 
     172                        echo "</li>"; 
     173                        continue; 
     174                } 
     175 
    42176                $admin_is_parent = false; 
    43                 $class = array(); 
     177 
    44178                $aria_attributes = ''; 
    45179 
     180                $class = array(); 
     181 
    46182                if ( $first ) { 
    47183                        $class[] = 'wp-first-item'; 
    48184                        $first = false; 
    49185                } 
    50186 
    51                 $submenu_items = false; 
    52                 if ( ! empty( $submenu[$item[2]] ) ) { 
     187                $submenu_items = $item->get_children(); 
     188 
     189                if ( ! empty( $submenu_items ) ) { 
    53190                        $class[] = 'wp-has-submenu'; 
    54                         $submenu_items = $submenu[$item[2]]; 
    55191                } 
    56192 
    57                 if ( ( $parent_file && $item[2] == $parent_file ) || ( empty($typenow) && $self == $item[2] ) ) { 
    58                         $class[] = ! empty( $submenu_items ) ? 'wp-has-current-submenu wp-menu-open' : 'current'; 
     193                if ( _admin_menu_is_current( $item ) ) { 
     194                        if ( ! empty( $submenu_items ) ) 
     195                                $class[] = 'wp-has-current-submenu wp-menu-open'; 
     196                        else 
     197                                $class[] = 'current'; 
    59198                } else { 
    60199                        $class[] = 'wp-not-current-submenu'; 
    61200                        if ( ! empty( $submenu_items ) ) 
    62201                                $aria_attributes .= 'aria-haspopup="true"'; 
    63202                } 
    64203 
    65                 if ( ! empty( $item[4] ) ) 
    66                         $class[] = $item[4]; 
     204                if ( ! empty( $item->class ) ) 
     205                        $class[] = $item->class; 
     206 
     207                $class[] = 'menu-top'; 
    67208 
    68209                $class = $class ? ' class="' . join( ' ', $class ) . '"' : ''; 
    69                 $id = ! empty( $item[5] ) ? ' id="' . preg_replace( '|[^a-zA-Z0-9_:.]|', '-', $item[5] ) . '"' : ''; 
     210 
     211                $id = ! empty( $item->id ) ? ' id="menu-' . preg_replace( '|[^a-zA-Z0-9_:.]|', '-', $item->id ) . '"' : ''; 
     212 
    70213                $img = ''; 
    71                 if ( ! empty( $item[6] ) ) 
    72                         $img = ( 'div' === $item[6] ) ? '<br />' : '<img src="' . $item[6] . '" alt="" />'; 
     214                if ( ! empty( $item->icon ) ) 
     215                        $img = ( 'div' === $item->icon ) ? '<br />' : '<img src="' . $item->icon . '" alt="" />'; 
     216 
    73217                $arrow = '<div class="wp-menu-arrow"><div></div></div>'; 
    74218 
    75                 $title = wptexturize( $item[0] ); 
    76                 $aria_label = esc_attr( strip_tags( $item[0] ) ); // strip the comment/plugins/updates bubbles spans but keep the pending number if any 
     219                $title = wptexturize( $item->title ); 
     220 
     221                $aria_label = esc_attr( strip_tags( $item->title ) ); // strip the comment/plugins/updates bubbles spans but keep the pending number if any 
    77222 
    78223                echo "\n\t<li$class$id>"; 
    79224 
    80                 if ( false !== strpos( $class, 'wp-menu-separator' ) ) { 
    81                         echo '<div class="separator"></div>'; 
    82                 } elseif ( $submenu_as_parent && ! empty( $submenu_items ) ) { 
    83                         $submenu_items = array_values( $submenu_items );  // Re-index. 
    84                         $menu_hook = get_plugin_page_hook( $submenu_items[0][2], $item[2] ); 
    85                         $menu_file = $submenu_items[0][2]; 
    86                         if ( false !== ( $pos = strpos( $menu_file, '?' ) ) ) 
    87                                 $menu_file = substr( $menu_file, 0, $pos ); 
    88                         if ( ! empty( $menu_hook ) || ( ('index.php' != $submenu_items[0][2]) && file_exists( WP_PLUGIN_DIR . "/$menu_file" ) ) ) { 
    89                                 $admin_is_parent = true; 
    90                                 echo "<div class='wp-menu-image'><a href='admin.php?page={$submenu_items[0][2]}' tabindex='-1' aria-label='$aria_label'>$img</a></div>$arrow<a href='admin.php?page={$submenu_items[0][2]}'$class $aria_attributes>$title</a>"; 
    91                         } else { 
    92                                 echo "\n\t<div class='wp-menu-image'><a href='{$submenu_items[0][2]}' tabindex='-1' aria-label='$aria_label'>$img</a></div>$arrow<a href='{$submenu_items[0][2]}'$class $aria_attributes>$title</a>"; 
    93                         } 
    94                 } elseif ( ! empty( $item[2] ) && current_user_can( $item[1] ) ) { 
    95                         $menu_hook = get_plugin_page_hook( $item[2], 'admin.php' ); 
    96                         $menu_file = $item[2]; 
    97                         if ( false !== ( $pos = strpos( $menu_file, '?' ) ) ) 
    98                                 $menu_file = substr( $menu_file, 0, $pos ); 
    99                         if ( ! empty( $menu_hook ) || ( ('index.php' != $item[2]) && file_exists( WP_PLUGIN_DIR . "/$menu_file" ) ) ) { 
    100                                 $admin_is_parent = true; 
    101                                 echo "\n\t<div class='wp-menu-image'><a href='admin.php?page={$item[2]}' tabindex='-1' aria-label='$aria_label'>$img</a></div>$arrow<a href='admin.php?page={$item[2]}'$class $aria_attributes>{$item[0]}</a>"; 
    102                         } else { 
    103                                 echo "\n\t<div class='wp-menu-image'><a href='{$item[2]}' tabindex='-1' aria-label='$aria_label'>$img</a></div>$arrow<a href='{$item[2]}'$class $aria_attributes>{$item[0]}</a>"; 
    104                         } 
     225                $url = false; 
     226                if ( $submenu_as_parent && ! empty( $submenu_items ) ) { 
     227                        $first_submenu = reset( $submenu_items ); 
     228 
     229                        $menu_hook = get_plugin_page_hook( $first_submenu->slug, $item->slug ); 
     230                        $url = _admin_menu_get_url( $menu_hook, $first_submenu, $admin_is_parent ); 
     231                } 
     232                elseif ( ! empty( $item->slug ) && current_user_can( $item->cap ) ) { 
     233                        $menu_hook = get_plugin_page_hook( $item->slug, 'admin.php' ); 
     234                        $url = _admin_menu_get_url( $menu_hook, $item, $admin_is_parent ); 
     235                } 
     236 
     237                if ( $url ) { 
     238                        echo "<div class='wp-menu-image'><a href='$url' tabindex='-1' aria-label='$aria_label'>$img</a></div>"; 
     239                        echo $arrow; 
     240                        echo "<a href='$url'$class $aria_attributes>$title</a>"; 
    105241                } 
    106242 
    107243                if ( ! empty( $submenu_items ) ) { 
    108244                        echo "\n\t<div class='wp-submenu'><div class='wp-submenu-wrap'>"; 
    109                         echo "<div class='wp-submenu-head'>{$item[0]}</div><ul>"; 
     245                        echo "<div class='wp-submenu-head'>{$item->title}</div><ul>"; 
    110246                        $first = true; 
    111                         foreach ( $submenu_items as $sub_key => $sub_item ) { 
    112                                 if ( ! current_user_can( $sub_item[1] ) ) 
     247                        foreach ( $submenu_items as $sub_item ) { 
     248                                if ( ! current_user_can( $sub_item->cap ) ) 
    113249                                        continue; 
    114250 
    115251                                $class = array(); 
     252 
    116253                                if ( $first ) { 
    117254                                        $class[] = 'wp-first-item'; 
    118255                                        $first = false; 
    119256                                } 
    120257 
    121                                 $menu_file = $item[2]; 
    122  
    123                                 if ( false !== ( $pos = strpos( $menu_file, '?' ) ) ) 
    124                                         $menu_file = substr( $menu_file, 0, $pos ); 
    125  
    126                                 // Handle current for post_type=post|page|foo pages, which won't match $self. 
    127                                 $self_type = ! empty( $typenow ) ? $self . '?post_type=' . $typenow : 'nothing'; 
    128  
    129                                 if ( isset( $submenu_file ) ) { 
    130                                         if ( $submenu_file == $sub_item[2] ) 
    131                                                 $class[] = 'current'; 
    132                                 // If plugin_page is set the parent must either match the current page or not physically exist. 
    133                                 // This allows plugin pages with the same hook to exist under different parents. 
    134                                 } else if ( 
    135                                         ( ! isset( $plugin_page ) && $self == $sub_item[2] ) || 
    136                                         ( isset( $plugin_page ) && $plugin_page == $sub_item[2] && ( $item[2] == $self_type || $item[2] == $self || file_exists($menu_file) === false ) ) 
    137                                 ) { 
     258                                if ( _admin_submenu_is_current( $sub_item, $item ) ) { 
    138259                                        $class[] = 'current'; 
    139260                                } 
    140261 
    141262                                $class = $class ? ' class="' . join( ' ', $class ) . '"' : ''; 
    142263 
    143                                 $menu_hook = get_plugin_page_hook($sub_item[2], $item[2]); 
    144                                 $sub_file = $sub_item[2]; 
    145                                 if ( false !== ( $pos = strpos( $sub_file, '?' ) ) ) 
    146                                         $sub_file = substr($sub_file, 0, $pos); 
     264                                $title = wptexturize( $sub_item->title ); 
    147265 
    148                                 $title = wptexturize($sub_item[0]); 
     266                                $sub_item_url = _admin_submenu_get_url( $sub_item, $item, $admin_is_parent ); 
     267                                $sub_item_url = esc_url( $sub_item_url ); 
    149268 
    150                                 if ( ! empty( $menu_hook ) || ( ('index.php' != $sub_item[2]) && file_exists( WP_PLUGIN_DIR . "/$sub_file" ) ) ) { 
    151                                         // If admin.php is the current page or if the parent exists as a file in the plugins or admin dir 
    152                                         if ( (!$admin_is_parent && file_exists(WP_PLUGIN_DIR . "/$menu_file") && !is_dir(WP_PLUGIN_DIR . "/{$item[2]}")) || file_exists($menu_file) ) 
    153                                                 $sub_item_url = add_query_arg( array('page' => $sub_item[2]), $item[2] ); 
    154                                         else 
    155                                                 $sub_item_url = add_query_arg( array('page' => $sub_item[2]), 'admin.php' ); 
    156  
    157                                         $sub_item_url = esc_url( $sub_item_url ); 
    158                                         echo "<li$class><a href='$sub_item_url'$class>$title</a></li>"; 
    159                                 } else { 
    160                                         echo "<li$class><a href='{$sub_item[2]}'$class>$title</a></li>"; 
    161                                 } 
     269                                echo "<li$class><a href='{$sub_item_url}'$class>$title</a></li>"; 
    162270                        } 
    163271                        echo "</ul></div></div>"; 
    164272                } 
    function _wp_menu_output( $menu, $submenu, $submenu_as_parent = true ) { 
    169277        echo '<span>' . esc_html__( 'Collapse menu' ) . '</span>'; 
    170278        echo '</li>'; 
    171279} 
    172  
    173280?> 
    174281 
    175282<div id="adminmenuback"></div> 
    176283<div id="adminmenuwrap"> 
    177 <div id="adminmenushadow"></div> 
    178 <ul id="adminmenu" role="navigation"> 
     284        <div id="adminmenushadow"></div> 
    179285 
     286        <ul id="adminmenu" role="navigation"> 
    180287<?php 
    181  
    182 _wp_menu_output( $menu, $submenu ); 
    183 do_action( 'adminmenu' ); 
    184  
     288        _add_admin_menu_classes( $admin_menu ); 
     289        _wp_menu_output( $admin_menu ); 
     290        do_action( 'adminmenu' ); 
    185291?> 
    186 </ul> 
     292        </ul> 
    187293</div> 
  • wp-admin/menu.php

    diff --git wp-admin/menu.php wp-admin/menu.php
    index bf914e5..4a43239 100644
     
    66 * @subpackage Administration 
    77 */ 
    88 
    9 /** 
    10  * Constructs the admin menu bar. 
    11  * 
    12  * The elements in the array are : 
    13  *     0: Menu item name 
    14  *     1: Minimum level or capability required. 
    15  *     2: The URL of the item's file 
    16  *     3: Class 
    17  *     4: ID 
    18  *     5: Icon for top level menu 
    19  * 
    20  * @global array $menu 
    21  * @name $menu 
    22  * @var array 
    23  */ 
     9$admin_menu = new WP_Admin_Menu; 
    2410 
    25 $menu[2] = array( __('Dashboard'), 'read', 'index.php', '', 'menu-top menu-top-first menu-icon-dashboard', 'menu-dashboard', 'div' ); 
     11$admin_menu->append( array( 
     12        'title' => __( 'Dashboard' ), 
     13        'cap' => 'read', 
     14        'id' => 'dashboard', 
     15        'slug' => 'index.php', 
     16) ); 
    2617 
    27 $submenu[ 'index.php' ][0] = array( __('Home'), 'read', 'index.php' ); 
     18        $admin_menu->add_first_submenu( 'dashboard', __( 'Home' ) ); 
    2819 
    2920if ( is_multisite() ) { 
    30         $submenu[ 'index.php' ][5] = array( __('My Sites'), 'read', 'my-sites.php' ); 
     21        $admin_menu->add_submenu( 'dashboard', array( 
     22                'title' => __( 'My Sites' ), 
     23                'cap' => 'read', 
     24                'slug' => 'my-sites.php', 
     25        ) ); 
    3126} 
    3227 
    3328if ( ! is_multisite() || is_super_admin() ) 
    3429        $update_data = wp_get_update_data(); 
    3530 
    3631if ( ! is_multisite() ) { 
    37         if ( current_user_can( 'update_core' ) ) 
    38                 $cap = 'update_core'; 
    39         elseif ( current_user_can( 'update_plugins' ) ) 
    40                 $cap = 'update_plugins'; 
    41         else 
    42                 $cap = 'update_themes'; 
    43         $submenu[ 'index.php' ][10] = array( sprintf( __('Updates %s'), "<span class='update-plugins count-{$update_data['counts']['total']}' title='{$update_data['title']}'><span class='update-count'>" . number_format_i18n($update_data['counts']['total']) . "</span></span>" ), $cap, 'update-core.php'); 
    44         unset( $cap ); 
     32        $admin_menu->add_submenu( 'dashboard', array( 
     33                'title' => _admin_menu_update_count( $update_data ), 
     34                'cap' => array( 'update_core', 'update_plugins', 'update_themes' ), 
     35                'slug' => 'update-core.php', 
     36        ) ); 
    4537} 
    4638 
    47 $menu[4] = array( '', 'read', 'separator1', '', 'wp-menu-separator' ); 
    48  
    49 $menu[5] = array( __('Posts'), 'edit_posts', 'edit.php', '', 'open-if-no-js menu-top menu-icon-post', 'menu-posts', 'div' ); 
    50         $submenu['edit.php'][5]  = array( __('All Posts'), 'edit_posts', 'edit.php' ); 
    51         /* translators: add new post */ 
    52         $submenu['edit.php'][10]  = array( _x('Add New', 'post'), 'edit_posts', 'post-new.php' ); 
    53  
    54         $i = 15; 
    55         foreach ( get_taxonomies( array(), 'objects' ) as $tax ) { 
    56                 if ( ! $tax->show_ui || ! in_array('post', (array) $tax->object_type, true) ) 
    57                         continue; 
    58  
    59                 $submenu['edit.php'][$i++] = array( esc_attr( $tax->labels->menu_name ), $tax->cap->manage_terms, 'edit-tags.php?taxonomy=' . $tax->name ); 
    60         } 
    61         unset($tax); 
    62  
    63 $menu[10] = array( __('Media'), 'upload_files', 'upload.php', '', 'menu-top menu-icon-media', 'menu-media', 'div' ); 
    64         $submenu['upload.php'][5] = array( __('Library'), 'upload_files', 'upload.php'); 
    65         /* translators: add new file */ 
    66         $submenu['upload.php'][10] = array( _x('Add New', 'file'), 'upload_files', 'media-new.php'); 
    67  
    68 $menu[15] = array( __('Links'), 'manage_links', 'link-manager.php', '', 'menu-top menu-icon-links', 'menu-links', 'div' ); 
    69         $submenu['link-manager.php'][5] = array( _x('All Links', 'admin menu'), 'manage_links', 'link-manager.php' ); 
    70         /* translators: add new links */ 
    71         $submenu['link-manager.php'][10] = array( _x('Add New', 'link'), 'manage_links', 'link-add.php' ); 
    72         $submenu['link-manager.php'][15] = array( __('Link Categories'), 'manage_categories', 'edit-tags.php?taxonomy=link_category' ); 
    73  
    74 $menu[20] = array( __('Pages'), 'edit_pages', 'edit.php?post_type=page', '', 'menu-top menu-icon-page', 'menu-pages', 'div' ); 
    75         $submenu['edit.php?post_type=page'][5] = array( __('All Pages'), 'edit_pages', 'edit.php?post_type=page' ); 
    76         /* translators: add new page */ 
    77         $submenu['edit.php?post_type=page'][10] = array( _x('Add New', 'page'), 'edit_pages', 'post-new.php?post_type=page' ); 
    78         $i = 15; 
    79         foreach ( get_taxonomies( array(), 'objects' ) as $tax ) { 
    80                 if ( ! $tax->show_ui || ! in_array('page', (array) $tax->object_type, true) ) 
    81                         continue; 
    82  
    83                 $submenu['edit.php?post_type=page'][$i++] = array( esc_attr( $tax->labels->menu_name ), $tax->cap->manage_terms, 'edit-tags.php?taxonomy=' . $tax->name . '&amp;post_type=page' ); 
    84         } 
    85         unset($tax); 
    86  
    87 $awaiting_mod = wp_count_comments(); 
    88 $awaiting_mod = $awaiting_mod->moderated; 
    89 $menu[25] = array( sprintf( __('Comments %s'), "<span class='awaiting-mod count-$awaiting_mod'><span class='pending-count'>" . number_format_i18n($awaiting_mod) . "</span></span>" ), 'edit_posts', 'edit-comments.php', '', 'menu-top menu-icon-comments', 'menu-comments', 'div' ); 
    90 unset($awaiting_mod); 
    91  
    92 $submenu[ 'edit-comments.php' ][0] = array( __('All Comments'), 'edit_posts', 'edit-comments.php' ); 
    93  
    94 $_wp_last_object_menu = 25; // The index of the last top-level menu in the object menu group 
    95  
    96 foreach ( (array) get_post_types( array('show_ui' => true, '_builtin' => false, 'show_in_menu' => true ) ) as $ptype ) { 
    97         $ptype_obj = get_post_type_object( $ptype ); 
    98         // Check if it should be a submenu. 
    99         if ( $ptype_obj->show_in_menu !== true ) 
    100                 continue; 
    101         $ptype_menu_position = is_int( $ptype_obj->menu_position ) ? $ptype_obj->menu_position : ++$_wp_last_object_menu; // If we're to use $_wp_last_object_menu, increment it first. 
    102         $ptype_for_id = sanitize_html_class( $ptype ); 
    103         if ( is_string( $ptype_obj->menu_icon ) ) { 
    104                 $menu_icon   = esc_url( $ptype_obj->menu_icon ); 
    105                 $ptype_class = $ptype_for_id; 
    106         } else { 
    107                 $menu_icon   = 'div'; 
    108                 $ptype_class = 'post'; 
     39$admin_menu->append( array( 
     40        'id' => 'separator1', 
     41        'class' => 'wp-menu-separator', 
     42) ); 
     43 
     44$admin_menu->append( array( 
     45        'title' => __( 'Posts' ), 
     46        'cap' => 'edit_posts', 
     47        'class' => 'open-if-no-js menu-icon-post', 
     48        'id' => 'posts', 
     49        'slug' => 'edit.php', 
     50) ); 
     51 
     52        $admin_menu->add_first_submenu( 'posts', __( 'All Posts' ) ); 
     53 
     54        $admin_menu->add_submenu( 'posts', array( 
     55                /* translators: add new post */ 
     56                'title' => _x( 'Add New', 'post' ), 
     57                'cap' => 'edit_posts', 
     58                'slug' => 'post-new.php', 
     59        ) ); 
     60 
     61        $admin_menu->_add_tax_submenus( 'posts', 'post' ); 
     62 
     63$admin_menu->append( array( 
     64        'title' => __( 'Media' ), 
     65        'cap' => 'upload_files', 
     66        'id' => 'media', 
     67        'slug' => 'upload.php', 
     68) ); 
     69 
     70        $admin_menu->add_first_submenu( 'media', __( 'Library' ) ); 
     71 
     72        $admin_menu->add_submenu( 'media', array( 
     73                /* translators: add new file */ 
     74                'title' => _x( 'Add New', 'file' ), 
     75                'cap' => 'upload_files', 
     76                'slug' => 'media-new.php', 
     77        ) ); 
     78 
     79$admin_menu->append( array( 
     80        'title' => __( 'Links' ), 
     81        'cap' => 'manage_links', 
     82        'id' => 'links', 
     83        'slug' => 'link-manager.php', 
     84) ); 
     85 
     86        $admin_menu->add_first_submenu( 'links', __( 'All Links' ) ); 
     87 
     88        $admin_menu->add_submenu( 'links', array( 
     89                /* translators: add new link */ 
     90                'title' => _x( 'Add New', 'link' ), 
     91                'cap' => 'manage_links', 
     92                'slug' => 'link-add.php', 
     93        ) ); 
     94 
     95        $admin_menu->add_submenu( 'links', array( 
     96                'title' => __( 'Link Categories' ), 
     97                'cap' => 'manage_categories', 
     98                'slug' => 'edit-tags.php?taxonomy=link_category', 
     99        ) ); 
     100 
     101$admin_menu->append( array( 
     102        'title' => __( 'Pages' ), 
     103        'cap' => 'edit_pages', 
     104        'class' => 'menu-icon-page', 
     105        'id' => 'pages', 
     106        'slug' => 'edit.php?post_type=page', 
     107) ); 
     108 
     109        $admin_menu->add_first_submenu( 'pages', __( 'All Pages' ) ); 
     110 
     111        $admin_menu->add_submenu( 'pages', array( 
     112                /* translators: add new link */ 
     113                'title' => _x( 'Add New', 'page' ), 
     114                'cap' => 'edit_pages', 
     115                'slug' => 'post-new.php?post_type=page', 
     116        ) ); 
     117 
     118        $admin_menu->_add_tax_submenus( 'pages', 'page' ); 
     119 
     120$admin_menu->append( array( 
     121        'title' => _admin_menu_comment_count( wp_count_comments()->moderated ), 
     122        'cap' => 'edit_posts', 
     123        'id' => 'comments', 
     124        'slug' => 'edit-comments.php', 
     125) ); 
     126 
     127        $admin_menu->add_first_submenu( 'comments', __( 'All Comments' ) ); 
     128 
     129$admin_menu->append( array( 
     130        'id' => 'separator2', 
     131        'class' => 'wp-menu-separator', 
     132) ); 
     133 
     134$admin_menu->append( array( 
     135        'title' => __('Appearance'), 
     136        'cap' => array( 'switch_themes', 'edit_theme_options' ), 
     137        'slug' => 'themes.php', 
     138        'id' => 'appearance', 
     139) ); 
     140 
     141        $admin_menu->add_first_submenu( 'appearance', __( 'Themes') ); 
     142 
     143        if ( current_theme_supports( 'menus' ) || current_theme_supports( 'widgets' ) ) { 
     144                $admin_menu->add_submenu( 'appearance', array( 
     145                        'title' => __('Menus'), 
     146                        'cap' => array( 'switch_themes', 'edit_theme_options' ), 
     147                        'slug' => 'nav-menus.php', 
     148                ) ); 
    109149        } 
    110150 
    111         // if $ptype_menu_position is already populated or will be populated by a hard-coded value below, increment the position. 
    112         $core_menu_positions = array(59, 60, 65, 70, 75, 80, 85, 99); 
    113         while ( isset($menu[$ptype_menu_position]) || in_array($ptype_menu_position, $core_menu_positions) ) 
    114                 $ptype_menu_position++; 
    115  
    116         $menu[$ptype_menu_position] = array( esc_attr( $ptype_obj->labels->menu_name ), $ptype_obj->cap->edit_posts, "edit.php?post_type=$ptype", '', 'menu-top menu-icon-' . $ptype_class, 'menu-posts-' . $ptype_for_id, $menu_icon ); 
    117         $submenu["edit.php?post_type=$ptype"][5]  = array( $ptype_obj->labels->all_items, $ptype_obj->cap->edit_posts,  "edit.php?post_type=$ptype"); 
    118         $submenu["edit.php?post_type=$ptype"][10]  = array( $ptype_obj->labels->add_new, $ptype_obj->cap->edit_posts, "post-new.php?post_type=$ptype" ); 
    119  
    120         $i = 15; 
    121         foreach ( get_taxonomies( array(), 'objects' ) as $tax ) { 
    122                 if ( ! $tax->show_ui || ! in_array($ptype, (array) $tax->object_type, true) ) 
    123                         continue; 
    124  
    125                 $submenu["edit.php?post_type=$ptype"][$i++] = array( esc_attr( $tax->labels->menu_name ), $tax->cap->manage_terms, "edit-tags.php?taxonomy=$tax->name&amp;post_type=$ptype" ); 
     151        if ( ! is_multisite() ) { 
     152                $admin_menu->add_submenu( 'appearance', array( 
     153                        'title' => _x('Editor', 'theme editor'), 
     154                        'cap' => 'edit_themes', 
     155                        'slug' => 'theme-editor.php', 
     156                ) ); 
    126157        } 
    127 } 
    128 unset($ptype, $ptype_obj, $ptype_class, $ptype_for_id, $ptype_menu_position, $menu_icon, $i, $tax); 
    129  
    130 $menu[59] = array( '', 'read', 'separator2', '', 'wp-menu-separator' ); 
    131158 
    132 if ( current_user_can( 'switch_themes') ) { 
    133         $menu[60] = array( __('Appearance'), 'switch_themes', 'themes.php', '', 'menu-top menu-icon-appearance', 'menu-appearance', 'div' ); 
    134                 $submenu['themes.php'][5]  = array(__('Themes'), 'switch_themes', 'themes.php'); 
    135                 if ( current_theme_supports( 'menus' ) || current_theme_supports( 'widgets' ) ) 
    136                         $submenu['themes.php'][10] = array(__('Menus'), 'edit_theme_options', 'nav-menus.php'); 
    137 } else { 
    138         $menu[60] = array( __('Appearance'), 'edit_theme_options', 'themes.php', '', 'menu-top menu-icon-appearance', 'menu-appearance', 'div' ); 
    139                 $submenu['themes.php'][5]  = array(__('Themes'), 'edit_theme_options', 'themes.php'); 
    140                 if ( current_theme_supports( 'menus' ) || current_theme_supports( 'widgets' ) ) 
    141                         $submenu['themes.php'][10] = array(__('Menus'), 'edit_theme_options', 'nav-menus.php' ); 
    142 } 
    143  
    144 // Add 'Editor' to the bottom of the Appearance menu. 
    145 if ( ! is_multisite() ) 
    146         add_action('admin_menu', '_add_themes_utility_last', 101); 
    147 function _add_themes_utility_last() { 
    148         // Must use API on the admin_menu hook, direct modification is only possible on/before the _admin_menu hook 
    149         add_submenu_page('themes.php', _x('Editor', 'theme editor'), _x('Editor', 'theme editor'), 'edit_themes', 'theme-editor.php'); 
    150 } 
    151  
    152 $count = ''; 
    153159if ( ! is_multisite() && current_user_can( 'update_plugins' ) ) { 
     160 
    154161        if ( ! isset( $update_data ) ) 
    155162                $update_data = wp_get_update_data(); 
    156         $count = "<span class='update-plugins count-{$update_data['counts']['plugins']}'><span class='plugin-count'>" . number_format_i18n($update_data['counts']['plugins']) . "</span></span>"; 
     163 
     164        $plugin_title = _admin_menu_plugin_update_count( $update_data ); 
     165} else { 
     166        $plugin_title = __( 'Plugins' ); 
    157167} 
    158168 
    159 $menu[65] = array( sprintf( __('Plugins %s'), $count ), 'activate_plugins', 'plugins.php', '', 'menu-top menu-icon-plugins', 'menu-plugins', 'div' ); 
     169$admin_menu->append( array( 
     170        'title' => $plugin_title, 
     171        'cap' => 'activate_plugins', 
     172        'slug' => 'plugins.php', 
     173        'id' => 'plugins', 
     174) ); 
    160175 
    161 $submenu['plugins.php'][5]  = array( __('Installed Plugins'), 'activate_plugins', 'plugins.php' ); 
     176        $admin_menu->add_first_submenu( 'plugins', __( 'Installed Plugins') ); 
    162177 
    163178        if ( ! is_multisite() ) { 
    164                 /* translators: add new plugin */ 
    165                 $submenu['plugins.php'][10] = array( _x('Add New', 'plugin'), 'install_plugins', 'plugin-install.php' ); 
    166                 $submenu['plugins.php'][15] = array( _x('Editor', 'plugin editor'), 'edit_plugins', 'plugin-editor.php' ); 
     179                $admin_menu->add_submenu( 'plugins', array( 
     180                        /* translators: add new plugin */ 
     181                        'title' => _x('Add New', 'plugin'), 
     182                        'cap' => 'install_plugins', 
     183                        'slug' => 'plugin-install.php', 
     184                ) ); 
     185 
     186                $admin_menu->add_submenu( 'plugins', array( 
     187                        'title' => _x('Editor', 'plugin editor'), 
     188                        'cap' => 'edit_plugins', 
     189                        'slug' => 'plugin-editor.php', 
     190                ) ); 
    167191        } 
    168192 
    169 unset( $update_data ); 
     193unset( $update_data, $plugin_title ); 
    170194 
    171 if ( current_user_can('list_users') ) 
    172         $menu[70] = array( __('Users'), 'list_users', 'users.php', '', 'menu-top menu-icon-users', 'menu-users', 'div' ); 
    173 else 
    174         $menu[70] = array( __('Profile'), 'read', 'profile.php', '', 'menu-top menu-icon-users', 'menu-users', 'div' ); 
     195if ( current_user_can('list_users') ) { 
     196        $admin_menu->append( array( 
     197                'title' => __('Users'), 
     198                'cap' => 'list_users', 
     199                'slug' => 'users.php', 
     200                'id' => 'users', 
     201        ) ); 
     202} else { 
     203        $admin_menu->append( array( 
     204                'title' => __('Profile'), 
     205                'cap' => 'read', 
     206                'slug' => 'profile.php', 
     207                'id' => 'users', 
     208        ) ); 
     209} 
    175210 
    176211if ( current_user_can('list_users') ) { 
    177212        $_wp_real_parent_file['profile.php'] = 'users.php'; // Back-compat for plugins adding submenus to profile.php. 
    178         $submenu['users.php'][5] = array(__('All Users'), 'list_users', 'users.php'); 
    179         if ( current_user_can('create_users') ) 
    180                 $submenu['users.php'][10] = array(_x('Add New', 'user'), 'create_users', 'user-new.php'); 
    181         else 
    182                 $submenu['users.php'][10] = array(_x('Add New', 'user'), 'promote_users', 'user-new.php'); 
    183213 
    184         $submenu['users.php'][15] = array(__('Your Profile'), 'read', 'profile.php'); 
     214        $admin_menu->add_first_submenu( 'users', __( 'All Users') ); 
     215 
     216        $admin_menu->add_submenu( 'users', array( 
     217                'title' => _x('Add New', 'user'), 
     218                'cap' => array( 'create_users', 'promote_users' ), 
     219                'slug' => 'user-new.php', 
     220        ) ); 
     221 
     222        $admin_menu->add_submenu( 'users', array( 
     223                'title' => __('Your Profile'), 
     224                'cap' => 'read', 
     225                'slug' => 'profile.php', 
     226        ) ); 
    185227} else { 
    186228        $_wp_real_parent_file['users.php'] = 'profile.php'; 
    187         $submenu['profile.php'][5] = array(__('Your Profile'), 'read', 'profile.php'); 
    188         if ( current_user_can('create_users') ) 
    189                 $submenu['profile.php'][10] = array(__('Add New User'), 'create_users', 'user-new.php'); 
    190         else 
    191                 $submenu['profile.php'][10] = array(__('Add New User'), 'promote_users', 'user-new.php'); 
    192 } 
    193229 
    194 $menu[75] = array( __('Tools'), 'edit_posts', 'tools.php', '', 'menu-top menu-icon-tools', 'menu-tools', 'div' ); 
    195         $submenu['tools.php'][5] = array( __('Available Tools'), 'edit_posts', 'tools.php' ); 
    196         $submenu['tools.php'][10] = array( __('Import'), 'import', 'import.php' ); 
    197         $submenu['tools.php'][15] = array( __('Export'), 'export', 'export.php' ); 
    198         if ( is_multisite() && !is_main_site() ) 
    199                 $submenu['tools.php'][25] = array( __('Delete Site'), 'manage_options', 'ms-delete-site.php' ); 
    200         if ( ! is_multisite() && defined('WP_ALLOW_MULTISITE') && WP_ALLOW_MULTISITE ) 
    201                 $submenu['tools.php'][50] = array(__('Network Setup'), 'manage_options', 'network.php'); 
     230        $admin_menu->add_first_submenu( 'users', __( 'Your Profile') ); 
    202231 
    203 $menu[80] = array( __('Settings'), 'manage_options', 'options-general.php', '', 'menu-top menu-icon-settings', 'menu-settings', 'div' ); 
    204         $submenu['options-general.php'][10] = array(_x('General', 'settings screen'), 'manage_options', 'options-general.php'); 
    205         $submenu['options-general.php'][15] = array(__('Writing'), 'manage_options', 'options-writing.php'); 
    206         $submenu['options-general.php'][20] = array(__('Reading'), 'manage_options', 'options-reading.php'); 
    207         $submenu['options-general.php'][25] = array(__('Discussion'), 'manage_options', 'options-discussion.php'); 
    208         $submenu['options-general.php'][30] = array(__('Media'), 'manage_options', 'options-media.php'); 
    209         $submenu['options-general.php'][35] = array(__('Privacy'), 'manage_options', 'options-privacy.php'); 
    210         $submenu['options-general.php'][40] = array(__('Permalinks'), 'manage_options', 'options-permalink.php'); 
     232        $admin_menu->add_submenu( 'users', array( 
     233                'title' => _x('Add New', 'user'), 
     234                'cap' => array( 'create_users', 'promote_users' ), 
     235                'slug' => 'user-new.php', 
     236        ) ); 
     237} 
     238 
     239$admin_menu->append( array( 
     240        'title' => __('Tools'), 
     241        'cap' => 'edit_posts', 
     242        'slug' => 'tools.php', 
     243        'id' => 'tools', 
     244) ); 
     245 
     246        $admin_menu->add_first_submenu( 'tools', __('Available Tools') ); 
     247 
     248        $admin_menu->add_submenu( 'tools', array( 
     249                'title' => __('Import'), 
     250                'cap' => 'import', 
     251                'slug' => 'import.php', 
     252        ) ); 
     253 
     254        $admin_menu->add_submenu( 'tools', array( 
     255                'title' => __('Export'), 
     256                'cap' => 'export', 
     257                'slug' => 'export.php', 
     258        ) ); 
     259 
     260        if ( is_multisite() && !is_main_site() ) { 
     261                $admin_menu->add_submenu( 'tools', array( 
     262                        'title' => __('Delete Site'), 
     263                        'cap' => 'manage_options', 
     264                        'slug' => 'ms-delete-site.php', 
     265                ) ); 
     266        } 
    211267 
    212 $_wp_last_utility_menu = 80; // The index of the last top-level menu in the utility menu group 
     268        if ( ! is_multisite() && defined('WP_ALLOW_MULTISITE') && WP_ALLOW_MULTISITE ) { 
     269                $admin_menu->add_submenu( 'tools', array( 
     270                        'title' => __('Network Setup'), 
     271                        'cap' => 'manage_options', 
     272                        'slug' => 'network.php', 
     273                ) ); 
     274        } 
    213275 
    214 $menu[99] = array( '', 'read', 'separator-last', '', 'wp-menu-separator' ); 
     276$admin_menu->append( array( 
     277        'title' => __('Settings'), 
     278        'cap' => 'manage_options', 
     279        'slug' => 'options-general.php', 
     280        'id' => 'settings', 
     281) ); 
     282 
     283        $admin_menu->add_first_submenu( 'settings', _x('General', 'settings screen') ); 
     284 
     285        $admin_menu->add_submenu( 'settings', array( 
     286                'title' => __('Writing'), 
     287                'cap' => 'manage_options', 
     288                'slug' => 'options-writing.php', 
     289        ) ); 
     290 
     291        $admin_menu->add_submenu( 'settings', array( 
     292                'title' => __('Reading'), 
     293                'cap' => 'manage_options', 
     294                'slug' => 'options-reading.php', 
     295        ) ); 
     296 
     297        $admin_menu->add_submenu( 'settings', array( 
     298                'title' => __('Discussion'), 
     299                'cap' => 'manage_options', 
     300                'slug' => 'options-writing.php', 
     301        ) ); 
     302 
     303        $admin_menu->add_submenu( 'settings', array( 
     304                'title' => __('Media'), 
     305                'cap' => 'manage_options', 
     306                'slug' => 'options-media.php', 
     307        ) ); 
     308 
     309        $admin_menu->add_submenu( 'settings', array( 
     310                'title' => __('Privacy'), 
     311                'cap' => 'manage_options', 
     312                'slug' => 'options-privacy.php', 
     313        ) ); 
     314 
     315        $admin_menu->add_submenu( 'settings', array( 
     316                'title' => __('Permalinks'), 
     317                'cap' => 'manage_options', 
     318                'slug' => 'options-permalink.php', 
     319        ) ); 
     320 
     321$admin_menu->append( array( 
     322        'id' => 'separator-last', 
     323        'class' => 'wp-menu-separator', 
     324) ); 
     325 
     326// CPT menus need to be added later due to 'menu_position' 
     327$admin_menu->_add_post_type_menus(); 
     328add_action( 'admin_menu', array( $admin_menu, '_add_post_type_submenus' ), 9 ); 
    215329 
    216330// Back-compat for old top-levels 
    217331$_wp_real_parent_file['post.php'] = 'edit.php'; 
    $compat = array( 
    233347        'edit-comments' => 'comments', 
    234348        'options-general' => 'settings', 
    235349        'themes' => 'appearance', 
    236         ); 
     350); 
    237351 
    238352require_once(ABSPATH . 'wp-admin/includes/menu.php'); 
  • wp-admin/network/menu.php

    diff --git wp-admin/network/menu.php wp-admin/network/menu.php
    index a35a280..a6308bf 100644
     
    77 * @since 3.1.0 
    88 */ 
    99 
    10 /* translators: Network menu item */ 
    11 $menu[2] = array(__('Dashboard'), 'manage_network', 'index.php', '', 'menu-top menu-top-first menu-icon-dashboard', 'menu-dashboard', 'div'); 
     10$admin_menu = new WP_Admin_Menu; 
    1211 
    13 $menu[4] = array( '', 'read', 'separator1', '', 'wp-menu-separator' ); 
     12$admin_menu->append( array( 
     13        /* translators: Network menu item */ 
     14        'title' => __( 'Dashboard' ), 
     15        'cap' => 'manage_network', 
     16        'id' => 'dashboard', 
     17        'slug' => 'index.php', 
     18) ); 
    1419 
    15 /* translators: Sites menu item */ 
    16 $menu[5] = array(__('Sites'), 'manage_sites', 'sites.php', '', 'menu-top menu-icon-site', 'menu-site', 'div'); 
    17 $submenu['sites.php'][5]  = array( __('All Sites'), 'manage_sites', 'sites.php' ); 
    18 $submenu['sites.php'][10]  = array( _x('Add New', 'site'), 'create_sites', 'site-new.php' ); 
     20$admin_menu->append( array( 
     21        'id' => 'separator1', 
     22        'class' => 'wp-menu-separator', 
     23) ); 
    1924 
    20 $menu[10] = array(__('Users'), 'manage_network_users', 'users.php', '', 'menu-top menu-icon-users', 'menu-users', 'div'); 
    21 $submenu['users.php'][5]  = array( __('All Users'), 'manage_network_users', 'users.php' ); 
    22 $submenu['users.php'][10]  = array( _x('Add New', 'user'), 'create_users', 'user-new.php' ); 
     25$admin_menu->append( array( 
     26        /* translators: Sites menu item */ 
     27        'title' => __( 'Sites' ), 
     28        'cap' => 'manage_sites', 
     29        'id' => 'site', 
     30        'slug' => 'sites.php', 
     31) ); 
     32 
     33        $admin_menu->add_first_submenu( 'site', __( 'All Sites' ) ); 
     34 
     35        $admin_menu->add_submenu( 'site', array( 
     36                /* translators: add new site */ 
     37                'title' => _x( 'Add New', 'site' ), 
     38                'cap' => 'create_sites', 
     39                'slug' => 'site-new.php', 
     40        ) ); 
     41 
     42$admin_menu->append( array( 
     43        'title' => __( 'Users' ), 
     44        'cap' => 'manage_network_users', 
     45        'slug' => 'users.php', 
     46        'id' => 'users', 
     47) ); 
     48 
     49        $admin_menu->add_first_submenu( 'users', __( 'All Users') ); 
     50 
     51        $admin_menu->add_submenu( 'users', array( 
     52                'title' => _x( 'Add New', 'user' ), 
     53                'cap' => 'create_users', 
     54                'slug' => 'user-new.php', 
     55        ) ); 
    2356 
    2457$update_data = wp_get_update_data(); 
    2558 
    26 if ( $update_data['counts']['themes'] ) { 
    27         $menu[15] = array(sprintf( __( 'Themes %s' ), "<span class='update-plugins count-{$update_data['counts']['themes']}'><span class='theme-count'>" . number_format_i18n( $update_data['counts']['themes'] ) . "</span></span>" ), 'manage_network_themes', 'themes.php', '', 'menu-top menu-icon-appearance', 'menu-appearance', 'div' ); 
    28 } else { 
    29         $menu[15] = array( __( 'Themes' ), 'manage_network_themes', 'themes.php', '', 'menu-top menu-icon-appearance', 'menu-appearance', 'div' ); 
    30 } 
    31 $submenu['themes.php'][5]  = array( __('Installed Themes'), 'manage_network_themes', 'themes.php' ); 
    32 $submenu['themes.php'][10] = array( _x('Add New', 'theme'), 'install_themes', 'theme-install.php' ); 
    33 $submenu['themes.php'][15] = array( _x('Editor', 'theme editor'), 'edit_themes', 'theme-editor.php' ); 
    34  
    35 if ( current_user_can( 'update_plugins' ) ) { 
    36         $menu[20] = array( sprintf( __( 'Plugins %s' ), "<span class='update-plugins count-{$update_data['counts']['plugins']}'><span class='plugin-count'>" . number_format_i18n( $update_data['counts']['plugins'] ) . "</span></span>" ), 'manage_network_plugins', 'plugins.php', '', 'menu-top menu-icon-plugins', 'menu-plugins', 'div'); 
    37 } else { 
    38         $menu[20] = array( __('Plugins'), 'manage_network_plugins', 'plugins.php', '', 'menu-top menu-icon-plugins', 'menu-plugins', 'div' ); 
    39 } 
    40 $submenu['plugins.php'][5]  = array( __('Installed Plugins'), 'manage_network_plugins', 'plugins.php' ); 
    41 $submenu['plugins.php'][10] = array( _x('Add New', 'plugin editor'), 'install_plugins', 'plugin-install.php' ); 
    42 $submenu['plugins.php'][15] = array( _x('Editor', 'plugin editor'), 'edit_plugins', 'plugin-editor.php' ); 
    43  
    44 $menu[25] = array(__('Settings'), 'manage_network_options', 'settings.php', '', 'menu-top menu-icon-settings', 'menu-settings', 'div'); 
    45 if ( defined( 'MULTISITE' ) && defined( 'WP_ALLOW_MULTISITE' ) && WP_ALLOW_MULTISITE ) { 
    46         $submenu['settings.php'][5]  = array( __('Network Settings'), 'manage_network_options', 'settings.php' ); 
    47         $submenu['settings.php'][10] = array( __('Network Setup'), 'manage_network_options', 'setup.php' ); 
    48 } 
    49  
    50 if ( $update_data['counts']['total'] ) { 
    51         $menu[30] = array( sprintf( __( 'Updates %s' ), "<span class='update-plugins count-{$update_data['counts']['total']}' title='{$update_data['title']}'><span class='update-count'>" . number_format_i18n($update_data['counts']['total']) . "</span></span>" ), 'manage_network', 'upgrade.php', '', 'menu-top menu-icon-tools', 'menu-update', 'div' ); 
    52 } else { 
    53         $menu[30] = array( __( 'Updates' ), 'manage_network', 'upgrade.php', '', 'menu-top menu-icon-tools', 'menu-update', 'div' ); 
    54 } 
     59$admin_menu->append( array( 
     60        'title' => _admin_menu_theme_update_count( $update_data ), 
     61        'cap' => 'manage_network_themes', 
     62        'slug' => 'themes.php', 
     63        'id' => 'appearance', 
     64) ); 
    5565 
    56 unset($update_data); 
     66        $admin_menu->add_first_submenu( 'appearance', __( 'Installed Themes' ) ); 
     67 
     68        $admin_menu->add_submenu( 'appearance', array( 
     69                'title' => _x( 'Add New', 'theme' ), 
     70                'cap' => 'install_themes', 
     71                'slug' => 'theme-install.php', 
     72        ) ); 
     73 
     74        $admin_menu->add_submenu( 'appearance', array( 
     75                'title' => _x( 'Editor', 'theme editor' ), 
     76                'cap' => 'edit_themes', 
     77                'slug' => 'theme-editor.php', 
     78        ) ); 
     79 
     80$admin_menu->append( array( 
     81        'title' => _admin_menu_plugin_update_count( $update_data ), 
     82        'cap' => 'manage_network_plugins', 
     83        'slug' => 'plugins.php', 
     84        'id' => 'plugins', 
     85) ); 
     86 
     87        $admin_menu->add_first_submenu( 'plugins', __( 'Installed Plugins' ) ); 
    5788 
    58 $submenu[ 'upgrade.php' ][10] = array( __( 'Available Updates' ), 'update_core', 'update-core.php' ); 
    59 $submenu[ 'upgrade.php' ][15] = array( __( 'Update Network' ), 'manage_network', 'upgrade.php' ); 
     89        $admin_menu->add_submenu( 'plugins', array( 
     90                'title' => _x( 'Add New', 'plugin' ), 
     91                'cap' => 'install_plugins', 
     92                'slug' => 'plugin-install.php', 
     93        ) ); 
     94 
     95        $admin_menu->add_submenu( 'plugins', array( 
     96                'title' => _x( 'Editor', 'plugin editor' ), 
     97                'cap' => 'edit_plugins', 
     98                'slug' => 'plugin-editor.php', 
     99        ) ); 
     100 
     101$admin_menu->append( array( 
     102        'title' => __('Settings'), 
     103        'cap' => 'manage_network_options', 
     104        'slug' => 'settings.php', 
     105        'id' => 'settings', 
     106) ); 
     107 
     108        $admin_menu->add_first_submenu( 'settings', __('Network Settings') ); 
     109 
     110        $admin_menu->add_submenu( 'settings', array( 
     111                'title' => __('Writing'), 
     112                'cap' => 'manage_network_options', 
     113                'slug' => 'setup.php', 
     114        ) ); 
     115 
     116$admin_menu->append( array( 
     117        'title' => _admin_menu_update_count( $update_data ), 
     118        'cap' => 'manage_network', 
     119        'slug' => 'upgrade.php', 
     120        'class' => 'menu-icon-tools', 
     121        'id' => 'update', 
     122) ); 
     123 
     124        $admin_menu->add_first_submenu( 'update', __('Update Network') ); 
     125 
     126        $admin_menu->add_submenu( 'update', array( 
     127                'title' => __('Available Updates'), 
     128                'cap' => 'update_core', 
     129                'slug' => 'update-core.php', 
     130        ) ); 
     131 
     132unset($update_data); 
    60133 
    61 $menu[99] = array( '', 'read', 'separator-last', '', 'wp-menu-separator-last' ); 
     134$admin_menu->append( array( 
     135        'id' => 'separator-last', 
     136        'class' => 'wp-menu-separator', 
     137) ); 
    62138 
    63139require_once(ABSPATH . 'wp-admin/includes/menu.php'); 
  • wp-admin/themes.php

    diff --git wp-admin/themes.php wp-admin/themes.php
    index 5a78fe3..57682df 100644
    $customize_title = sprintf( __( 'Customize &#8220;%s&#8221;' ), $ct->display('Na 
    150150                <?php theme_update_available( $ct ); ?> 
    151151        </div> 
    152152 
    153         <?php 
    154         // Pretend you didn't see this. 
     153<?php 
    155154        $options = array(); 
    156         if ( is_array( $submenu ) && isset( $submenu['themes.php'] ) ) { 
    157                 foreach ( (array) $submenu['themes.php'] as $item) { 
    158                         $class = ''; 
    159                         if ( 'themes.php' == $item[2] || 'theme-editor.php' == $item[2] ) 
    160                                 continue; 
    161                         // 0 = name, 1 = capability, 2 = file 
    162                         if ( ( strcmp($self, $item[2]) == 0 && empty($parent_file)) || ($parent_file && ($item[2] == $parent_file)) ) 
    163                                 $class = ' class="current"'; 
    164                         if ( !empty($submenu[$item[2]]) ) { 
    165                                 $submenu[$item[2]] = array_values($submenu[$item[2]]); // Re-index. 
    166                                 $menu_hook = get_plugin_page_hook($submenu[$item[2]][0][2], $item[2]); 
    167                                 if ( file_exists(WP_PLUGIN_DIR . "/{$submenu[$item[2]][0][2]}") || !empty($menu_hook)) 
    168                                         $options[] = "<a href='admin.php?page={$submenu[$item[2]][0][2]}'$class>{$item[0]}</a>"; 
    169                                 else 
    170                                         $options[] = "<a href='{$submenu[$item[2]][0][2]}'$class>{$item[0]}</a>"; 
    171                         } else if ( current_user_can($item[1]) ) { 
    172                                 if ( file_exists(ABSPATH . 'wp-admin/' . $item[2]) ) { 
    173                                         $options[] = "<a href='{$item[2]}'$class>{$item[0]}</a>"; 
    174                                 } else { 
    175                                         $options[] = "<a href='themes.php?page={$item[2]}'$class>{$item[0]}</a>"; 
    176                                 } 
    177                         } 
     155        $parent_menu = $admin_menu->get( 'appearance' ); 
     156        foreach ( $parent_menu->get_children() as $item ) { 
     157                if ( 'themes.php' == $item->slug || 'theme-editor.php' == $item->slug ) 
     158                        continue; 
     159 
     160                if ( !current_user_can( $item->cap ) ) 
     161                        continue; 
     162 
     163                $class = ''; 
     164                if ( ( $self == $item->slug && empty($parent_file) ) || 
     165                         ( $parent_file && ($item->slug == $parent_file) ) ) 
     166                        $class = ' class="current"'; 
     167 
     168                if ( file_exists( ABSPATH . 'wp-admin/' . $item->slug ) ) { 
     169                        $url = $item->slug; 
     170                } else { 
     171                        $url = 'themes.php?page=' . $item->slug; 
    178172                } 
     173 
     174                $options[] = "<a href='$url'$class>{$item->title}</a>"; 
    179175        } 
    180176 
    181177        if ( $options || current_user_can( 'edit_theme_options' ) ) : 
    182         ?> 
     178?> 
    183179        <div class="theme-options"> 
    184180                <?php if ( current_user_can( 'edit_theme_options' ) ) : ?> 
    185181                <a id="customize-current-theme-link" href="<?php echo wp_customize_url(); ?>" class="load-customize hide-if-no-customize" title="<?php echo esc_attr( $customize_title ); ?>"><?php _e( 'Customize' ); ?></a> 
  • wp-admin/user/menu.php

    diff --git wp-admin/user/menu.php wp-admin/user/menu.php
    index 9f30076..2a8cf99 100644
     
    77 * @since 3.1.0 
    88 */ 
    99 
    10 $menu[2] = array(__('Dashboard'), 'exist', 'index.php', '', 'menu-top menu-top-first menu-icon-dashboard', 'menu-dashboard', 'div'); 
     10$admin_menu = new WP_Admin_Menu; 
    1111 
    12 $menu[4] = array( '', 'exist', 'separator1', '', 'wp-menu-separator' ); 
     12$admin_menu->append( array( 
     13        'title' => __( 'Dashboard' ), 
     14        'cap' => 'exist', 
     15        'id' => 'dashboard', 
     16        'slug' => 'index.php', 
     17) ); 
    1318 
    14 $menu[70] = array( __('Profile'), 'exist', 'profile.php', '', 'menu-top menu-icon-users', 'menu-users', 'div' ); 
     19$admin_menu->append( array( 
     20        'id' => 'separator1', 
     21        'class' => 'wp-menu-separator', 
     22) ); 
    1523 
    16 $menu[99] = array( '', 'exist', 'separator-last', '', 'wp-menu-separator-last' ); 
     24$admin_menu->append( array( 
     25        'title' => __( 'Profile' ), 
     26        'cap' => 'exist', 
     27        'id' => 'users', 
     28        'slug' => 'profile.php', 
     29) ); 
     30 
     31$admin_menu->append( array( 
     32        'id' => 'separator-last', 
     33        'class' => 'wp-menu-separator', 
     34) ); 
    1735 
    1836$_wp_real_parent_file['users.php'] = 'profile.php'; 
    1937$compat = array(); 
    20 $submenu = array(); 
    2138 
    2239require_once(ABSPATH . 'wp-admin/includes/menu.php'); 
  • wp-includes/class-wp-xmlrpc-server.php

    diff --git wp-includes/class-wp-xmlrpc-server.php wp-includes/class-wp-xmlrpc-server.php
    index b65e4fb..6932709 100644
    class wp_xmlrpc_server extends IXR_Server { 
    709709                } 
    710710 
    711711                if ( in_array( 'menu', $fields ) ) { 
    712                         $_post_type['menu_position'] = (int) $post_type->menu_position; 
     712                        $_post_type['menu_position'] = $post_type->menu_position; 
    713713                        $_post_type['menu_icon'] = $post_type->menu_icon; 
    714714                        $_post_type['show_in_menu'] = (bool) $post_type->show_in_menu; 
    715715                } 
  • wp-includes/functions.php

    diff --git wp-includes/functions.php wp-includes/functions.php
    index 2f0b6f0..0fcbba8 100644
    function wp_maybe_load_widgets() { 
    24562456 * Append the Widgets menu to the themes main menu. 
    24572457 * 
    24582458 * @since 2.2.0 
    2459  * @uses $submenu The administration submenu list. 
     2459 * @uses $admin_menu The administration menu object. 
    24602460 */ 
    24612461function wp_widgets_add_menu() { 
    2462         global $submenu; 
    2463         $submenu['themes.php'][7] = array( __( 'Widgets' ), 'edit_theme_options', 'widgets.php' ); 
    2464         ksort( $submenu['themes.php'], SORT_NUMERIC ); 
     2462        global $admin_menu; 
     2463 
     2464        $parent = $admin_menu->get( 'appearance' ); 
     2465 
     2466        $parent->insert_after( 'themes.php', array( 
     2467                'title' => __( 'Widgets' ), 
     2468                'cap' => 'edit_theme_options', 
     2469                'slug' => 'widgets.php' 
     2470        ) ); 
    24652471} 
    24662472 
    24672473/** 
  • wp-includes/post.php

    diff --git wp-includes/post.php wp-includes/post.php
    index b22abf6..e09bb1c 100644
    function get_post_types( $args = array(), $output = 'names', $operator = 'and' ) 
    918918 *     * If not set, the default is inherited from show_ui 
    919919 * - show_in_admin_bar - Makes this post type available via the admin bar. 
    920920 *     * If not set, the default is inherited from show_in_menu 
    921  * - menu_position - The position in the menu order the post type should appear. 
    922921 *     * show_in_menu must be true 
    923922 *     * Defaults to null, which places it at the bottom of its area. 
     923 * - menu_position - The id of the admin menu; this menu will show up above it. 
    924924 * - menu_icon - The url to the icon to be used for this menu. Defaults to use the posts icon. 
    925925 * - capability_type - The string to use to build the read, edit, and delete capabilities. Defaults to 'post'. 
    926926 *     * May be passed as an array to allow for alternative plurals when using this argument as a base to construct the 
    function register_post_type( $post_type, $args = array() ) { 
    980980                '_builtin' => false, '_edit_link' => 'post.php?post=%d', 'hierarchical' => false, 
    981981                'public' => false, 'rewrite' => true, 'has_archive' => false, 'query_var' => true, 
    982982                'supports' => array(), 'register_meta_box_cb' => null, 
    983                 'taxonomies' => array(), 'show_ui' => null, 'menu_position' => null, 'menu_icon' => null, 
     983                'taxonomies' => array(), 
     984                'show_ui' => null, 'show_in_menu' => null, 'menu_position' => null, 'menu_icon' => null, 
    984985                'can_export' => true, 
    985                 'show_in_nav_menus' => null, 'show_in_menu' => null, 'show_in_admin_bar' => null, 
     986                'show_in_nav_menus' => null, 'show_in_admin_bar' => null, 
    986987                'delete_with_user' => null, 
    987988        ); 
    988989        $args = wp_parse_args($args, $defaults); 
    function register_post_type( $post_type, $args = array() ) { 
    10061007        if ( null === $args->show_in_menu || ! $args->show_ui ) 
    10071008                $args->show_in_menu = $args->show_ui; 
    10081009 
     1010        if ( is_numeric( $args->menu_position ) ) { 
     1011                _deprecated_argument( __FUNCTION__, '3.5', __( "Numeric values for 'menu_position' are deprecated. Use menu ids instead." ) ); 
     1012                $args->menu_position = null; 
     1013        } 
     1014 
    10091015        // If not set, default to the whether the full UI is shown. 
    10101016        if ( null === $args->show_in_admin_bar ) 
    10111017                $args->show_in_admin_bar = true === $args->show_in_menu; 
    function _get_custom_object_labels( $object, $nohier_vs_hier_defaults ) { 
    12931299} 
    12941300 
    12951301/** 
    1296  * Adds submenus for post types. 
    1297  * 
    1298  * @access private 
    1299  * @since 3.1.0 
    1300  */ 
    1301 function _add_post_type_submenus() { 
    1302         foreach ( get_post_types( array( 'show_ui' => true ) ) as $ptype ) { 
    1303                 $ptype_obj = get_post_type_object( $ptype ); 
    1304                 // Submenus only. 
    1305                 if ( ! $ptype_obj->show_in_menu || $ptype_obj->show_in_menu === true ) 
    1306                         continue; 
    1307                 add_submenu_page( $ptype_obj->show_in_menu, $ptype_obj->labels->name, $ptype_obj->labels->all_items, $ptype_obj->cap->edit_posts, "edit.php?post_type=$ptype" ); 
    1308         } 
    1309 } 
    1310 add_action( 'admin_menu', '_add_post_type_submenus' ); 
    1311  
    1312 /** 
    13131302 * Register support of certain features for a post type. 
    13141303 * 
    13151304 * All features are directly associated with a functional area of the edit screen, such as the