home *** CD-ROM | disk | FTP | other *** search
/ HTML Examples / WP.iso / wordpress2 / wp-includes / class-wp-admin-bar.php < prev    next >
Encoding:
PHP Script  |  2017-07-26  |  16.6 KB  |  604 lines

  1. <?php
  2. /**
  3.  * Toolbar API: WP_Admin_Bar class
  4.  *
  5.  * @package WordPress
  6.  * @subpackage Toolbar
  7.  * @since 3.1.0
  8.  */
  9.  
  10. /**
  11.  * Core class used to implement the Toolbar API.
  12.  *
  13.  * @since 3.1.0
  14.  */
  15. class WP_Admin_Bar {
  16.     private $nodes = array();
  17.     private $bound = false;
  18.     public $user;
  19.  
  20.     /**
  21.      * @param string $name
  22.      * @return string|array|void
  23.      */
  24.     public function __get( $name ) {
  25.         switch ( $name ) {
  26.             case 'proto' :
  27.                 return is_ssl() ? 'https://' : 'http://';
  28.  
  29.             case 'menu' :
  30.                 _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.' );
  31.                 return array(); // Sorry, folks.
  32.         }
  33.     }
  34.  
  35.     /**
  36.      */
  37.     public function initialize() {
  38.         $this->user = new stdClass;
  39.  
  40.         if ( is_user_logged_in() ) {
  41.             /* Populate settings we need for the menu based on the current user. */
  42.             $this->user->blogs = get_blogs_of_user( get_current_user_id() );
  43.             if ( is_multisite() ) {
  44.                 $this->user->active_blog = get_active_blog_for_user( get_current_user_id() );
  45.                 $this->user->domain = empty( $this->user->active_blog ) ? user_admin_url() : trailingslashit( get_home_url( $this->user->active_blog->blog_id ) );
  46.                 $this->user->account_domain = $this->user->domain;
  47.             } else {
  48.                 $this->user->active_blog = $this->user->blogs[get_current_blog_id()];
  49.                 $this->user->domain = trailingslashit( home_url() );
  50.                 $this->user->account_domain = $this->user->domain;
  51.             }
  52.         }
  53.  
  54.         add_action( 'wp_head', 'wp_admin_bar_header' );
  55.  
  56.         add_action( 'admin_head', 'wp_admin_bar_header' );
  57.  
  58.         if ( current_theme_supports( 'admin-bar' ) ) {
  59.             /**
  60.              * To remove the default padding styles from WordPress for the Toolbar, use the following code:
  61.              * add_theme_support( 'admin-bar', array( 'callback' => '__return_false' ) );
  62.              */
  63.             $admin_bar_args = get_theme_support( 'admin-bar' );
  64.             $header_callback = $admin_bar_args[0]['callback'];
  65.         }
  66.  
  67.         if ( empty($header_callback) )
  68.             $header_callback = '_admin_bar_bump_cb';
  69.  
  70.         add_action('wp_head', $header_callback);
  71.  
  72.         wp_enqueue_script( 'admin-bar' );
  73.         wp_enqueue_style( 'admin-bar' );
  74.  
  75.         /**
  76.          * Fires after WP_Admin_Bar is initialized.
  77.          *
  78.          * @since 3.1.0
  79.          */
  80.         do_action( 'admin_bar_init' );
  81.     }
  82.  
  83.     /**
  84.      * @param array $node
  85.      */
  86.     public function add_menu( $node ) {
  87.         $this->add_node( $node );
  88.     }
  89.  
  90.     /**
  91.      * @param string $id
  92.      */
  93.     public function remove_menu( $id ) {
  94.         $this->remove_node( $id );
  95.     }
  96.  
  97.     /**
  98.      * Adds a node to the menu.
  99.      *
  100.      * @since 3.1.0
  101.      * @since 4.5.0 Added the ability to pass 'lang' and 'dir' meta data.
  102.      *
  103.      * @param array $args {
  104.      *     Arguments for adding a node.
  105.      *
  106.      *     @type string $id     ID of the item.
  107.      *     @type string $title  Title of the node.
  108.      *     @type string $parent Optional. ID of the parent node.
  109.      *     @type string $href   Optional. Link for the item.
  110.      *     @type bool   $group  Optional. Whether or not the node is a group. Default false.
  111.      *     @type array  $meta   Meta data including the following keys: 'html', 'class', 'rel', 'lang', 'dir',
  112.      *                          'onclick', 'target', 'title', 'tabindex'. Default empty.
  113.      * }
  114.      */
  115.     public function add_node( $args ) {
  116.         // Shim for old method signature: add_node( $parent_id, $menu_obj, $args )
  117.         if ( func_num_args() >= 3 && is_string( func_get_arg(0) ) )
  118.             $args = array_merge( array( 'parent' => func_get_arg(0) ), func_get_arg(2) );
  119.  
  120.         if ( is_object( $args ) )
  121.             $args = get_object_vars( $args );
  122.  
  123.         // Ensure we have a valid title.
  124.         if ( empty( $args['id'] ) ) {
  125.             if ( empty( $args['title'] ) )
  126.                 return;
  127.  
  128.             _doing_it_wrong( __METHOD__, __( 'The menu ID should not be empty.' ), '3.3.0' );
  129.             // Deprecated: Generate an ID from the title.
  130.             $args['id'] = esc_attr( sanitize_title( trim( $args['title'] ) ) );
  131.         }
  132.  
  133.         $defaults = array(
  134.             'id'     => false,
  135.             'title'  => false,
  136.             'parent' => false,
  137.             'href'   => false,
  138.             'group'  => false,
  139.             'meta'   => array(),
  140.         );
  141.  
  142.         // If the node already exists, keep any data that isn't provided.
  143.         if ( $maybe_defaults = $this->get_node( $args['id'] ) )
  144.             $defaults = get_object_vars( $maybe_defaults );
  145.  
  146.         // Do the same for 'meta' items.
  147.         if ( ! empty( $defaults['meta'] ) && ! empty( $args['meta'] ) )
  148.             $args['meta'] = wp_parse_args( $args['meta'], $defaults['meta'] );
  149.  
  150.         $args = wp_parse_args( $args, $defaults );
  151.  
  152.         $back_compat_parents = array(
  153.             'my-account-with-avatar' => array( 'my-account', '3.3' ),
  154.             'my-blogs'               => array( 'my-sites',   '3.3' ),
  155.         );
  156.  
  157.         if ( isset( $back_compat_parents[ $args['parent'] ] ) ) {
  158.             list( $new_parent, $version ) = $back_compat_parents[ $args['parent'] ];
  159.             _deprecated_argument( __METHOD__, $version, sprintf( 'Use <code>%s</code> as the parent for the <code>%s</code> admin bar node instead of <code>%s</code>.', $new_parent, $args['id'], $args['parent'] ) );
  160.             $args['parent'] = $new_parent;
  161.         }
  162.  
  163.         $this->_set_node( $args );
  164.     }
  165.  
  166.     /**
  167.      * @param array $args
  168.      */
  169.     final protected function _set_node( $args ) {
  170.         $this->nodes[ $args['id'] ] = (object) $args;
  171.     }
  172.  
  173.     /**
  174.      * Gets a node.
  175.      *
  176.      * @param string $id
  177.      * @return object Node.
  178.      */
  179.     final public function get_node( $id ) {
  180.         if ( $node = $this->_get_node( $id ) )
  181.             return clone $node;
  182.     }
  183.  
  184.     /**
  185.      * @param string $id
  186.      * @return object|void
  187.      */
  188.     final protected function _get_node( $id ) {
  189.         if ( $this->bound )
  190.             return;
  191.  
  192.         if ( empty( $id ) )
  193.             $id = 'root';
  194.  
  195.         if ( isset( $this->nodes[ $id ] ) )
  196.             return $this->nodes[ $id ];
  197.     }
  198.  
  199.     /**
  200.      * @return array|void
  201.      */
  202.     final public function get_nodes() {
  203.         if ( ! $nodes = $this->_get_nodes() )
  204.             return;
  205.  
  206.         foreach ( $nodes as &$node ) {
  207.             $node = clone $node;
  208.         }
  209.         return $nodes;
  210.     }
  211.  
  212.     /**
  213.      * @return array|void
  214.      */
  215.     final protected function _get_nodes() {
  216.         if ( $this->bound )
  217.             return;
  218.  
  219.         return $this->nodes;
  220.     }
  221.  
  222.     /**
  223.      * Add a group to a menu node.
  224.      *
  225.      * @since 3.3.0
  226.      *
  227.      * @param array $args {
  228.      *     Array of arguments for adding a group.
  229.      *
  230.      *     @type string $id     ID of the item.
  231.      *     @type string $parent Optional. ID of the parent node. Default 'root'.
  232.      *     @type array  $meta   Meta data for the group including the following keys:
  233.      *                         'class', 'onclick', 'target', and 'title'.
  234.      * }
  235.      */
  236.     final public function add_group( $args ) {
  237.         $args['group'] = true;
  238.  
  239.         $this->add_node( $args );
  240.     }
  241.  
  242.     /**
  243.      * Remove a node.
  244.      *
  245.      * @param string $id The ID of the item.
  246.      */
  247.     public function remove_node( $id ) {
  248.         $this->_unset_node( $id );
  249.     }
  250.  
  251.     /**
  252.      * @param string $id
  253.      */
  254.     final protected function _unset_node( $id ) {
  255.         unset( $this->nodes[ $id ] );
  256.     }
  257.  
  258.     /**
  259.      */
  260.     public function render() {
  261.         $root = $this->_bind();
  262.         if ( $root )
  263.             $this->_render( $root );
  264.     }
  265.  
  266.     /**
  267.      * @return object|void
  268.      */
  269.     final protected function _bind() {
  270.         if ( $this->bound )
  271.             return;
  272.  
  273.         // Add the root node.
  274.         // Clear it first, just in case. Don't mess with The Root.
  275.         $this->remove_node( 'root' );
  276.         $this->add_node( array(
  277.             'id'    => 'root',
  278.             'group' => false,
  279.         ) );
  280.  
  281.         // Normalize nodes: define internal 'children' and 'type' properties.
  282.         foreach ( $this->_get_nodes() as $node ) {
  283.             $node->children = array();
  284.             $node->type = ( $node->group ) ? 'group' : 'item';
  285.             unset( $node->group );
  286.  
  287.             // The Root wants your orphans. No lonely items allowed.
  288.             if ( ! $node->parent )
  289.                 $node->parent = 'root';
  290.         }
  291.  
  292.         foreach ( $this->_get_nodes() as $node ) {
  293.             if ( 'root' == $node->id )
  294.                 continue;
  295.  
  296.             // Fetch the parent node. If it isn't registered, ignore the node.
  297.             if ( ! $parent = $this->_get_node( $node->parent ) ) {
  298.                 continue;
  299.             }
  300.  
  301.             // Generate the group class (we distinguish between top level and other level groups).
  302.             $group_class = ( $node->parent == 'root' ) ? 'ab-top-menu' : 'ab-submenu';
  303.  
  304.             if ( $node->type == 'group' ) {
  305.                 if ( empty( $node->meta['class'] ) )
  306.                     $node->meta['class'] = $group_class;
  307.                 else
  308.                     $node->meta['class'] .= ' ' . $group_class;
  309.             }
  310.  
  311.             // Items in items aren't allowed. Wrap nested items in 'default' groups.
  312.             if ( $parent->type == 'item' && $node->type == 'item' ) {
  313.                 $default_id = $parent->id . '-default';
  314.                 $default    = $this->_get_node( $default_id );
  315.  
  316.                 // The default group is added here to allow groups that are
  317.                 // added before standard menu items to render first.
  318.                 if ( ! $default ) {
  319.                     // Use _set_node because add_node can be overloaded.
  320.                     // Make sure to specify default settings for all properties.
  321.                     $this->_set_node( array(
  322.                         'id'        => $default_id,
  323.                         'parent'    => $parent->id,
  324.                         'type'      => 'group',
  325.                         'children'  => array(),
  326.                         'meta'      => array(
  327.                             'class'     => $group_class,
  328.                         ),
  329.                         'title'     => false,
  330.                         'href'      => false,
  331.                     ) );
  332.                     $default = $this->_get_node( $default_id );
  333.                     $parent->children[] = $default;
  334.                 }
  335.                 $parent = $default;
  336.  
  337.             // Groups in groups aren't allowed. Add a special 'container' node.
  338.             // The container will invisibly wrap both groups.
  339.             } elseif ( $parent->type == 'group' && $node->type == 'group' ) {
  340.                 $container_id = $parent->id . '-container';
  341.                 $container    = $this->_get_node( $container_id );
  342.  
  343.                 // We need to create a container for this group, life is sad.
  344.                 if ( ! $container ) {
  345.                     // Use _set_node because add_node can be overloaded.
  346.                     // Make sure to specify default settings for all properties.
  347.                     $this->_set_node( array(
  348.                         'id'       => $container_id,
  349.                         'type'     => 'container',
  350.                         'children' => array( $parent ),
  351.                         'parent'   => false,
  352.                         'title'    => false,
  353.                         'href'     => false,
  354.                         'meta'     => array(),
  355.                     ) );
  356.  
  357.                     $container = $this->_get_node( $container_id );
  358.  
  359.                     // Link the container node if a grandparent node exists.
  360.                     $grandparent = $this->_get_node( $parent->parent );
  361.  
  362.                     if ( $grandparent ) {
  363.                         $container->parent = $grandparent->id;
  364.  
  365.                         $index = array_search( $parent, $grandparent->children, true );
  366.                         if ( $index === false )
  367.                             $grandparent->children[] = $container;
  368.                         else
  369.                             array_splice( $grandparent->children, $index, 1, array( $container ) );
  370.                     }
  371.  
  372.                     $parent->parent = $container->id;
  373.                 }
  374.  
  375.                 $parent = $container;
  376.             }
  377.  
  378.             // Update the parent ID (it might have changed).
  379.             $node->parent = $parent->id;
  380.  
  381.             // Add the node to the tree.
  382.             $parent->children[] = $node;
  383.         }
  384.  
  385.         $root = $this->_get_node( 'root' );
  386.         $this->bound = true;
  387.         return $root;
  388.     }
  389.  
  390.     /**
  391.      *
  392.      * @global bool $is_IE
  393.      * @param object $root
  394.      */
  395.     final protected function _render( $root ) {
  396.         global $is_IE;
  397.  
  398.         // Add browser classes.
  399.         // We have to do this here since admin bar shows on the front end.
  400.         $class = 'nojq nojs';
  401.         if ( $is_IE ) {
  402.             if ( strpos( $_SERVER['HTTP_USER_AGENT'], 'MSIE 7' ) )
  403.                 $class .= ' ie7';
  404.             elseif ( strpos( $_SERVER['HTTP_USER_AGENT'], 'MSIE 8' ) )
  405.                 $class .= ' ie8';
  406.             elseif ( strpos( $_SERVER['HTTP_USER_AGENT'], 'MSIE 9' ) )
  407.                 $class .= ' ie9';
  408.         } elseif ( wp_is_mobile() ) {
  409.             $class .= ' mobile';
  410.         }
  411.  
  412.         ?>
  413.         <div id="wpadminbar" class="<?php echo $class; ?>">
  414.             <?php if ( ! is_admin() ) { ?>
  415.                 <a class="screen-reader-shortcut" href="#wp-toolbar" tabindex="1"><?php _e( 'Skip to toolbar' ); ?></a>
  416.             <?php } ?>
  417.             <div class="quicklinks" id="wp-toolbar" role="navigation" aria-label="<?php esc_attr_e( 'Toolbar' ); ?>" tabindex="0">
  418.                 <?php foreach ( $root->children as $group ) {
  419.                     $this->_render_group( $group );
  420.                 } ?>
  421.             </div>
  422.             <?php if ( is_user_logged_in() ) : ?>
  423.             <a class="screen-reader-shortcut" href="<?php echo esc_url( wp_logout_url() ); ?>"><?php _e('Log Out'); ?></a>
  424.             <?php endif; ?>
  425.         </div>
  426.  
  427.         <?php
  428.     }
  429.  
  430.     /**
  431.      * @param object $node
  432.      */
  433.     final protected function _render_container( $node ) {
  434.         if ( $node->type != 'container' || empty( $node->children ) )
  435.             return;
  436.  
  437.         ?><div id="<?php echo esc_attr( 'wp-admin-bar-' . $node->id ); ?>" class="ab-group-container"><?php
  438.             foreach ( $node->children as $group ) {
  439.                 $this->_render_group( $group );
  440.             }
  441.         ?></div><?php
  442.     }
  443.  
  444.     /**
  445.      * @param object $node
  446.      */
  447.     final protected function _render_group( $node ) {
  448.         if ( $node->type == 'container' ) {
  449.             $this->_render_container( $node );
  450.             return;
  451.         }
  452.         if ( $node->type != 'group' || empty( $node->children ) )
  453.             return;
  454.  
  455.         if ( ! empty( $node->meta['class'] ) )
  456.             $class = ' class="' . esc_attr( trim( $node->meta['class'] ) ) . '"';
  457.         else
  458.             $class = '';
  459.  
  460.         ?><ul id="<?php echo esc_attr( 'wp-admin-bar-' . $node->id ); ?>"<?php echo $class; ?>><?php
  461.             foreach ( $node->children as $item ) {
  462.                 $this->_render_item( $item );
  463.             }
  464.         ?></ul><?php
  465.     }
  466.  
  467.     /**
  468.      * @param object $node
  469.      */
  470.     final protected function _render_item( $node ) {
  471.         if ( $node->type != 'item' )
  472.             return;
  473.  
  474.         $is_parent = ! empty( $node->children );
  475.         $has_link  = ! empty( $node->href );
  476.  
  477.         // Allow only numeric values, then casted to integers, and allow a tabindex value of `0` for a11y.
  478.         $tabindex = ( isset( $node->meta['tabindex'] ) && is_numeric( $node->meta['tabindex'] ) ) ? (int) $node->meta['tabindex'] : '';
  479.         $aria_attributes = ( '' !== $tabindex ) ? ' tabindex="' . $tabindex . '"' : '';
  480.  
  481.         $menuclass = '';
  482.  
  483.         if ( $is_parent ) {
  484.             $menuclass = 'menupop ';
  485.             $aria_attributes .= ' aria-haspopup="true"';
  486.         }
  487.  
  488.         if ( ! empty( $node->meta['class'] ) )
  489.             $menuclass .= $node->meta['class'];
  490.  
  491.         if ( $menuclass )
  492.             $menuclass = ' class="' . esc_attr( trim( $menuclass ) ) . '"';
  493.  
  494.         ?>
  495.  
  496.         <li id="<?php echo esc_attr( 'wp-admin-bar-' . $node->id ); ?>"<?php echo $menuclass; ?>><?php
  497.             if ( $has_link ):
  498.                 ?><a class="ab-item"<?php echo $aria_attributes; ?> href="<?php echo esc_url( $node->href ) ?>"<?php
  499.                     if ( ! empty( $node->meta['onclick'] ) ) :
  500.                         ?> onclick="<?php echo esc_js( $node->meta['onclick'] ); ?>"<?php
  501.                     endif;
  502.                 if ( ! empty( $node->meta['target'] ) ) :
  503.                     ?> target="<?php echo esc_attr( $node->meta['target'] ); ?>"<?php
  504.                 endif;
  505.                 if ( ! empty( $node->meta['title'] ) ) :
  506.                     ?> title="<?php echo esc_attr( $node->meta['title'] ); ?>"<?php
  507.                 endif;
  508.                 if ( ! empty( $node->meta['rel'] ) ) :
  509.                     ?> rel="<?php echo esc_attr( $node->meta['rel'] ); ?>"<?php
  510.                 endif;
  511.                 if ( ! empty( $node->meta['lang'] ) ) :
  512.                     ?> lang="<?php echo esc_attr( $node->meta['lang'] ); ?>"<?php
  513.                 endif;
  514.                 if ( ! empty( $node->meta['dir'] ) ) :
  515.                     ?> dir="<?php echo esc_attr( $node->meta['dir'] ); ?>"<?php
  516.                 endif;
  517.                 ?>><?php
  518.             else:
  519.                 ?><div class="ab-item ab-empty-item"<?php echo $aria_attributes;
  520.                 if ( ! empty( $node->meta['title'] ) ) :
  521.                     ?> title="<?php echo esc_attr( $node->meta['title'] ); ?>"<?php
  522.                 endif;
  523.                 if ( ! empty( $node->meta['lang'] ) ) :
  524.                     ?> lang="<?php echo esc_attr( $node->meta['lang'] ); ?>"<?php
  525.                 endif;
  526.                 if ( ! empty( $node->meta['dir'] ) ) :
  527.                     ?> dir="<?php echo esc_attr( $node->meta['dir'] ); ?>"<?php
  528.                 endif;
  529.                 ?>><?php
  530.             endif;
  531.  
  532.             echo $node->title;
  533.  
  534.             if ( $has_link ) :
  535.                 ?></a><?php
  536.             else:
  537.                 ?></div><?php
  538.             endif;
  539.  
  540.             if ( $is_parent ) :
  541.                 ?><div class="ab-sub-wrapper"><?php
  542.                     foreach ( $node->children as $group ) {
  543.                         $this->_render_group( $group );
  544.                     }
  545.                 ?></div><?php
  546.             endif;
  547.  
  548.             if ( ! empty( $node->meta['html'] ) )
  549.                 echo $node->meta['html'];
  550.  
  551.             ?>
  552.         </li><?php
  553.     }
  554.  
  555.     /**
  556.      * Renders toolbar items recursively.
  557.      *
  558.      * @since 3.1.0
  559.      * @deprecated 3.3.0 Use WP_Admin_Bar::_render_item() or WP_Admin_bar::render() instead.
  560.      * @see WP_Admin_Bar::_render_item()
  561.      * @see WP_Admin_Bar::render()
  562.      *
  563.      * @param string $id    Unused.
  564.      * @param object $node
  565.      */
  566.     public function recursive_render( $id, $node ) {
  567.         _deprecated_function( __METHOD__, '3.3.0', 'WP_Admin_bar::render(), WP_Admin_Bar::_render_item()' );
  568.         $this->_render_item( $node );
  569.     }
  570.  
  571.     /**
  572.      */
  573.     public function add_menus() {
  574.         // User related, aligned right.
  575.         add_action( 'admin_bar_menu', 'wp_admin_bar_my_account_menu', 0 );
  576.         add_action( 'admin_bar_menu', 'wp_admin_bar_search_menu', 4 );
  577.         add_action( 'admin_bar_menu', 'wp_admin_bar_my_account_item', 7 );
  578.  
  579.         // Site related.
  580.         add_action( 'admin_bar_menu', 'wp_admin_bar_sidebar_toggle', 0 );
  581.         add_action( 'admin_bar_menu', 'wp_admin_bar_wp_menu', 10 );
  582.         add_action( 'admin_bar_menu', 'wp_admin_bar_my_sites_menu', 20 );
  583.         add_action( 'admin_bar_menu', 'wp_admin_bar_site_menu', 30 );
  584.         add_action( 'admin_bar_menu', 'wp_admin_bar_customize_menu', 40 );
  585.         add_action( 'admin_bar_menu', 'wp_admin_bar_updates_menu', 50 );
  586.  
  587.         // Content related.
  588.         if ( ! is_network_admin() && ! is_user_admin() ) {
  589.             add_action( 'admin_bar_menu', 'wp_admin_bar_comments_menu', 60 );
  590.             add_action( 'admin_bar_menu', 'wp_admin_bar_new_content_menu', 70 );
  591.         }
  592.         add_action( 'admin_bar_menu', 'wp_admin_bar_edit_menu', 80 );
  593.  
  594.         add_action( 'admin_bar_menu', 'wp_admin_bar_add_secondary_groups', 200 );
  595.  
  596.         /**
  597.          * Fires after menus are added to the menu bar.
  598.          *
  599.          * @since 3.1.0
  600.          */
  601.         do_action( 'add_admin_bar_menus' );
  602.     }
  603. }
  604.