WordPress.org

Make WordPress Core

Ticket #12718: 12718.diff

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

    diff --git wp-admin/includes/menu.php wp-admin/includes/menu.php
    index 14cadfa..20861d8 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); 
     138unset($separator_found, $menu_item); 
    139139 
    140140function add_cssclass($add, $class) { 
    141141        $class = empty($class) ? $add : $class .= ' ' . $add; 
    142142        return $class; 
    143143} 
    144144 
    145 function add_menu_classes($menu) { 
     145function _add_admin_menu_classes( $admin_menu ) { 
     146        $items = array_values( $admin_menu->get_children() ); 
    146147 
    147         $first = $lastorder = false; 
    148         $i = 0; 
    149         $mc = count($menu); 
    150         foreach ( $menu as $order => $top ) { 
    151                 $i++; 
     148        // Remove the last menu item if it is a separator. 
     149        $last = end( $items ); 
     150        if ( 'wp-menu-separator' == $last->class ) { 
     151                $admin_menu->remove( $last->id ); 
     152                array_pop( $items ); 
     153        } 
    152154 
    153                 if ( 0 == $order ) { // dashboard is always shown/single 
    154                         $menu[0][4] = add_cssclass('menu-top-first', $top[4]); 
    155                         $lastorder = 0; 
     155        $first = false; 
     156 
     157        foreach ( $items as $i => $menu_item ) { 
     158                if ( 'dashboard' == $menu_item->id ) { // dashboard is always shown/single 
     159                        $menu_item->class = add_cssclass( 'menu-top-first', $menu_item->class ); 
    156160                        continue; 
    157161                } 
    158162 
    159                 if ( 0 === strpos($top[2], 'separator') ) { // if separator 
     163                if ( 'wp-menu-separator' == $menu_item->class ) { 
    160164                        $first = true; 
    161                         $c = $menu[$lastorder][4]; 
    162                         $menu[$lastorder][4] = add_cssclass('menu-top-last', $c); 
     165                        $previous = $items[$i-1]; 
     166                        $previous->class = add_cssclass( 'menu-top-last', $previous->class ); 
    163167                        continue; 
    164168                } 
    165169 
    166170                if ( $first ) { 
    167                         $c = $menu[$order][4]; 
    168                         $menu[$order][4] = add_cssclass('menu-top-first', $c); 
     171                        $menu_item->class = add_cssclass( 'menu-top-first', $menu_item->class ); 
    169172                        $first = false; 
    170173                } 
    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; 
    178174        } 
    179175 
    180         return apply_filters( 'add_menu_classes', $menu ); 
    181 } 
    182  
    183 uksort($menu, "strnatcasecmp"); // make it all pretty 
     176        $last = end( $items ); 
    184177 
    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); 
     178        $last->class = add_cssclass( 'menu-top-last', $last->class ); 
    215179} 
    216180 
    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 ); 
    223  
    224181if ( !user_can_access_admin_page() ) { 
    225182        do_action('admin_page_access_denied'); 
    226183        wp_die( __('You do not have sufficient permissions to access this page.') ); 
    227184} 
    228185 
    229 $menu = add_menu_classes($menu); 
     186_add_admin_menu_classes( $admin_menu ); 
     187 
  • wp-admin/includes/plugin.php

    diff --git wp-admin/includes/plugin.php wp-admin/includes/plugin.php
    index 083b5c4..a558bff 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 017f676..cd96110 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 
    26114/** 
    27115 * Display menu. 
    28116 * 
    get_admin_page_parent(); 
    33121 * @param array $submenu 
    34122 * @param bool $submenu_as_parent 
    35123 */ 
    36 function _wp_menu_output( $menu, $submenu, $submenu_as_parent = true ) { 
    37         global $self, $parent_file, $submenu_file, $plugin_page, $pagenow, $typenow; 
    38  
     124function _wp_menu_output( $menu, $submenu_as_parent = true ) { 
    39125        $first = true; 
    40         // 0 = name, 1 = capability, 2 = file, 3 = class, 4 = id, 5 = icon src 
    41         foreach ( $menu as $key => $item ) { 
     126        foreach ( $menu->get_children() as $item ) { 
     127 
     128                if ( 'wp-menu-separator' == $item->class ) { 
     129                        echo "\n\t<li class='wp-menu-separator' id='menu-$item->id'>"; 
     130                        echo '<div class="separator"></div>'; 
     131                        echo "</li>"; 
     132                        continue; 
     133                } 
     134 
    42135                $admin_is_parent = false; 
    43                 $class = array(); 
     136 
    44137                $aria_attributes = 'tabindex="1"'; 
    45138 
     139                $class = array(); 
     140 
    46141                if ( $first ) { 
    47142                        $class[] = 'wp-first-item'; 
    48143                        $first = false; 
    49144                } 
    50145 
    51                 $submenu_items = false; 
    52                 if ( ! empty( $submenu[$item[2]] ) ) { 
     146                $submenu_items = $item->get_children(); 
     147 
     148                if ( ! empty( $submenu_items ) ) { 
    53149                        $class[] = 'wp-has-submenu'; 
    54                         $submenu_items = $submenu[$item[2]]; 
    55150                } 
    56151 
    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'; 
     152                if ( _admin_menu_is_current( $item ) ) { 
     153                        if ( ! empty( $submenu_items ) ) 
     154                                $class[] = 'wp-has-current-submenu wp-menu-open'; 
     155                        else 
     156                                $class[] = 'current'; 
    59157                } else { 
    60158                        $class[] = 'wp-not-current-submenu'; 
    61159                        if ( ! empty( $submenu_items ) ) 
    62160                                $aria_attributes .= ' aria-haspopup="true"'; 
    63161                } 
    64162 
    65                 if ( ! empty( $item[4] ) ) 
    66                         $class[] = $item[4]; 
     163                if ( ! empty( $item->class ) ) 
     164                        $class[] = $item->class; 
     165 
     166                $class[] = 'menu-top'; 
    67167 
    68168                $class = $class ? ' class="' . join( ' ', $class ) . '"' : ''; 
    69                 $id = ! empty( $item[5] ) ? ' id="' . preg_replace( '|[^a-zA-Z0-9_:.]|', '-', $item[5] ) . '"' : ''; 
     169 
     170                $id = ! empty( $item->id ) ? ' id="menu-' . preg_replace( '|[^a-zA-Z0-9_:.]|', '-', $item->id ) . '"' : ''; 
     171 
    70172                $img = ''; 
    71                 if ( ! empty( $item[6] ) ) 
    72                         $img = ( 'div' === $item[6] ) ? '<br />' : '<img src="' . $item[6] . '" alt="" />'; 
     173                if ( ! empty( $item->icon ) ) 
     174                        $img = ( 'div' === $item->icon ) ? '<br />' : '<img src="' . $item->icon . '" alt="" />'; 
     175 
    73176                $arrow = '<div class="wp-menu-arrow"><div></div></div>'; 
    74177 
    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 
     178                $title = wptexturize( $item->title ); 
     179 
     180                $aria_label = esc_attr( strip_tags( $item->title ) ); // strip the comment/plugins/updates bubbles spans but keep the pending number if any 
    77181 
    78182                echo "\n\t<li$class$id>"; 
    79183 
    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]}' 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]}' 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]}' 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]}' aria-label='$aria_label'>$img</a></div>$arrow<a href='{$item[2]}'$class $aria_attributes>{$item[0]}</a>"; 
    104                         } 
     184                $url = false; 
     185                if ( $submenu_as_parent && ! empty( $submenu_items ) ) { 
     186                        $first_submenu = reset( $submenu_items ); 
     187 
     188                        $menu_hook = get_plugin_page_hook( $first_submenu->slug, $item->slug ); 
     189                        $url = _admin_menu_get_url( $menu_hook, $first_submenu, $admin_is_parent ); 
     190                } 
     191                elseif ( ! empty( $item->slug ) && current_user_can( $item->cap ) ) { 
     192                        $menu_hook = get_plugin_page_hook( $item->slug, 'admin.php' ); 
     193                        $url = _admin_menu_get_url( $menu_hook, $item, $admin_is_parent ); 
     194                } 
     195 
     196                if ( $url ) { 
     197                        echo "<div class='wp-menu-image'><a href='$url' aria-label='$aria_label'>$img</a></div>"; 
     198                        echo $arrow; 
     199                        echo "<a href='$url'$class $aria_attributes>$title</a>"; 
    105200                } 
    106201 
    107202                if ( ! empty( $submenu_items ) ) { 
    108203                        echo "\n\t<div class='wp-submenu'><div class='wp-submenu-wrap'>"; 
    109                         echo "<div class='wp-submenu-head'>{$item[0]}</div><ul>"; 
     204                        echo "<div class='wp-submenu-head'>{$item->title}</div><ul>"; 
    110205                        $first = true; 
    111                         foreach ( $submenu_items as $sub_key => $sub_item ) { 
    112                                 if ( ! current_user_can( $sub_item[1] ) ) 
     206                        foreach ( $submenu_items as $sub_item ) { 
     207                                if ( ! current_user_can( $sub_item->cap ) ) 
    113208                                        continue; 
    114209 
    115210                                $aria_attributes = 'tabindex="1"'; 
     211 
    116212                                $class = array(); 
     213 
    117214                                if ( $first ) { 
    118215                                        $class[] = 'wp-first-item'; 
    119216                                        $first = false; 
    120217                                } 
    121218 
    122                                 $menu_file = $item[2]; 
    123  
    124                                 if ( false !== ( $pos = strpos( $menu_file, '?' ) ) ) 
    125                                         $menu_file = substr( $menu_file, 0, $pos ); 
    126  
    127                                 // Handle current for post_type=post|page|foo pages, which won't match $self. 
    128                                 $self_type = ! empty( $typenow ) ? $self . '?post_type=' . $typenow : 'nothing'; 
    129  
    130                                 if ( isset( $submenu_file ) ) { 
    131                                         if ( $submenu_file == $sub_item[2] ) 
    132                                                 $class[] = 'current'; 
    133                                 // If plugin_page is set the parent must either match the current page or not physically exist. 
    134                                 // This allows plugin pages with the same hook to exist under different parents. 
    135                                 } else if ( 
    136                                         ( ! isset( $plugin_page ) && $self == $sub_item[2] ) || 
    137                                         ( isset( $plugin_page ) && $plugin_page == $sub_item[2] && ( $item[2] == $self_type || $item[2] == $self || file_exists($menu_file) === false ) ) 
    138                                 ) { 
     219                                if ( _admin_submenu_is_current( $sub_item, $item ) ) { 
    139220                                        $class[] = 'current'; 
    140221                                } 
    141222 
    142223                                $class = $class ? ' class="' . join( ' ', $class ) . '"' : ''; 
    143224 
    144                                 $menu_hook = get_plugin_page_hook($sub_item[2], $item[2]); 
    145                                 $sub_file = $sub_item[2]; 
    146                                 if ( false !== ( $pos = strpos( $sub_file, '?' ) ) ) 
    147                                         $sub_file = substr($sub_file, 0, $pos); 
    148  
    149                                 $title = wptexturize($sub_item[0]); 
     225                                $title = wptexturize( $sub_item->title ); 
    150226 
    151                                 if ( ! empty( $menu_hook ) || ( ('index.php' != $sub_item[2]) && file_exists( WP_PLUGIN_DIR . "/$sub_file" ) ) ) { 
    152                                         // If admin.php is the current page or if the parent exists as a file in the plugins or admin dir 
    153                                         if ( (!$admin_is_parent && file_exists(WP_PLUGIN_DIR . "/$menu_file") && !is_dir(WP_PLUGIN_DIR . "/{$item[2]}")) || file_exists($menu_file) ) 
    154                                                 $sub_item_url = add_query_arg( array('page' => $sub_item[2]), $item[2] ); 
    155                                         else 
    156                                                 $sub_item_url = add_query_arg( array('page' => $sub_item[2]), 'admin.php' ); 
     227                                $sub_item_url = _admin_submenu_get_url( $sub_item, $item, $admin_is_parent ); 
     228                                $sub_item_url = esc_url( $sub_item_url ); 
    157229 
    158                                         $sub_item_url = esc_url( $sub_item_url ); 
    159                                         echo "<li$class><a href='$sub_item_url'$class $aria_attributes>$title</a></li>"; 
    160                                 } else { 
    161                                         echo "<li$class><a href='{$sub_item[2]}'$class $aria_attributes>$title</a></li>"; 
    162                                 } 
     230                                echo "<li$class><a href='{$sub_item_url}'$class $aria_attributes>$title</a></li>"; 
    163231                        } 
    164232                        echo "</ul></div></div>"; 
    165233                } 
    function _wp_menu_output( $menu, $submenu, $submenu_as_parent = true ) { 
    170238        echo '<span>' . esc_html__( 'Collapse menu' ) . '</span>'; 
    171239        echo '</li>'; 
    172240} 
    173  
    174241?> 
    175242 
    176243<div id="adminmenuback"></div> 
    177244<div id="adminmenuwrap"> 
    178 <div id="adminmenushadow"></div> 
    179 <ul id="adminmenu" role="navigation"> 
     245        <div id="adminmenushadow"></div> 
    180246 
     247        <ul id="adminmenu" role="navigation"> 
    181248<?php 
    182  
    183 _wp_menu_output( $menu, $submenu ); 
    184 do_action( 'adminmenu' ); 
    185  
     249        _wp_menu_output( $admin_menu ); 
     250        do_action( 'adminmenu' ); 
    186251?> 
    187 </ul> 
     252        </ul> 
    188253</div> 
  • wp-admin/menu.php

    diff --git wp-admin/menu.php wp-admin/menu.php
    index bf914e5..4d94331 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        '_index' => 2 
     17) ); 
    2618 
    27 $submenu[ 'index.php' ][0] = array( __('Home'), 'read', 'index.php' ); 
     19        $admin_menu->add_first_submenu( 'dashboard', __( 'Home' ), 0 ); 
    2820 
    2921if ( is_multisite() ) { 
    30         $submenu[ 'index.php' ][5] = array( __('My Sites'), 'read', 'my-sites.php' ); 
     22        $admin_menu->add_submenu( 'dashboard', array( 
     23                'title' => __( 'My Sites' ), 
     24                'cap' => 'read', 
     25                'slug' => 'my-sites.php', 
     26                '_index' => 5 
     27        ) ); 
    3128} 
    3229 
    3330if ( ! is_multisite() || is_super_admin() ) 
    3431        $update_data = wp_get_update_data(); 
    3532 
    3633if ( ! 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 ); 
     34        $admin_menu->add_submenu( 'dashboard', array( 
     35                'title' => _admin_menu_update_count( $update_data ), 
     36                'cap' => array( 'update_core', 'update_plugins', 'update_themes' ), 
     37                'slug' => 'update-core.php', 
     38                '_index' => 10 
     39        ) ); 
    4540} 
    4641 
    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' ); 
     42$admin_menu->append( array( 
     43        'id' => 'separator1', 
     44        'class' => 'wp-menu-separator', 
     45        '_index' => 4 
     46) ); 
     47 
     48$admin_menu->append( array( 
     49        'title' => __( 'Posts' ), 
     50        'cap' => 'edit_posts', 
     51        'class' => 'open-if-no-js menu-icon-post', 
     52        'id' => 'posts', 
     53        'slug' => 'edit.php', 
     54        '_index' => 5 
     55) ); 
     56 
     57        $admin_menu->add_first_submenu( 'posts', __( 'All Posts' ) ); 
     58 
     59        $admin_menu->add_submenu( 'posts', array( 
     60                /* translators: add new post */ 
     61                'title' => _x( 'Add New', 'post' ), 
     62                'cap' => 'edit_posts', 
     63                'slug' => 'post-new.php', 
     64                '_index' => 10 
     65        ) ); 
     66 
     67        $admin_menu->_add_tax_submenus( 'posts', 'post' ); 
     68 
     69$admin_menu->append( array( 
     70        'title' => __( 'Media' ), 
     71        'cap' => 'upload_files', 
     72        'id' => 'media', 
     73        'slug' => 'upload.php', 
     74        '_index' => 10 
     75) ); 
     76 
     77        $admin_menu->add_first_submenu( 'media', __( 'Library' ) ); 
     78 
     79        $admin_menu->add_submenu( 'media', array( 
     80                /* translators: add new file */ 
     81                'title' => _x( 'Add New', 'file' ), 
     82                'cap' => 'upload_files', 
     83                'slug' => 'media-new.php', 
     84                '_index' => 10 
     85        ) ); 
     86 
     87$admin_menu->append( array( 
     88        'title' => __( 'Links' ), 
     89        'cap' => 'manage_links', 
     90        'id' => 'links', 
     91        'slug' => 'link-manager.php', 
     92        '_index' => 15 
     93) ); 
     94 
     95        $admin_menu->add_first_submenu( 'links', __( 'All Links' ) ); 
     96 
     97        $admin_menu->add_submenu( 'links', array( 
     98                /* translators: add new link */ 
     99                'title' => _x( 'Add New', 'link' ), 
     100                'cap' => 'manage_links', 
     101                'slug' => 'link-add.php', 
     102                '_index' => 10 
     103        ) ); 
     104 
     105        $admin_menu->add_submenu( 'links', array( 
     106                'title' => __( 'Link Categories' ), 
     107                'cap' => 'manage_categories', 
     108                'slug' => 'edit-tags.php?taxonomy=link_category', 
     109                '_index' => 15 
     110        ) ); 
     111 
     112$admin_menu->append( array( 
     113        'title' => __( 'Pages' ), 
     114        'cap' => 'edit_pages', 
     115        'class' => 'menu-icon-page', 
     116        'id' => 'pages', 
     117        'slug' => 'edit.php?post_type=page', 
     118        '_index' => 20 
     119) ); 
     120 
     121        $admin_menu->add_first_submenu( 'pages', __( 'All Pages' ) ); 
     122 
     123        $admin_menu->add_submenu( 'pages', array( 
     124                /* translators: add new link */ 
     125                'title' => _x( 'Add New', 'page' ), 
     126                'cap' => 'edit_pages', 
     127                'slug' => 'post-new.php?post_type=page', 
     128                '_index' => 10 
     129        ) ); 
     130 
     131        $admin_menu->_add_tax_submenus( 'pages', 'page' ); 
     132 
     133$admin_menu->append( array( 
     134        'title' => _admin_menu_comment_count( wp_count_comments()->moderated ), 
     135        'cap' => 'edit_posts', 
     136        'id' => 'comments', 
     137        'slug' => 'edit-comments.php', 
     138        '_index' => 25 
     139) ); 
     140 
     141        $admin_menu->add_first_submenu( 'comments', __( 'All Comments' ), 0 ); 
     142 
     143$admin_menu->append( array( 
     144        'id' => 'separator2', 
     145        'class' => 'wp-menu-separator', 
     146        '_index' => 59 
     147) ); 
     148 
     149$admin_menu->append( array( 
     150        'title' => __('Appearance'), 
     151        'cap' => array( 'switch_themes', 'edit_theme_options' ), 
     152        'slug' => 'themes.php', 
     153        'id' => 'appearance', 
     154        '_index' => 60 
     155) ); 
     156 
     157        $admin_menu->add_first_submenu( 'appearance', __( 'Themes') ); 
     158 
     159        if ( current_theme_supports( 'menus' ) || current_theme_supports( 'widgets' ) ) { 
     160                $admin_menu->add_submenu( 'appearance', array( 
     161                        'title' => __('Menus'), 
     162                        'cap' => array( 'switch_themes', 'edit_theme_options' ), 
     163                        'slug' => 'nav-menus.php', 
     164                        '_index' => 10 
     165                ) ); 
    84166        } 
    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'; 
    109         } 
    110  
    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; 
    124167 
    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" ); 
     168        if ( ! is_multisite() ) { 
     169                $admin_menu->add_submenu( 'appearance', array( 
     170                        'title' => _x('Editor', 'theme editor'), 
     171                        'cap' => 'edit_themes', 
     172                        'slug' => 'theme-editor.php', 
     173                        '_index' => 15 
     174                ) ); 
    126175        } 
    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' ); 
    131  
    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 } 
    151176 
    152 $count = ''; 
    153177if ( ! is_multisite() && current_user_can( 'update_plugins' ) ) { 
     178 
    154179        if ( ! isset( $update_data ) ) 
    155180                $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>"; 
     181 
     182        $plugin_title = _admin_menu_plugin_update_count( $update_data ); 
     183} else { 
     184        $plugin_title = __( 'Plugins' ); 
    157185} 
    158186 
    159 $menu[65] = array( sprintf( __('Plugins %s'), $count ), 'activate_plugins', 'plugins.php', '', 'menu-top menu-icon-plugins', 'menu-plugins', 'div' ); 
     187$admin_menu->append( array( 
     188        'title' => $plugin_title, 
     189        'cap' => 'activate_plugins', 
     190        'slug' => 'plugins.php', 
     191        'id' => 'plugins', 
     192        '_index' => 65 
     193) ); 
    160194 
    161 $submenu['plugins.php'][5]  = array( __('Installed Plugins'), 'activate_plugins', 'plugins.php' ); 
     195        $admin_menu->add_first_submenu( 'plugins', __( 'Installed Plugins') ); 
    162196 
    163197        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' ); 
     198                $admin_menu->add_submenu( 'plugins', array( 
     199                        /* translators: add new plugin */ 
     200                        'title' => _x('Add New', 'plugin'), 
     201                        'cap' => 'install_plugins', 
     202                        'slug' => 'plugin-install.php', 
     203                        '_index' => 10 
     204                ) ); 
     205 
     206                $admin_menu->add_submenu( 'plugins', array( 
     207                        'title' => _x('Editor', 'plugin editor'), 
     208                        'cap' => 'edit_plugins', 
     209                        'slug' => 'plugin-editor.php', 
     210                        '_index' => 15 
     211                ) ); 
    167212        } 
    168213 
    169 unset( $update_data ); 
     214unset( $update_data, $plugin_title ); 
    170215 
    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' ); 
     216if ( current_user_can('list_users') ) { 
     217        $admin_menu->append( array( 
     218                'title' => __('Users'), 
     219                'cap' => 'list_users', 
     220                'slug' => 'users.php', 
     221                'id' => 'users', 
     222                '_index' => 70 
     223        ) ); 
     224} else { 
     225        $admin_menu->append( array( 
     226                'title' => __('Profile'), 
     227                'cap' => 'read', 
     228                'slug' => 'profile.php', 
     229                'id' => 'users', 
     230                '_index' => 70 
     231        ) ); 
     232} 
    175233 
    176234if ( current_user_can('list_users') ) { 
    177235        $_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'); 
    183236 
    184         $submenu['users.php'][15] = array(__('Your Profile'), 'read', 'profile.php'); 
     237        $admin_menu->add_first_submenu( 'users', __( 'All Users') ); 
     238 
     239        $admin_menu->add_submenu( 'users', array( 
     240                'title' => _x('Add New', 'user'), 
     241                'cap' => array( 'create_users', 'promote_users' ), 
     242                'slug' => 'user-new.php', 
     243                '_index' => 10 
     244        ) ); 
     245 
     246        $admin_menu->add_submenu( 'users', array( 
     247                'title' => __('Your Profile'), 
     248                'cap' => 'read', 
     249                'slug' => 'profile.php', 
     250                '_index' => 15 
     251        ) ); 
    185252} else { 
    186253        $_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'); 
     254 
     255        $admin_menu->add_first_submenu( 'users', __( 'Your Profile') ); 
     256 
     257        $admin_menu->add_submenu( 'users', array( 
     258                'title' => _x('Add New', 'user'), 
     259                'cap' => array( 'create_users', 'promote_users' ), 
     260                'slug' => 'user-new.php', 
     261                '_index' => 10 
     262        ) ); 
    192263} 
    193264 
    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'); 
    202  
    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'); 
    211  
    212 $_wp_last_utility_menu = 80; // The index of the last top-level menu in the utility menu group 
    213  
    214 $menu[99] = array( '', 'read', 'separator-last', '', 'wp-menu-separator' ); 
     265$admin_menu->append( array( 
     266        'title' => __('Tools'), 
     267        'cap' => 'edit_posts', 
     268        'slug' => 'tools.php', 
     269        'id' => 'tools', 
     270        '_index' => 75 
     271) ); 
     272 
     273        $admin_menu->add_first_submenu( 'tools', __('Available Tools') ); 
     274 
     275        $admin_menu->add_submenu( 'tools', array( 
     276                'title' => __('Import'), 
     277                'cap' => 'import', 
     278                'slug' => 'import.php', 
     279                '_index' => 10 
     280        ) ); 
     281 
     282        $admin_menu->add_submenu( 'tools', array( 
     283                'title' => __('Export'), 
     284                'cap' => 'export', 
     285                'slug' => 'export.php', 
     286                '_index' => 15 
     287        ) ); 
     288 
     289        if ( is_multisite() && !is_main_site() ) { 
     290                $admin_menu->add_submenu( 'tools', array( 
     291                        'title' => __('Delete Site'), 
     292                        'cap' => 'manage_options', 
     293                        'slug' => 'ms-delete-site.php', 
     294                        '_index' => 25 
     295                ) ); 
     296        } 
     297 
     298        if ( ! is_multisite() && defined('WP_ALLOW_MULTISITE') && WP_ALLOW_MULTISITE ) { 
     299                $admin_menu->add_submenu( 'tools', array( 
     300                        'title' => __('Network Setup'), 
     301                        'cap' => 'manage_options', 
     302                        'slug' => 'network.php', 
     303                        '_index' => 50 
     304                ) ); 
     305        } 
     306 
     307$admin_menu->append( array( 
     308        'title' => __('Settings'), 
     309        'cap' => 'manage_options', 
     310        'slug' => 'options-general.php', 
     311        'id' => 'settings', 
     312        '_index' => 80 
     313) ); 
     314 
     315        $admin_menu->add_first_submenu( 'settings', _x('General', 'settings screen'), 10 ); 
     316 
     317        $admin_menu->add_submenu( 'settings', array( 
     318                'title' => __('Writing'), 
     319                'cap' => 'manage_options', 
     320                'slug' => 'options-writing.php', 
     321                '_index' => 15 
     322        ) ); 
     323 
     324        $admin_menu->add_submenu( 'settings', array( 
     325                'title' => __('Reading'), 
     326                'cap' => 'manage_options', 
     327                'slug' => 'options-reading.php', 
     328                '_index' => 20 
     329        ) ); 
     330 
     331        $admin_menu->add_submenu( 'settings', array( 
     332                'title' => __('Discussion'), 
     333                'cap' => 'manage_options', 
     334                'slug' => 'options-writing.php', 
     335                '_index' => 25 
     336        ) ); 
     337 
     338        $admin_menu->add_submenu( 'settings', array( 
     339                'title' => __('Media'), 
     340                'cap' => 'manage_options', 
     341                'slug' => 'options-media.php', 
     342                '_index' => 30 
     343        ) ); 
     344 
     345        $admin_menu->add_submenu( 'settings', array( 
     346                'title' => __('Privacy'), 
     347                'cap' => 'manage_options', 
     348                'slug' => 'options-privacy.php', 
     349                '_index' => 35 
     350        ) ); 
     351 
     352        $admin_menu->add_submenu( 'settings', array( 
     353                'title' => __('Permalinks'), 
     354                'cap' => 'manage_options', 
     355                'slug' => 'options-permalink.php', 
     356                '_index' => 40 
     357        ) ); 
     358 
     359$admin_menu->append( array( 
     360        'id' => 'separator-last', 
     361        'class' => 'wp-menu-separator', 
     362        '_index' => 99 
     363) ); 
     364 
     365// CPT menus need to be added later due to 'menu_position' 
     366$admin_menu->_add_cpt_menus(); 
    215367 
    216368// Back-compat for old top-levels 
    217369$_wp_real_parent_file['post.php'] = 'edit.php'; 
  • wp-admin/network/menu.php

    diff --git wp-admin/network/menu.php wp-admin/network/menu.php
    index a35a280..7f13336 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        '_index' => 2 
     19) ); 
    1420 
    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' ); 
     21$admin_menu->append( array( 
     22        'id' => 'separator1', 
     23        'class' => 'wp-menu-separator', 
     24        '_index' => 4 
     25) ); 
    1926 
    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' ); 
     27$admin_menu->append( array( 
     28        /* translators: Sites menu item */ 
     29        'title' => __( 'Sites' ), 
     30        'cap' => 'manage_sites', 
     31        'id' => 'site', 
     32        'slug' => 'sites.php', 
     33        '_index' => 5 
     34) ); 
     35 
     36        $admin_menu->add_first_submenu( 'site', __( 'All Sites' ) ); 
     37 
     38        $admin_menu->add_submenu( 'site', array( 
     39                /* translators: add new site */ 
     40                'title' => _x( 'Add New', 'site' ), 
     41                'cap' => 'create_sites', 
     42                'slug' => 'site-new.php', 
     43                '_index' => 10 
     44        ) ); 
     45 
     46$admin_menu->append( array( 
     47        'title' => __( 'Users' ), 
     48        'cap' => 'manage_network_users', 
     49        'slug' => 'users.php', 
     50        'id' => 'users', 
     51        '_index' => 10 
     52) ); 
     53 
     54        $admin_menu->add_first_submenu( 'users', __( 'All Users') ); 
     55 
     56        $admin_menu->add_submenu( 'users', array( 
     57                'title' => _x( 'Add New', 'user' ), 
     58                'cap' => 'create_users', 
     59                'slug' => 'user-new.php', 
     60                '_index' => 10 
     61        ) ); 
    2362 
    2463$update_data = wp_get_update_data(); 
    2564 
    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 } 
     65$admin_menu->append( array( 
     66        'title' => _admin_menu_theme_update_count( $update_data ), 
     67        'cap' => 'manage_network_themes', 
     68        'slug' => 'themes.php', 
     69        'id' => 'appearance', 
     70        '_index' => 15 
     71) ); 
    5572 
    56 unset($update_data); 
     73        $admin_menu->add_first_submenu( 'appearance', __( 'Installed Themes' ) ); 
     74 
     75        $admin_menu->add_submenu( 'appearance', array( 
     76                'title' => _x( 'Add New', 'theme' ), 
     77                'cap' => 'install_themes', 
     78                'slug' => 'theme-install.php', 
     79                '_index' => 10 
     80        ) ); 
     81 
     82        $admin_menu->add_submenu( 'appearance', array( 
     83                'title' => _x( 'Editor', 'theme editor' ), 
     84                'cap' => 'edit_themes', 
     85                'slug' => 'theme-editor.php', 
     86                '_index' => 15 
     87        ) ); 
     88 
     89$admin_menu->append( array( 
     90        'title' => _admin_menu_plugin_update_count( $update_data ), 
     91        'cap' => 'manage_network_plugins', 
     92        'slug' => 'plugins.php', 
     93        'id' => 'plugins', 
     94        '_index' => 20 
     95) ); 
     96 
     97        $admin_menu->add_first_submenu( 'plugins', __( 'Installed Plugins' ) ); 
    5798 
    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' ); 
     99        $admin_menu->add_submenu( 'plugins', array( 
     100                'title' => _x( 'Add New', 'plugin' ), 
     101                'cap' => 'install_plugins', 
     102                'slug' => 'plugin-install.php', 
     103                '_index' => 10 
     104        ) ); 
     105 
     106        $admin_menu->add_submenu( 'plugins', array( 
     107                'title' => _x( 'Editor', 'plugin editor' ), 
     108                'cap' => 'edit_plugins', 
     109                'slug' => 'plugin-editor.php', 
     110                '_index' => 15 
     111        ) ); 
     112 
     113$admin_menu->append( array( 
     114        'title' => __('Settings'), 
     115        'cap' => 'manage_network_options', 
     116        'slug' => 'settings.php', 
     117        'id' => 'settings', 
     118        '_index' => 25 
     119) ); 
     120 
     121        $admin_menu->add_first_submenu( 'settings', __('Network Settings') ); 
     122 
     123        $admin_menu->add_submenu( 'settings', array( 
     124                'title' => __('Writing'), 
     125                'cap' => 'manage_network_options', 
     126                'slug' => 'setup.php', 
     127                '_index' => 10 
     128        ) ); 
     129 
     130$admin_menu->append( array( 
     131        'title' => _admin_menu_update_count( $update_data ), 
     132        'cap' => 'manage_network', 
     133        'slug' => 'upgrade.php', 
     134        'class' => 'menu-icon-tools', 
     135        'id' => 'update', 
     136        '_index' => 30 
     137) ); 
     138 
     139        $admin_menu->add_first_submenu( 'update', __('Update Network'), 10 ); 
     140 
     141        $admin_menu->add_submenu( 'update', array( 
     142                'title' => __('Available Updates'), 
     143                'cap' => 'update_core', 
     144                'slug' => 'update-core.php', 
     145                '_index' => 15 
     146        ) ); 
     147 
     148unset($update_data); 
    60149 
    61 $menu[99] = array( '', 'read', 'separator-last', '', 'wp-menu-separator-last' ); 
     150$admin_menu->append( array( 
     151        'id' => 'separator-last', 
     152        'class' => 'wp-menu-separator', 
     153        '_index' => 99 
     154) ); 
    62155 
    63156require_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..fc44700 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        '_index' => 2 
     18) ); 
    1319 
    14 $menu[70] = array( __('Profile'), 'exist', 'profile.php', '', 'menu-top menu-icon-users', 'menu-users', 'div' ); 
     20$admin_menu->append( array( 
     21        'id' => 'separator1', 
     22        'class' => 'wp-menu-separator', 
     23        '_index' => 4 
     24) ); 
    1525 
    16 $menu[99] = array( '', 'exist', 'separator-last', '', 'wp-menu-separator-last' ); 
     26$admin_menu->append( array( 
     27        'title' => __( 'Profile' ), 
     28        'cap' => 'exist', 
     29        'id' => 'users', 
     30        'slug' => 'profile.php', 
     31        '_index' => 70 
     32) ); 
     33 
     34$admin_menu->append( array( 
     35        'id' => 'separator-last', 
     36        'class' => 'wp-menu-separator', 
     37        '_index' => 99 
     38) ); 
    1739 
    1840$_wp_real_parent_file['users.php'] = 'profile.php'; 
    1941$compat = array(); 
    20 $submenu = array(); 
    2142 
    2243require_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 7f0fd23..7e2e6dc 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 ea4f3d6..96cecc2 100644
    function get_post_types( $args = array(), $output = 'names', $operator = 'and' ) 
    904904 *     * If not set, the default is inherited from show_ui 
    905905 * - show_in_admin_bar - Makes this post type available via the admin bar. 
    906906 *     * If not set, the default is inherited from show_in_menu 
    907  * - menu_position - The position in the menu order the post type should appear. 
    908907 *     * show_in_menu must be true 
    909908 *     * Defaults to null, which places it at the bottom of its area. 
     909 * - menu_position - The id of the admin menu; this menu will show up above it. 
    910910 * - menu_icon - The url to the icon to be used for this menu. Defaults to use the posts icon. 
    911911 * - capability_type - The string to use to build the read, edit, and delete capabilities. Defaults to 'post'. 
    912912 *     * 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() ) { 
    966966                '_builtin' => false, '_edit_link' => 'post.php?post=%d', 'hierarchical' => false, 
    967967                'public' => false, 'rewrite' => true, 'has_archive' => false, 'query_var' => true, 
    968968                'supports' => array(), 'register_meta_box_cb' => null, 
    969                 'taxonomies' => array(), 'show_ui' => null, 'menu_position' => null, 'menu_icon' => null, 
     969                'taxonomies' => array(), 
     970                'show_ui' => null, 'show_in_menu' => null, 'menu_position' => null, 'menu_icon' => null, 
    970971                'can_export' => true, 
    971                 'show_in_nav_menus' => null, 'show_in_menu' => null, 'show_in_admin_bar' => null, 
     972                'show_in_nav_menus' => null, 'show_in_admin_bar' => null, 
    972973                'delete_with_user' => null, 
    973974        ); 
    974975        $args = wp_parse_args($args, $defaults); 
    function register_post_type( $post_type, $args = array() ) { 
    992993        if ( null === $args->show_in_menu || ! $args->show_ui ) 
    993994                $args->show_in_menu = $args->show_ui; 
    994995 
     996        if ( is_numeric( $args->menu_position ) ) { 
     997                _deprecated_argument( __FUNCTION__, '3.5', __( "Numeric values for 'menu_position' are deprecated. Use menu ids instead." ) ); 
     998                $args->menu_position = null; 
     999        } 
     1000 
    9951001        // If not set, default to the whether the full UI is shown. 
    9961002        if ( null === $args->show_in_admin_bar ) 
    9971003                $args->show_in_admin_bar = true === $args->show_in_menu;