wp/wp-includes/class-wp-admin-bar.php
changeset 21 48c4eec2b7e6
parent 19 3d72ae0968f4
equal deleted inserted replaced
20:7b1b88e27a20 21:48c4eec2b7e6
    10 /**
    10 /**
    11  * Core class used to implement the Toolbar API.
    11  * Core class used to implement the Toolbar API.
    12  *
    12  *
    13  * @since 3.1.0
    13  * @since 3.1.0
    14  */
    14  */
       
    15 #[AllowDynamicProperties]
    15 class WP_Admin_Bar {
    16 class WP_Admin_Bar {
    16 	private $nodes = array();
    17 	private $nodes = array();
    17 	private $bound = false;
    18 	private $bound = false;
    18 	public $user;
    19 	public $user;
    19 
    20 
    20 	/**
    21 	/**
    21 	 * @since 3.3.0
    22 	 * Deprecated menu property.
    22 	 *
    23 	 *
    23 	 * @param string $name
    24 	 * @since 3.1.0
    24 	 * @return string|array|void
    25 	 * @deprecated 3.3.0 Modify admin bar nodes with WP_Admin_Bar::get_node(),
    25 	 */
    26 	 *                   WP_Admin_Bar::add_node(), and WP_Admin_Bar::remove_node().
    26 	public function __get( $name ) {
    27 	 * @var array
    27 		switch ( $name ) {
    28 	 */
    28 			case 'proto':
    29 	public $menu = array();
    29 				return is_ssl() ? 'https://' : 'http://';
       
    30 
       
    31 			case 'menu':
       
    32 				_deprecated_argument( 'WP_Admin_Bar', '3.3.0', 'Modify admin bar nodes with WP_Admin_Bar::get_node(), WP_Admin_Bar::add_node(), and WP_Admin_Bar::remove_node(), not the <code>menu</code> property.' );
       
    33 				return array(); // Sorry, folks.
       
    34 		}
       
    35 	}
       
    36 
    30 
    37 	/**
    31 	/**
    38 	 * Initializes the admin bar.
    32 	 * Initializes the admin bar.
    39 	 *
    33 	 *
    40 	 * @since 3.1.0
    34 	 * @since 3.1.0
    41 	 */
    35 	 */
    42 	public function initialize() {
    36 	public function initialize() {
    43 		$this->user = new stdClass;
    37 		$this->user = new stdClass();
    44 
    38 
    45 		if ( is_user_logged_in() ) {
    39 		if ( is_user_logged_in() ) {
    46 			/* Populate settings we need for the menu based on the current user. */
    40 			/* Populate settings we need for the menu based on the current user. */
    47 			$this->user->blogs = get_blogs_of_user( get_current_user_id() );
    41 			$this->user->blogs = get_blogs_of_user( get_current_user_id() );
    48 			if ( is_multisite() ) {
    42 			if ( is_multisite() ) {
   111 	/**
   105 	/**
   112 	 * Adds a node to the menu.
   106 	 * Adds a node to the menu.
   113 	 *
   107 	 *
   114 	 * @since 3.1.0
   108 	 * @since 3.1.0
   115 	 * @since 4.5.0 Added the ability to pass 'lang' and 'dir' meta data.
   109 	 * @since 4.5.0 Added the ability to pass 'lang' and 'dir' meta data.
       
   110 	 * @since 6.5.0 Added the ability to pass 'menu_title' for an ARIA menu name.
   116 	 *
   111 	 *
   117 	 * @param array $args {
   112 	 * @param array $args {
   118 	 *     Arguments for adding a node.
   113 	 *     Arguments for adding a node.
   119 	 *
   114 	 *
   120 	 *     @type string $id     ID of the item.
   115 	 *     @type string $id     ID of the item.
   121 	 *     @type string $title  Title of the node.
   116 	 *     @type string $title  Title of the node.
   122 	 *     @type string $parent Optional. ID of the parent node.
   117 	 *     @type string $parent Optional. ID of the parent node.
   123 	 *     @type string $href   Optional. Link for the item.
   118 	 *     @type string $href   Optional. Link for the item.
   124 	 *     @type bool   $group  Optional. Whether or not the node is a group. Default false.
   119 	 *     @type bool   $group  Optional. Whether or not the node is a group. Default false.
   125 	 *     @type array  $meta   Meta data including the following keys: 'html', 'class', 'rel', 'lang', 'dir',
   120 	 *     @type array  $meta   Meta data including the following keys: 'html', 'class', 'rel', 'lang', 'dir',
   126 	 *                          'onclick', 'target', 'title', 'tabindex'. Default empty.
   121 	 *                          'onclick', 'target', 'title', 'tabindex', 'menu_title'. Default empty.
   127 	 * }
   122 	 * }
   128 	 */
   123 	 */
   129 	public function add_node( $args ) {
   124 	public function add_node( $args ) {
   130 		// Shim for old method signature: add_node( $parent_id, $menu_obj, $args ).
   125 		// Shim for old method signature: add_node( $parent_id, $menu_obj, $args ).
   131 		if ( func_num_args() >= 3 && is_string( $args ) ) {
   126 		if ( func_num_args() >= 3 && is_string( $args ) ) {
   317 	final protected function _bind() {
   312 	final protected function _bind() {
   318 		if ( $this->bound ) {
   313 		if ( $this->bound ) {
   319 			return;
   314 			return;
   320 		}
   315 		}
   321 
   316 
   322 		// Add the root node.
   317 		/*
   323 		// Clear it first, just in case. Don't mess with The Root.
   318 		 * Add the root node.
       
   319 		 * Clear it first, just in case. Don't mess with The Root.
       
   320 		 */
   324 		$this->remove_node( 'root' );
   321 		$this->remove_node( 'root' );
   325 		$this->add_node(
   322 		$this->add_node(
   326 			array(
   323 			array(
   327 				'id'    => 'root',
   324 				'id'    => 'root',
   328 				'group' => false,
   325 				'group' => false,
   366 			// Items in items aren't allowed. Wrap nested items in 'default' groups.
   363 			// Items in items aren't allowed. Wrap nested items in 'default' groups.
   367 			if ( 'item' === $parent->type && 'item' === $node->type ) {
   364 			if ( 'item' === $parent->type && 'item' === $node->type ) {
   368 				$default_id = $parent->id . '-default';
   365 				$default_id = $parent->id . '-default';
   369 				$default    = $this->_get_node( $default_id );
   366 				$default    = $this->_get_node( $default_id );
   370 
   367 
   371 				// The default group is added here to allow groups that are
   368 				/*
   372 				// added before standard menu items to render first.
   369 				 * The default group is added here to allow groups that are
       
   370 				 * added before standard menu items to render first.
       
   371 				 */
   373 				if ( ! $default ) {
   372 				if ( ! $default ) {
   374 					// Use _set_node because add_node can be overloaded.
   373 					/*
   375 					// Make sure to specify default settings for all properties.
   374 					 * Use _set_node because add_node can be overloaded.
       
   375 					 * Make sure to specify default settings for all properties.
       
   376 					 */
   376 					$this->_set_node(
   377 					$this->_set_node(
   377 						array(
   378 						array(
   378 							'id'       => $default_id,
   379 							'id'       => $default_id,
   379 							'parent'   => $parent->id,
   380 							'parent'   => $parent->id,
   380 							'type'     => 'group',
   381 							'type'     => 'group',
   389 					$default            = $this->_get_node( $default_id );
   390 					$default            = $this->_get_node( $default_id );
   390 					$parent->children[] = $default;
   391 					$parent->children[] = $default;
   391 				}
   392 				}
   392 				$parent = $default;
   393 				$parent = $default;
   393 
   394 
   394 				// Groups in groups aren't allowed. Add a special 'container' node.
   395 				/*
   395 				// The container will invisibly wrap both groups.
   396 				 * Groups in groups aren't allowed. Add a special 'container' node.
       
   397 				 * The container will invisibly wrap both groups.
       
   398 				 */
   396 			} elseif ( 'group' === $parent->type && 'group' === $node->type ) {
   399 			} elseif ( 'group' === $parent->type && 'group' === $node->type ) {
   397 				$container_id = $parent->id . '-container';
   400 				$container_id = $parent->id . '-container';
   398 				$container    = $this->_get_node( $container_id );
   401 				$container    = $this->_get_node( $container_id );
   399 
   402 
   400 				// We need to create a container for this group, life is sad.
   403 				// We need to create a container for this group, life is sad.
   401 				if ( ! $container ) {
   404 				if ( ! $container ) {
   402 					// Use _set_node because add_node can be overloaded.
   405 					/*
   403 					// Make sure to specify default settings for all properties.
   406 					 * Use _set_node because add_node can be overloaded.
       
   407 					 * Make sure to specify default settings for all properties.
       
   408 					 */
   404 					$this->_set_node(
   409 					$this->_set_node(
   405 						array(
   410 						array(
   406 							'id'       => $container_id,
   411 							'id'       => $container_id,
   407 							'type'     => 'container',
   412 							'type'     => 'container',
   408 							'children' => array( $parent ),
   413 							'children' => array( $parent ),
   451 	 * @since 3.3.0
   456 	 * @since 3.3.0
   452 	 *
   457 	 *
   453 	 * @param object $root
   458 	 * @param object $root
   454 	 */
   459 	 */
   455 	final protected function _render( $root ) {
   460 	final protected function _render( $root ) {
   456 		// Add browser classes.
   461 		/*
   457 		// We have to do this here since admin bar shows on the front end.
   462 		 * Add browser classes.
       
   463 		 * We have to do this here since admin bar shows on the front end.
       
   464 		 */
   458 		$class = 'nojq nojs';
   465 		$class = 'nojq nojs';
   459 		if ( wp_is_mobile() ) {
   466 		if ( wp_is_mobile() ) {
   460 			$class .= ' mobile';
   467 			$class .= ' mobile';
   461 		}
   468 		}
   462 
   469 
   470 				foreach ( $root->children as $group ) {
   477 				foreach ( $root->children as $group ) {
   471 					$this->_render_group( $group );
   478 					$this->_render_group( $group );
   472 				}
   479 				}
   473 				?>
   480 				?>
   474 			</div>
   481 			</div>
   475 			<?php if ( is_user_logged_in() ) : ?>
       
   476 			<a class="screen-reader-shortcut" href="<?php echo esc_url( wp_logout_url() ); ?>"><?php _e( 'Log Out' ); ?></a>
       
   477 			<?php endif; ?>
       
   478 		</div>
   482 		</div>
   479 
   483 
   480 		<?php
   484 		<?php
   481 	}
   485 	}
   482 
   486 
   497 		echo '</div>';
   501 		echo '</div>';
   498 	}
   502 	}
   499 
   503 
   500 	/**
   504 	/**
   501 	 * @since 3.3.0
   505 	 * @since 3.3.0
       
   506 	 * @since 6.5.0 Added `$menu_title` parameter to allow an ARIA menu name.
   502 	 *
   507 	 *
   503 	 * @param object $node
   508 	 * @param object $node
   504 	 */
   509 	 * @param string|bool $menu_title The accessible name of this ARIA menu or false if not provided.
   505 	final protected function _render_group( $node ) {
   510 	 */
       
   511 	final protected function _render_group( $node, $menu_title = false ) {
   506 		if ( 'container' === $node->type ) {
   512 		if ( 'container' === $node->type ) {
   507 			$this->_render_container( $node );
   513 			$this->_render_container( $node );
   508 			return;
   514 			return;
   509 		}
   515 		}
   510 		if ( 'group' !== $node->type || empty( $node->children ) ) {
   516 		if ( 'group' !== $node->type || empty( $node->children ) ) {
   515 			$class = ' class="' . esc_attr( trim( $node->meta['class'] ) ) . '"';
   521 			$class = ' class="' . esc_attr( trim( $node->meta['class'] ) ) . '"';
   516 		} else {
   522 		} else {
   517 			$class = '';
   523 			$class = '';
   518 		}
   524 		}
   519 
   525 
   520 		echo "<ul id='" . esc_attr( 'wp-admin-bar-' . $node->id ) . "'$class>";
   526 		if ( empty( $menu_title ) ) {
       
   527 			echo "<ul role='menu' id='" . esc_attr( 'wp-admin-bar-' . $node->id ) . "'$class>";
       
   528 		} else {
       
   529 			echo "<ul role='menu' aria-label='" . esc_attr( $menu_title ) . "' id='" . esc_attr( 'wp-admin-bar-' . $node->id ) . "'$class>";
       
   530 		}
   521 		foreach ( $node->children as $item ) {
   531 		foreach ( $node->children as $item ) {
   522 			$this->_render_item( $item );
   532 			$this->_render_item( $item );
   523 		}
   533 		}
   524 		echo '</ul>';
   534 		echo '</ul>';
   525 	}
   535 	}
   538 		$has_link              = ! empty( $node->href );
   548 		$has_link              = ! empty( $node->href );
   539 		$is_root_top_item      = 'root-default' === $node->parent;
   549 		$is_root_top_item      = 'root-default' === $node->parent;
   540 		$is_top_secondary_item = 'top-secondary' === $node->parent;
   550 		$is_top_secondary_item = 'top-secondary' === $node->parent;
   541 
   551 
   542 		// Allow only numeric values, then casted to integers, and allow a tabindex value of `0` for a11y.
   552 		// Allow only numeric values, then casted to integers, and allow a tabindex value of `0` for a11y.
   543 		$tabindex        = ( isset( $node->meta['tabindex'] ) && is_numeric( $node->meta['tabindex'] ) ) ? (int) $node->meta['tabindex'] : '';
   553 		$tabindex         = ( isset( $node->meta['tabindex'] ) && is_numeric( $node->meta['tabindex'] ) ) ? (int) $node->meta['tabindex'] : '';
   544 		$aria_attributes = ( '' !== $tabindex ) ? ' tabindex="' . $tabindex . '"' : '';
   554 		$aria_attributes  = ( '' !== $tabindex ) ? ' tabindex="' . $tabindex . '"' : '';
       
   555 		$aria_attributes .= ' role="menuitem"';
   545 
   556 
   546 		$menuclass = '';
   557 		$menuclass = '';
   547 		$arrow     = '';
   558 		$arrow     = '';
   548 
   559 
   549 		if ( $is_parent ) {
   560 		if ( $is_parent ) {
   550 			$menuclass        = 'menupop ';
   561 			$menuclass        = 'menupop ';
   551 			$aria_attributes .= ' aria-haspopup="true"';
   562 			$aria_attributes .= ' aria-expanded="false"';
   552 		}
   563 		}
   553 
   564 
   554 		if ( ! empty( $node->meta['class'] ) ) {
   565 		if ( ! empty( $node->meta['class'] ) ) {
   555 			$menuclass .= $node->meta['class'];
   566 			$menuclass .= $node->meta['class'];
   556 		}
   567 		}
   562 
   573 
   563 		if ( $menuclass ) {
   574 		if ( $menuclass ) {
   564 			$menuclass = ' class="' . esc_attr( trim( $menuclass ) ) . '"';
   575 			$menuclass = ' class="' . esc_attr( trim( $menuclass ) ) . '"';
   565 		}
   576 		}
   566 
   577 
   567 		echo "<li id='" . esc_attr( 'wp-admin-bar-' . $node->id ) . "'$menuclass>";
   578 		echo "<li role='group' id='" . esc_attr( 'wp-admin-bar-' . $node->id ) . "'$menuclass>";
   568 
   579 
   569 		if ( $has_link ) {
   580 		if ( $has_link ) {
   570 			$attributes = array( 'onclick', 'target', 'title', 'rel', 'lang', 'dir' );
   581 			$attributes = array( 'onclick', 'target', 'title', 'rel', 'lang', 'dir' );
   571 			echo "<a class='ab-item'$aria_attributes href='" . esc_url( $node->href ) . "'";
   582 			echo "<a class='ab-item'$aria_attributes href='" . esc_url( $node->href ) . "'";
   572 		} else {
   583 		} else {
   595 		}
   606 		}
   596 
   607 
   597 		if ( $is_parent ) {
   608 		if ( $is_parent ) {
   598 			echo '<div class="ab-sub-wrapper">';
   609 			echo '<div class="ab-sub-wrapper">';
   599 			foreach ( $node->children as $group ) {
   610 			foreach ( $node->children as $group ) {
   600 				$this->_render_group( $group );
   611 				if ( empty( $node->meta['menu_title'] ) ) {
       
   612 					$this->_render_group( $group, false );
       
   613 				} else {
       
   614 					$this->_render_group( $group, $node->meta['menu_title'] );
       
   615 				}
   601 			}
   616 			}
   602 			echo '</div>';
   617 			echo '</div>';
   603 		}
   618 		}
   604 
   619 
   605 		if ( ! empty( $node->meta['html'] ) ) {
   620 		if ( ! empty( $node->meta['html'] ) ) {
   631 	 * @since 3.1.0
   646 	 * @since 3.1.0
   632 	 */
   647 	 */
   633 	public function add_menus() {
   648 	public function add_menus() {
   634 		// User-related, aligned right.
   649 		// User-related, aligned right.
   635 		add_action( 'admin_bar_menu', 'wp_admin_bar_my_account_menu', 0 );
   650 		add_action( 'admin_bar_menu', 'wp_admin_bar_my_account_menu', 0 );
   636 		add_action( 'admin_bar_menu', 'wp_admin_bar_search_menu', 4 );
   651 		add_action( 'admin_bar_menu', 'wp_admin_bar_my_account_item', 9991 );
   637 		add_action( 'admin_bar_menu', 'wp_admin_bar_my_account_item', 7 );
   652 		add_action( 'admin_bar_menu', 'wp_admin_bar_recovery_mode_menu', 9992 );
   638 		add_action( 'admin_bar_menu', 'wp_admin_bar_recovery_mode_menu', 8 );
   653 		add_action( 'admin_bar_menu', 'wp_admin_bar_search_menu', 9999 );
   639 
   654 
   640 		// Site-related.
   655 		// Site-related.
   641 		add_action( 'admin_bar_menu', 'wp_admin_bar_sidebar_toggle', 0 );
   656 		add_action( 'admin_bar_menu', 'wp_admin_bar_sidebar_toggle', 0 );
   642 		add_action( 'admin_bar_menu', 'wp_admin_bar_wp_menu', 10 );
   657 		add_action( 'admin_bar_menu', 'wp_admin_bar_wp_menu', 10 );
   643 		add_action( 'admin_bar_menu', 'wp_admin_bar_my_sites_menu', 20 );
   658 		add_action( 'admin_bar_menu', 'wp_admin_bar_my_sites_menu', 20 );