X-Git-Url: https://scripts.mit.edu/gitweb/autoinstalls/wordpress.git/blobdiff_plain/f9001779751f83dc8a10e478bfecb4d8dd5f964c..16e7b37c7914d753890c1a05a9335f3b43751eb8:/wp-includes/class-wp-admin-bar.php diff --git a/wp-includes/class-wp-admin-bar.php b/wp-includes/class-wp-admin-bar.php index 549d5ecf..49986ac2 100644 --- a/wp-includes/class-wp-admin-bar.php +++ b/wp-includes/class-wp-admin-bar.php @@ -1,38 +1,67 @@ proto = 'https://'; + private $nodes = array(); + private $bound = false; + public $user; + + /** + * @param string $name + * @return string|array|void + */ + public function __get( $name ) { + switch ( $name ) { + case 'proto' : + return is_ssl() ? 'https://' : 'http://'; + + case 'menu' : + _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 menu property.' ); + return array(); // Sorry, folks. + } + } + /** + * @access public + */ + public function initialize() { $this->user = new stdClass; - $this->menu = new stdClass; - - /* Populate settings we need for the menu based on the current user. */ - $this->user->blogs = get_blogs_of_user( get_current_user_id() ); - if ( is_multisite() ) { - $this->user->active_blog = get_active_blog_for_user( get_current_user_id() ); - $this->user->domain = empty( $this->user->active_blog ) ? user_admin_url() : trailingslashit( get_home_url( $this->user->active_blog->blog_id ) ); - $this->user->account_domain = $this->user->domain; - } else { - $this->user->active_blog = $this->user->blogs[get_current_blog_id()]; - $this->user->domain = trailingslashit( home_url() ); - $this->user->account_domain = $this->user->domain; + + if ( is_user_logged_in() ) { + /* Populate settings we need for the menu based on the current user. */ + $this->user->blogs = get_blogs_of_user( get_current_user_id() ); + if ( is_multisite() ) { + $this->user->active_blog = get_active_blog_for_user( get_current_user_id() ); + $this->user->domain = empty( $this->user->active_blog ) ? user_admin_url() : trailingslashit( get_home_url( $this->user->active_blog->blog_id ) ); + $this->user->account_domain = $this->user->domain; + } else { + $this->user->active_blog = $this->user->blogs[get_current_blog_id()]; + $this->user->domain = trailingslashit( home_url() ); + $this->user->account_domain = $this->user->domain; + } } - $this->user->locale = get_locale(); add_action( 'wp_head', 'wp_admin_bar_header' ); add_action( 'admin_head', 'wp_admin_bar_header' ); if ( current_theme_supports( 'admin-bar' ) ) { - $admin_bar_args = get_theme_support( 'admin-bar' ); // add_theme_support( 'admin-bar', array( 'callback' => '__return_false') ); + /** + * To remove the default padding styles from WordPress for the Toolbar, use the following code: + * add_theme_support( 'admin-bar', array( 'callback' => '__return_false' ) ); + */ + $admin_bar_args = get_theme_support( 'admin-bar' ); $header_callback = $admin_bar_args[0]['callback']; } @@ -44,193 +73,528 @@ class WP_Admin_Bar { wp_enqueue_script( 'admin-bar' ); wp_enqueue_style( 'admin-bar' ); + /** + * Fires after WP_Admin_Bar is initialized. + * + * @since 3.1.0 + */ do_action( 'admin_bar_init' ); } - function add_menu( $args = array() ) { + /** + * @param array $node + */ + public function add_menu( $node ) { + $this->add_node( $node ); + } + + /** + * @param string $id + */ + public function remove_menu( $id ) { + $this->remove_node( $id ); + } + + /** + * Adds a node to the menu. + * + * @since 3.1.0 + * @since 4.5.0 Added the ability to pass 'lang' and 'dir' meta data. + * @access public + * + * @param array $args { + * Arguments for adding a node. + * + * @type string $id ID of the item. + * @type string $title Title of the node. + * @type string $parent Optional. ID of the parent node. + * @type string $href Optional. Link for the item. + * @type bool $group Optional. Whether or not the node is a group. Default false. + * @type array $meta Meta data including the following keys: 'html', 'class', 'rel', 'lang', 'dir', + * 'onclick', 'target', 'title', 'tabindex'. Default empty. + * } + */ + public function add_node( $args ) { + // Shim for old method signature: add_node( $parent_id, $menu_obj, $args ) + if ( func_num_args() >= 3 && is_string( func_get_arg(0) ) ) + $args = array_merge( array( 'parent' => func_get_arg(0) ), func_get_arg(2) ); + + if ( is_object( $args ) ) + $args = get_object_vars( $args ); + + // Ensure we have a valid title. + if ( empty( $args['id'] ) ) { + if ( empty( $args['title'] ) ) + return; + + _doing_it_wrong( __METHOD__, __( 'The menu ID should not be empty.' ), '3.3.0' ); + // Deprecated: Generate an ID from the title. + $args['id'] = esc_attr( sanitize_title( trim( $args['title'] ) ) ); + } + $defaults = array( - 'title' => false, - 'href' => false, - 'parent' => false, // false for a root menu, pass the ID value for a submenu of that menu. - 'id' => false, // defaults to a sanitized title value. - 'meta' => false // array of any of the following options: array( 'html' => '', 'class' => '', 'onclick' => '', target => '', title => '' ); + 'id' => false, + 'title' => false, + 'parent' => false, + 'href' => false, + 'group' => false, + 'meta' => array(), ); - $r = wp_parse_args( $args, $defaults ); - extract( $r, EXTR_SKIP ); + // If the node already exists, keep any data that isn't provided. + if ( $maybe_defaults = $this->get_node( $args['id'] ) ) + $defaults = get_object_vars( $maybe_defaults ); - if ( empty( $title ) ) - return false; + // Do the same for 'meta' items. + if ( ! empty( $defaults['meta'] ) && ! empty( $args['meta'] ) ) + $args['meta'] = wp_parse_args( $args['meta'], $defaults['meta'] ); - /* Make sure we have a valid ID */ - if ( empty( $id ) ) - $id = esc_attr( sanitize_title( trim( $title ) ) ); + $args = wp_parse_args( $args, $defaults ); - if ( ! empty( $parent ) ) { - /* Add the menu to the parent item */ - $child = array( 'id' => $id, 'title' => $title, 'href' => $href ); + $back_compat_parents = array( + 'my-account-with-avatar' => array( 'my-account', '3.3' ), + 'my-blogs' => array( 'my-sites', '3.3' ), + ); - if ( ! empty( $meta ) ) - $child['meta'] = $meta; + if ( isset( $back_compat_parents[ $args['parent'] ] ) ) { + list( $new_parent, $version ) = $back_compat_parents[ $args['parent'] ]; + _deprecated_argument( __METHOD__, $version, sprintf( 'Use %s as the parent for the %s admin bar node instead of %s.', $new_parent, $args['id'], $args['parent'] ) ); + $args['parent'] = $new_parent; + } - $this->add_node( $parent, $this->menu, $child ); - } else { - /* Add the menu item */ - $this->menu->{$id} = array( 'title' => $title, 'href' => $href ); + $this->_set_node( $args ); + } + + /** + * @param array $args + */ + final protected function _set_node( $args ) { + $this->nodes[ $args['id'] ] = (object) $args; + } + + /** + * Gets a node. + * + * @param string $id + * @return object Node. + */ + final public function get_node( $id ) { + if ( $node = $this->_get_node( $id ) ) + return clone $node; + } + + /** + * @param string $id + * @return object|void + */ + final protected function _get_node( $id ) { + if ( $this->bound ) + return; + + if ( empty( $id ) ) + $id = 'root'; + + if ( isset( $this->nodes[ $id ] ) ) + return $this->nodes[ $id ]; + } + + /** + * @return array|void + */ + final public function get_nodes() { + if ( ! $nodes = $this->_get_nodes() ) + return; - if ( ! empty( $meta ) ) - $this->menu->{$id}['meta'] = $meta; + foreach ( $nodes as &$node ) { + $node = clone $node; } + return $nodes; } - function remove_menu( $id ) { - return $this->remove_node( $id, $this->menu ); + /** + * @return array|void + */ + final protected function _get_nodes() { + if ( $this->bound ) + return; + + return $this->nodes; } - function render() { - ?> -
- + /** + * Add a group to a menu node. + * + * @since 3.3.0 + * + * @param array $args { + * Array of arguments for adding a group. + * + * @type string $id ID of the item. + * @type string $parent Optional. ID of the parent node. Default 'root'. + * @type array $meta Meta data for the group including the following keys: + * 'class', 'onclick', 'target', and 'title'. + * } + */ + final public function add_group( $args ) { + $args['group'] = true; + + $this->add_node( $args ); + } -
-
- - -
-
-
+ /** + * Remove a node. + * + * @param string $id The ID of the item. + */ + public function remove_node( $id ) { + $this->_unset_node( $id ); + } - menu = null; + /** + * @param string $id + */ + final protected function _unset_node( $id ) { + unset( $this->nodes[ $id ] ); } - /* Helpers */ - function recursive_render( $id, &$menu_item ) { ?> - _bind(); + if ( $root ) + $this->_render( $root ); + } - $menuclass = $is_parent ? 'menupop' : ''; - if ( ! empty( $menu_item['meta']['class'] ) ) - $menuclass .= ' ' . $menu_item['meta']['class']; - ?> + /** + * @return object|void + */ + final protected function _bind() { + if ( $this->bound ) + return; -
  • " class=""> - onclick="" target="" title=""remove_node( 'root' ); + $this->add_node( array( + 'id' => 'root', + 'group' => false, + ) ); + + // Normalize nodes: define internal 'children' and 'type' properties. + foreach ( $this->_get_nodes() as $node ) { + $node->children = array(); + $node->type = ( $node->group ) ? 'group' : 'item'; + unset( $node->group ); + + // The Root wants your orphans. No lonely items allowed. + if ( ! $node->parent ) + $node->parent = 'root'; + } - ?>>_get_nodes() as $node ) { + if ( 'root' == $node->id ) + continue; - if ( $is_parent ) : - ?>_get_node( $node->parent ) ) { + continue; + } - echo $menu_item['title']; + // Generate the group class (we distinguish between top level and other level groups). + $group_class = ( $node->parent == 'root' ) ? 'ab-top-menu' : 'ab-submenu'; - if ( $is_parent ) : - ?>type == 'group' ) { + if ( empty( $node->meta['class'] ) ) + $node->meta['class'] = $group_class; + else + $node->meta['class'] .= ' ' . $group_class; + } - ?> + // Items in items aren't allowed. Wrap nested items in 'default' groups. + if ( $parent->type == 'item' && $node->type == 'item' ) { + $default_id = $parent->id . '-default'; + $default = $this->_get_node( $default_id ); + + // The default group is added here to allow groups that are + // added before standard menu items to render first. + if ( ! $default ) { + // Use _set_node because add_node can be overloaded. + // Make sure to specify default settings for all properties. + $this->_set_node( array( + 'id' => $default_id, + 'parent' => $parent->id, + 'type' => 'group', + 'children' => array(), + 'meta' => array( + 'class' => $group_class, + ), + 'title' => false, + 'href' => false, + ) ); + $default = $this->_get_node( $default_id ); + $parent->children[] = $default; + } + $parent = $default; + + // Groups in groups aren't allowed. Add a special 'container' node. + // The container will invisibly wrap both groups. + } elseif ( $parent->type == 'group' && $node->type == 'group' ) { + $container_id = $parent->id . '-container'; + $container = $this->_get_node( $container_id ); + + // We need to create a container for this group, life is sad. + if ( ! $container ) { + // Use _set_node because add_node can be overloaded. + // Make sure to specify default settings for all properties. + $this->_set_node( array( + 'id' => $container_id, + 'type' => 'container', + 'children' => array( $parent ), + 'parent' => false, + 'title' => false, + 'href' => false, + 'meta' => array(), + ) ); + + $container = $this->_get_node( $container_id ); + + // Link the container node if a grandparent node exists. + $grandparent = $this->_get_node( $parent->parent ); + + if ( $grandparent ) { + $container->parent = $grandparent->id; + + $index = array_search( $parent, $grandparent->children, true ); + if ( $index === false ) + $grandparent->children[] = $container; + else + array_splice( $grandparent->children, $index, 1, array( $container ) ); + } + + $parent->parent = $container->id; + } + + $parent = $container; + } - - - + // Update the parent ID (it might have changed). + $node->parent = $parent->id; + + // Add the node to the tree. + $parent->children[] = $node; + } + + $root = $this->_get_node( 'root' ); + $this->bound = true; + return $root; + } - - + /** + * + * @global bool $is_IE + * @param object $root + */ + final protected function _render( $root ) { + global $is_IE; + + // Add browser classes. + // We have to do this here since admin bar shows on the front end. + $class = 'nojq nojs'; + if ( $is_IE ) { + if ( strpos( $_SERVER['HTTP_USER_AGENT'], 'MSIE 7' ) ) + $class .= ' ie7'; + elseif ( strpos( $_SERVER['HTTP_USER_AGENT'], 'MSIE 8' ) ) + $class .= ' ie8'; + elseif ( strpos( $_SERVER['HTTP_USER_AGENT'], 'MSIE 9' ) ) + $class .= ' ie9'; + } elseif ( wp_is_mobile() ) { + $class .= ' mobile'; + } + + ?> +
    + + + + + + -
  • + + $menu_item ) { - if ( $parent_id == $id ) { - $menu->{$parent_id}['children']->{$child['id']} = $child; - $child = null; - return true; + /** + * @param object $node + */ + final protected function _render_container( $node ) { + if ( $node->type != 'container' || empty( $node->children ) ) + return; + + ?>
    children as $group ) { + $this->_render_group( $group ); } + ?>
    {$id}['children'] ) ) - $this->add_node( $parent_id, $menu->{$id}['children'], $child ); + /** + * @param object $node + */ + final protected function _render_group( $node ) { + if ( $node->type == 'container' ) { + $this->_render_container( $node ); + return; } + if ( $node->type != 'group' || empty( $node->children ) ) + return; - $child = null; + if ( ! empty( $node->meta['class'] ) ) + $class = ' class="' . esc_attr( trim( $node->meta['class'] ) ) . '"'; + else + $class = ''; - return false; + ?>type != 'item' ) + return; + + $is_parent = ! empty( $node->children ); + $has_link = ! empty( $node->href ); + + // Allow only numeric values, then casted to integers, and allow a tabindex value of `0` for a11y. + $tabindex = ( isset( $node->meta['tabindex'] ) && is_numeric( $node->meta['tabindex'] ) ) ? (int) $node->meta['tabindex'] : ''; + $aria_attributes = ( '' !== $tabindex ) ? ' tabindex="' . $tabindex . '"' : ''; + + $menuclass = ''; + + if ( $is_parent ) { + $menuclass = 'menupop '; + $aria_attributes .= ' aria-haspopup="true"'; } - do_action( 'add_admin_bar_menus' ); + if ( ! empty( $node->meta['class'] ) ) + $menuclass .= $node->meta['class']; + + if ( $menuclass ) + $menuclass = ' class="' . esc_attr( trim( $menuclass ) ) . '"'; + + ?> + +
  • > href="href ) ?>"meta['onclick'] ) ) : + ?> onclick="meta['onclick'] ); ?>"meta['target'] ) ) : + ?> target="meta['target'] ); ?>"meta['title'] ) ) : + ?> title="meta['title'] ); ?>"meta['rel'] ) ) : + ?> rel="meta['rel'] ); ?>"meta['lang'] ) ) : + ?> lang="meta['lang'] ); ?>"meta['dir'] ) ) : + ?> dir="meta['dir'] ); ?>">
    meta['title'] ) ) : + ?> title="meta['title'] ); ?>"meta['lang'] ) ) : + ?> lang="meta['lang'] ); ?>"meta['dir'] ) ) : + ?> dir="meta['dir'] ); ?>">title; + + if ( $has_link ) : + ?>
    children as $group ) { + $this->_render_group( $group ); + } + ?>
    meta['html'] ) ) + echo $node->meta['html']; + + ?> +
  • $id ) ) { - unset( $menu->$id ); - return true; - } + /** + * @param string $id Unused. + * @param object $node + */ + public function recursive_render( $id, $node ) { + _deprecated_function( __METHOD__, '3.3.0', 'WP_Admin_bar::render(), WP_Admin_Bar::_render_item()' ); + $this->_render_item( $node ); + } - foreach( $menu as $menu_item_id => $menu_item ) { - if ( ! empty( $menu->{$menu_item_id}['children'] ) ) - $this->remove_node( $id, $menu->{$menu_item_id}['children'] ); + /** + * @access public + */ + public function add_menus() { + // User related, aligned right. + add_action( 'admin_bar_menu', 'wp_admin_bar_my_account_menu', 0 ); + add_action( 'admin_bar_menu', 'wp_admin_bar_search_menu', 4 ); + add_action( 'admin_bar_menu', 'wp_admin_bar_my_account_item', 7 ); + + // Site related. + add_action( 'admin_bar_menu', 'wp_admin_bar_sidebar_toggle', 0 ); + add_action( 'admin_bar_menu', 'wp_admin_bar_wp_menu', 10 ); + add_action( 'admin_bar_menu', 'wp_admin_bar_my_sites_menu', 20 ); + add_action( 'admin_bar_menu', 'wp_admin_bar_site_menu', 30 ); + add_action( 'admin_bar_menu', 'wp_admin_bar_customize_menu', 40 ); + add_action( 'admin_bar_menu', 'wp_admin_bar_updates_menu', 50 ); + + // Content related. + if ( ! is_network_admin() && ! is_user_admin() ) { + add_action( 'admin_bar_menu', 'wp_admin_bar_comments_menu', 60 ); + add_action( 'admin_bar_menu', 'wp_admin_bar_new_content_menu', 70 ); } + add_action( 'admin_bar_menu', 'wp_admin_bar_edit_menu', 80 ); - return false; - } + add_action( 'admin_bar_menu', 'wp_admin_bar_add_secondary_groups', 200 ); - // TODO: Convert to a core feature for multisite or remove - function load_user_locale_translations() { - $this->need_to_change_locale = ( get_locale() != $this->user->locale ); - if ( ! $this->need_to_change_locale ) - return; - /* - $this->previous_translations = get_translations_for_domain( 'default' ); - $this->adminbar_locale_filter = lambda( '$_', '$GLOBALS["wp_admin_bar"]->user->locale;' ); - unload_textdomain( 'default' ); - add_filter( 'locale', $this->adminbar_locale_filter ); - load_default_textdomain(); - $this->changed_locale = true; - */ - } - - function unload_user_locale_translations() { - global $l10n; - if ( ! $this->changed_locale ) - return; - /* - remove_filter( 'locale', $this->adminbar_locale_filter ); - $l10n['default'] = &$this->previous_translations; - */ + /** + * Fires after menus are added to the menu bar. + * + * @since 3.1.0 + */ + do_action( 'add_admin_bar_menus' ); } } -?>