WordPress.org

Make WordPress Core

Ticket #12718: 12718.4.diff

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

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

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

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

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

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

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

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

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

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

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

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

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