[ Index ]

PHP Cross Reference of WordPress Trunk (Updated Daily)

Search

title

Body

[close]

/wp-admin/includes/ -> menu.php (source)

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


Generated : Sun Jun 4 08:20:02 2023 Cross-referenced by PHPXref