| [ Index ] |
PHP Cross Reference of WordPress Trunk (Updated Daily) |
[Summary view] [Print] [Text view]
1 <?php 2 /** 3 * Build Administration Menu. 4 * 5 * @package WordPress 6 * @subpackage Administration 7 */ 8 9 if ( is_network_admin() ) { 10 11 /** 12 * Fires before the administration menu loads in the Network Admin. 13 * 14 * The hook fires before menus and sub-menus are removed based on user privileges. 15 * 16 * @since 3.1.0 17 * @access private 18 */ 19 do_action( '_network_admin_menu' ); 20 } elseif ( is_user_admin() ) { 21 22 /** 23 * Fires before the administration menu loads in the User Admin. 24 * 25 * The hook fires before menus and sub-menus are removed based on user privileges. 26 * 27 * @since 3.1.0 28 * @access private 29 */ 30 do_action( '_user_admin_menu' ); 31 } else { 32 33 /** 34 * Fires before the administration menu loads in the admin. 35 * 36 * The hook fires before menus and sub-menus are removed based on user privileges. 37 * 38 * @since 2.2.0 39 * @access private 40 */ 41 do_action( '_admin_menu' ); 42 } 43 44 /** 45 * @global array $menu 46 * @global array $submenu 47 * @global array $compat 48 */ 49 global $menu, $submenu, $compat; 50 51 // Create list of page plugin hook names. 52 foreach ( $menu as $menu_page ) { 53 $pos = strpos( $menu_page[2], '?' ); 54 55 if ( false !== $pos ) { 56 // Handle post_type=post|page|foo pages. 57 $hook_name = substr( $menu_page[2], 0, $pos ); 58 $hook_args = substr( $menu_page[2], $pos + 1 ); 59 wp_parse_str( $hook_args, $hook_args ); 60 61 // Set the hook name to be the post type. 62 if ( isset( $hook_args['post_type'] ) ) { 63 $hook_name = $hook_args['post_type']; 64 } else { 65 $hook_name = basename( $hook_name, '.php' ); 66 } 67 unset( $hook_args ); 68 } else { 69 $hook_name = basename( $menu_page[2], '.php' ); 70 } 71 72 $hook_name = sanitize_title( $hook_name ); 73 74 if ( isset( $compat[ $hook_name ] ) ) { 75 $hook_name = $compat[ $hook_name ]; 76 } elseif ( ! $hook_name ) { 77 continue; 78 } 79 80 $admin_page_hooks[ $menu_page[2] ] = $hook_name; 81 } 82 unset( $menu_page, $compat ); 83 84 $_wp_submenu_nopriv = array(); 85 $_wp_menu_nopriv = array(); 86 // Loop over submenus and remove pages for which the user does not have privs. 87 foreach ( $submenu as $parent => $sub ) { 88 foreach ( $sub as $index => $data ) { 89 if ( ! current_user_can( $data[1] ) ) { 90 unset( $submenu[ $parent ][ $index ] ); 91 $_wp_submenu_nopriv[ $parent ][ $data[2] ] = true; 92 } 93 } 94 unset( $index, $data ); 95 96 if ( empty( $submenu[ $parent ] ) ) { 97 unset( $submenu[ $parent ] ); 98 } 99 } 100 unset( $sub, $parent ); 101 102 /* 103 * Loop over the top-level menu. 104 * Menus for which the original parent is not accessible due to lack of privileges 105 * will have the next submenu in line be assigned as the new menu parent. 106 */ 107 foreach ( $menu as $id => $data ) { 108 if ( empty( $submenu[ $data[2] ] ) ) { 109 continue; 110 } 111 112 $subs = $submenu[ $data[2] ]; 113 $first_sub = reset( $subs ); 114 $old_parent = $data[2]; 115 $new_parent = $first_sub[2]; 116 117 /* 118 * If the first submenu is not the same as the assigned parent, 119 * make the first submenu the new parent. 120 */ 121 if ( $new_parent !== $old_parent ) { 122 $_wp_real_parent_file[ $old_parent ] = $new_parent; 123 124 $menu[ $id ][2] = $new_parent; 125 126 foreach ( $submenu[ $old_parent ] as $index => $data ) { 127 $submenu[ $new_parent ][ $index ] = $submenu[ $old_parent ][ $index ]; 128 unset( $submenu[ $old_parent ][ $index ] ); 129 } 130 unset( $submenu[ $old_parent ], $index ); 131 132 if ( isset( $_wp_submenu_nopriv[ $old_parent ] ) ) { 133 $_wp_submenu_nopriv[ $new_parent ] = $_wp_submenu_nopriv[ $old_parent ]; 134 } 135 } 136 } 137 unset( $id, $data, $subs, $first_sub, $old_parent, $new_parent ); 138 139 if ( is_network_admin() ) { 140 141 /** 142 * Fires before the administration menu loads in the Network Admin. 143 * 144 * @since 3.1.0 145 * 146 * @param string $context Empty context. 147 */ 148 do_action( 'network_admin_menu', '' ); 149 } elseif ( is_user_admin() ) { 150 151 /** 152 * Fires before the administration menu loads in the User Admin. 153 * 154 * @since 3.1.0 155 * 156 * @param string $context Empty context. 157 */ 158 do_action( 'user_admin_menu', '' ); 159 } else { 160 161 /** 162 * Fires before the administration menu loads in the admin. 163 * 164 * @since 1.5.0 165 * 166 * @param string $context Empty context. 167 */ 168 do_action( 'admin_menu', '' ); 169 } 170 171 /* 172 * Remove menus that have no accessible submenus and require privileges 173 * that the user does not have. Run re-parent loop again. 174 */ 175 foreach ( $menu as $id => $data ) { 176 if ( ! current_user_can( $data[1] ) ) { 177 $_wp_menu_nopriv[ $data[2] ] = true; 178 } 179 180 /* 181 * If there is only one submenu and it is has same destination as the parent, 182 * remove the submenu. 183 */ 184 if ( ! empty( $submenu[ $data[2] ] ) && 1 === count( $submenu[ $data[2] ] ) ) { 185 $subs = $submenu[ $data[2] ]; 186 $first_sub = reset( $subs ); 187 188 if ( $data[2] === $first_sub[2] ) { 189 unset( $submenu[ $data[2] ] ); 190 } 191 } 192 193 // If submenu is empty... 194 if ( empty( $submenu[ $data[2] ] ) ) { 195 // And user doesn't have privs, remove menu. 196 if ( isset( $_wp_menu_nopriv[ $data[2] ] ) ) { 197 unset( $menu[ $id ] ); 198 } 199 } 200 } 201 unset( $id, $data, $subs, $first_sub ); 202 203 /** 204 * Adds a CSS class to a string. 205 * 206 * @since 2.7.0 207 * 208 * @param string $class_to_add The CSS class to add. 209 * @param string $classes The string to add the CSS class to. 210 * @return string The string with the CSS class added. 211 */ 212 function add_cssclass( $class_to_add, $classes ) { 213 if ( empty( $classes ) ) { 214 return $class_to_add; 215 } 216 217 return $classes . ' ' . $class_to_add; 218 } 219 220 /** 221 * Adds CSS classes for top-level administration menu items. 222 * 223 * The list of added classes includes `.menu-top-first` and `.menu-top-last`. 224 * 225 * @since 2.7.0 226 * 227 * @param array $menu The array of administration menu items. 228 * @return array The array of administration menu items with the CSS classes added. 229 */ 230 function add_menu_classes( $menu ) { 231 $first_item = false; 232 $last_order = false; 233 $items_count = count( $menu ); 234 235 $i = 0; 236 237 foreach ( $menu as $order => $top ) { 238 ++$i; 239 240 if ( 0 === $order ) { // Dashboard is always shown/single. 241 $menu[0][4] = add_cssclass( 'menu-top-first', $top[4] ); 242 $last_order = 0; 243 continue; 244 } 245 246 if ( str_starts_with( $top[2], 'separator' ) && false !== $last_order ) { // If separator. 247 $first_item = true; 248 $classes = $menu[ $last_order ][4]; 249 250 $menu[ $last_order ][4] = add_cssclass( 'menu-top-last', $classes ); 251 continue; 252 } 253 254 if ( $first_item ) { 255 $first_item = false; 256 $classes = $menu[ $order ][4]; 257 258 $menu[ $order ][4] = add_cssclass( 'menu-top-first', $classes ); 259 } 260 261 if ( $i === $items_count ) { // Last item. 262 $classes = $menu[ $order ][4]; 263 264 $menu[ $order ][4] = add_cssclass( 'menu-top-last', $classes ); 265 } 266 267 $last_order = $order; 268 } 269 270 /** 271 * Filters administration menu array with classes added for top-level items. 272 * 273 * @since 2.7.0 274 * 275 * @param array $menu Associative array of administration menu items. 276 */ 277 return apply_filters( 'add_menu_classes', $menu ); 278 } 279 280 uksort( $menu, 'strnatcasecmp' ); // Make it all pretty. 281 282 /** 283 * Filters whether to enable custom ordering of the administration menu. 284 * 285 * See the {@see 'menu_order'} filter for reordering menu items. 286 * 287 * @since 2.8.0 288 * 289 * @param bool $custom Whether custom ordering is enabled. Default false. 290 */ 291 if ( apply_filters( 'custom_menu_order', false ) ) { 292 $menu_order = array(); 293 294 foreach ( $menu as $menu_item ) { 295 $menu_order[] = $menu_item[2]; 296 } 297 unset( $menu_item ); 298 299 $default_menu_order = $menu_order; 300 301 /** 302 * Filters the order of administration menu items. 303 * 304 * A truthy value must first be passed to the {@see 'custom_menu_order'} filter 305 * for this filter to work. Use the following to enable custom menu ordering: 306 * 307 * add_filter( 'custom_menu_order', '__return_true' ); 308 * 309 * @since 2.8.0 310 * 311 * @param array $menu_order An ordered array of menu items. 312 */ 313 $menu_order = apply_filters( 'menu_order', $menu_order ); 314 $menu_order = array_flip( $menu_order ); 315 316 $default_menu_order = array_flip( $default_menu_order ); 317 318 /** 319 * @global array $menu_order 320 * @global array $default_menu_order 321 * 322 * @param array $a 323 * @param array $b 324 * @return int 325 */ 326 function sort_menu( $a, $b ) { 327 global $menu_order, $default_menu_order; 328 329 $a = $a[2]; 330 $b = $b[2]; 331 332 if ( isset( $menu_order[ $a ] ) && ! isset( $menu_order[ $b ] ) ) { 333 return -1; 334 } elseif ( ! isset( $menu_order[ $a ] ) && isset( $menu_order[ $b ] ) ) { 335 return 1; 336 } elseif ( isset( $menu_order[ $a ] ) && isset( $menu_order[ $b ] ) ) { 337 return $menu_order[ $a ] <=> $menu_order[ $b ]; 338 } else { 339 return $default_menu_order[ $a ] <=> $default_menu_order[ $b ]; 340 } 341 } 342 343 usort( $menu, 'sort_menu' ); 344 unset( $menu_order, $default_menu_order ); 345 } 346 347 // Prevent adjacent separators. 348 $prev_menu_was_separator = false; 349 foreach ( $menu as $id => $data ) { 350 if ( false === stristr( $data[4], 'wp-menu-separator' ) ) { 351 352 // This item is not a separator, so falsey the toggler and do nothing. 353 $prev_menu_was_separator = false; 354 } else { 355 356 // The previous item was a separator, so unset this one. 357 if ( true === $prev_menu_was_separator ) { 358 unset( $menu[ $id ] ); 359 } 360 361 // This item is a separator, so truthy the toggler and move on. 362 $prev_menu_was_separator = true; 363 } 364 } 365 unset( $id, $data, $prev_menu_was_separator ); 366 367 // Remove the last menu item if it is a separator. 368 $last_menu_key = array_keys( $menu ); 369 $last_menu_key = array_pop( $last_menu_key ); 370 if ( ! empty( $menu ) && 'wp-menu-separator' === $menu[ $last_menu_key ][4] ) { 371 unset( $menu[ $last_menu_key ] ); 372 } 373 unset( $last_menu_key ); 374 375 if ( ! user_can_access_admin_page() ) { 376 377 /** 378 * Fires when access to an admin page is denied. 379 * 380 * @since 2.5.0 381 */ 382 do_action( 'admin_page_access_denied' ); 383 384 wp_die( __( 'Sorry, you are not allowed to access this page.' ), 403 ); 385 } 386 387 $menu = add_menu_classes( $menu );
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
| Generated : Fri Apr 24 08:20:12 2026 | Cross-referenced by PHPXref |