1 <?php |
1 <?php |
2 /** |
2 /** |
3 * The WordPress Toolbar |
3 * Toolbar API: WP_Admin_Bar class |
4 * |
|
5 * @since 3.1.0 |
|
6 * |
4 * |
7 * @package WordPress |
5 * @package WordPress |
8 * @subpackage Toolbar |
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 |
9 */ |
14 */ |
10 class WP_Admin_Bar { |
15 class WP_Admin_Bar { |
11 private $nodes = array(); |
16 private $nodes = array(); |
12 private $bound = false; |
17 private $bound = false; |
13 public $user; |
18 public $user; |
14 |
19 |
|
20 /** |
|
21 * @param string $name |
|
22 * @return string|array|void |
|
23 */ |
15 public function __get( $name ) { |
24 public function __get( $name ) { |
16 switch ( $name ) { |
25 switch ( $name ) { |
17 case 'proto' : |
26 case 'proto' : |
18 return is_ssl() ? 'https://' : 'http://'; |
27 return is_ssl() ? 'https://' : 'http://'; |
19 |
28 |
20 case 'menu' : |
29 case 'menu' : |
21 _deprecated_argument( 'WP_Admin_Bar', '3.3', '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.' ); |
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.' ); |
22 return array(); // Sorry, folks. |
31 return array(); // Sorry, folks. |
23 } |
32 } |
24 } |
33 } |
25 |
34 |
|
35 /** |
|
36 */ |
26 public function initialize() { |
37 public function initialize() { |
27 $this->user = new stdClass; |
38 $this->user = new stdClass; |
28 |
39 |
29 if ( is_user_logged_in() ) { |
40 if ( is_user_logged_in() ) { |
30 /* Populate settings we need for the menu based on the current user. */ |
41 /* Populate settings we need for the menu based on the current user. */ |
67 * @since 3.1.0 |
78 * @since 3.1.0 |
68 */ |
79 */ |
69 do_action( 'admin_bar_init' ); |
80 do_action( 'admin_bar_init' ); |
70 } |
81 } |
71 |
82 |
|
83 /** |
|
84 * @param array $node |
|
85 */ |
72 public function add_menu( $node ) { |
86 public function add_menu( $node ) { |
73 $this->add_node( $node ); |
87 $this->add_node( $node ); |
74 } |
88 } |
75 |
89 |
|
90 /** |
|
91 * @param string $id |
|
92 */ |
76 public function remove_menu( $id ) { |
93 public function remove_menu( $id ) { |
77 $this->remove_node( $id ); |
94 $this->remove_node( $id ); |
78 } |
95 } |
79 |
96 |
80 /** |
97 /** |
81 * Add a node to the menu. |
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. |
82 * |
102 * |
83 * @param array $args { |
103 * @param array $args { |
84 * Arguments for adding a node. |
104 * Arguments for adding a node. |
85 * |
105 * |
86 * @type string $id ID of the item. |
106 * @type string $id ID of the item. |
87 * @type string $title Title of the node. |
107 * @type string $title Title of the node. |
88 * @type string $parent Optional. ID of the parent node. |
108 * @type string $parent Optional. ID of the parent node. |
89 * @type string $href Optional. Link for the item. |
109 * @type string $href Optional. Link for the item. |
90 * @type bool $group Optional. Whether or not the node is a group. Default false. |
110 * @type bool $group Optional. Whether or not the node is a group. Default false. |
91 * @type array $meta Meta data including the following keys: 'html', 'class', 'rel', |
111 * @type array $meta Meta data including the following keys: 'html', 'class', 'rel', 'lang', 'dir', |
92 * 'onclick', 'target', 'title', 'tabindex'. Default empty. |
112 * 'onclick', 'target', 'title', 'tabindex'. Default empty. |
93 * } |
113 * } |
94 */ |
114 */ |
95 public function add_node( $args ) { |
115 public function add_node( $args ) { |
96 // Shim for old method signature: add_node( $parent_id, $menu_obj, $args ) |
116 // Shim for old method signature: add_node( $parent_id, $menu_obj, $args ) |
103 // Ensure we have a valid title. |
123 // Ensure we have a valid title. |
104 if ( empty( $args['id'] ) ) { |
124 if ( empty( $args['id'] ) ) { |
105 if ( empty( $args['title'] ) ) |
125 if ( empty( $args['title'] ) ) |
106 return; |
126 return; |
107 |
127 |
108 _doing_it_wrong( __METHOD__, __( 'The menu ID should not be empty.' ), '3.3' ); |
128 _doing_it_wrong( __METHOD__, __( 'The menu ID should not be empty.' ), '3.3.0' ); |
109 // Deprecated: Generate an ID from the title. |
129 // Deprecated: Generate an ID from the title. |
110 $args['id'] = esc_attr( sanitize_title( trim( $args['title'] ) ) ); |
130 $args['id'] = esc_attr( sanitize_title( trim( $args['title'] ) ) ); |
111 } |
131 } |
112 |
132 |
113 $defaults = array( |
133 $defaults = array( |
141 } |
161 } |
142 |
162 |
143 $this->_set_node( $args ); |
163 $this->_set_node( $args ); |
144 } |
164 } |
145 |
165 |
|
166 /** |
|
167 * @param array $args |
|
168 */ |
146 final protected function _set_node( $args ) { |
169 final protected function _set_node( $args ) { |
147 $this->nodes[ $args['id'] ] = (object) $args; |
170 $this->nodes[ $args['id'] ] = (object) $args; |
148 } |
171 } |
149 |
172 |
150 /** |
173 /** |
151 * Gets a node. |
174 * Gets a node. |
152 * |
175 * |
|
176 * @param string $id |
153 * @return object Node. |
177 * @return object Node. |
154 */ |
178 */ |
155 final public function get_node( $id ) { |
179 final public function get_node( $id ) { |
156 if ( $node = $this->_get_node( $id ) ) |
180 if ( $node = $this->_get_node( $id ) ) |
157 return clone $node; |
181 return clone $node; |
158 } |
182 } |
159 |
183 |
|
184 /** |
|
185 * @param string $id |
|
186 * @return object|void |
|
187 */ |
160 final protected function _get_node( $id ) { |
188 final protected function _get_node( $id ) { |
161 if ( $this->bound ) |
189 if ( $this->bound ) |
162 return; |
190 return; |
163 |
191 |
164 if ( empty( $id ) ) |
192 if ( empty( $id ) ) |
166 |
194 |
167 if ( isset( $this->nodes[ $id ] ) ) |
195 if ( isset( $this->nodes[ $id ] ) ) |
168 return $this->nodes[ $id ]; |
196 return $this->nodes[ $id ]; |
169 } |
197 } |
170 |
198 |
|
199 /** |
|
200 * @return array|void |
|
201 */ |
171 final public function get_nodes() { |
202 final public function get_nodes() { |
172 if ( ! $nodes = $this->_get_nodes() ) |
203 if ( ! $nodes = $this->_get_nodes() ) |
173 return; |
204 return; |
174 |
205 |
175 foreach ( $nodes as &$node ) { |
206 foreach ( $nodes as &$node ) { |
176 $node = clone $node; |
207 $node = clone $node; |
177 } |
208 } |
178 return $nodes; |
209 return $nodes; |
179 } |
210 } |
180 |
211 |
|
212 /** |
|
213 * @return array|void |
|
214 */ |
181 final protected function _get_nodes() { |
215 final protected function _get_nodes() { |
182 if ( $this->bound ) |
216 if ( $this->bound ) |
183 return; |
217 return; |
184 |
218 |
185 return $this->nodes; |
219 return $this->nodes; |
206 } |
240 } |
207 |
241 |
208 /** |
242 /** |
209 * Remove a node. |
243 * Remove a node. |
210 * |
244 * |
211 * @param string The ID of the item. |
245 * @param string $id The ID of the item. |
212 */ |
246 */ |
213 public function remove_node( $id ) { |
247 public function remove_node( $id ) { |
214 $this->_unset_node( $id ); |
248 $this->_unset_node( $id ); |
215 } |
249 } |
216 |
250 |
|
251 /** |
|
252 * @param string $id |
|
253 */ |
217 final protected function _unset_node( $id ) { |
254 final protected function _unset_node( $id ) { |
218 unset( $this->nodes[ $id ] ); |
255 unset( $this->nodes[ $id ] ); |
219 } |
256 } |
220 |
257 |
|
258 /** |
|
259 */ |
221 public function render() { |
260 public function render() { |
222 $root = $this->_bind(); |
261 $root = $this->_bind(); |
223 if ( $root ) |
262 if ( $root ) |
224 $this->_render( $root ); |
263 $this->_render( $root ); |
225 } |
264 } |
226 |
265 |
|
266 /** |
|
267 * @return object|void |
|
268 */ |
227 final protected function _bind() { |
269 final protected function _bind() { |
228 if ( $this->bound ) |
270 if ( $this->bound ) |
229 return; |
271 return; |
230 |
272 |
231 // Add the root node. |
273 // Add the root node. |
343 $root = $this->_get_node( 'root' ); |
385 $root = $this->_get_node( 'root' ); |
344 $this->bound = true; |
386 $this->bound = true; |
345 return $root; |
387 return $root; |
346 } |
388 } |
347 |
389 |
|
390 /** |
|
391 * |
|
392 * @global bool $is_IE |
|
393 * @param object $root |
|
394 */ |
348 final protected function _render( $root ) { |
395 final protected function _render( $root ) { |
349 global $is_IE; |
396 global $is_IE; |
350 |
397 |
351 // Add browser classes. |
398 // Add browser classes. |
352 // We have to do this here since admin bar shows on the front end. |
399 // We have to do this here since admin bar shows on the front end. |
389 $this->_render_group( $group ); |
439 $this->_render_group( $group ); |
390 } |
440 } |
391 ?></div><?php |
441 ?></div><?php |
392 } |
442 } |
393 |
443 |
|
444 /** |
|
445 * @param object $node |
|
446 */ |
394 final protected function _render_group( $node ) { |
447 final protected function _render_group( $node ) { |
395 if ( $node->type == 'container' ) |
448 if ( $node->type == 'container' ) { |
396 return $this->_render_container( $node ); |
449 $this->_render_container( $node ); |
397 |
450 return; |
|
451 } |
398 if ( $node->type != 'group' || empty( $node->children ) ) |
452 if ( $node->type != 'group' || empty( $node->children ) ) |
399 return; |
453 return; |
400 |
454 |
401 if ( ! empty( $node->meta['class'] ) ) |
455 if ( ! empty( $node->meta['class'] ) ) |
402 $class = ' class="' . esc_attr( trim( $node->meta['class'] ) ) . '"'; |
456 $class = ' class="' . esc_attr( trim( $node->meta['class'] ) ) . '"'; |
408 $this->_render_item( $item ); |
462 $this->_render_item( $item ); |
409 } |
463 } |
410 ?></ul><?php |
464 ?></ul><?php |
411 } |
465 } |
412 |
466 |
|
467 /** |
|
468 * @param object $node |
|
469 */ |
413 final protected function _render_item( $node ) { |
470 final protected function _render_item( $node ) { |
414 if ( $node->type != 'item' ) |
471 if ( $node->type != 'item' ) |
415 return; |
472 return; |
416 |
473 |
417 $is_parent = ! empty( $node->children ); |
474 $is_parent = ! empty( $node->children ); |
418 $has_link = ! empty( $node->href ); |
475 $has_link = ! empty( $node->href ); |
419 |
476 |
420 $tabindex = isset( $node->meta['tabindex'] ) ? (int) $node->meta['tabindex'] : ''; |
477 // Allow only numeric values, then casted to integers, and allow a tabindex value of `0` for a11y. |
421 $aria_attributes = $tabindex ? 'tabindex="' . $tabindex . '"' : ''; |
478 $tabindex = ( isset( $node->meta['tabindex'] ) && is_numeric( $node->meta['tabindex'] ) ) ? (int) $node->meta['tabindex'] : ''; |
|
479 $aria_attributes = ( '' !== $tabindex ) ? ' tabindex="' . $tabindex . '"' : ''; |
422 |
480 |
423 $menuclass = ''; |
481 $menuclass = ''; |
424 |
482 |
425 if ( $is_parent ) { |
483 if ( $is_parent ) { |
426 $menuclass = 'menupop '; |
484 $menuclass = 'menupop '; |
435 |
493 |
436 ?> |
494 ?> |
437 |
495 |
438 <li id="<?php echo esc_attr( 'wp-admin-bar-' . $node->id ); ?>"<?php echo $menuclass; ?>><?php |
496 <li id="<?php echo esc_attr( 'wp-admin-bar-' . $node->id ); ?>"<?php echo $menuclass; ?>><?php |
439 if ( $has_link ): |
497 if ( $has_link ): |
440 ?><a class="ab-item" <?php echo $aria_attributes; ?> href="<?php echo esc_url( $node->href ) ?>"<?php |
498 ?><a class="ab-item"<?php echo $aria_attributes; ?> href="<?php echo esc_url( $node->href ) ?>"<?php |
441 if ( ! empty( $node->meta['onclick'] ) ) : |
499 if ( ! empty( $node->meta['onclick'] ) ) : |
442 ?> onclick="<?php echo esc_js( $node->meta['onclick'] ); ?>"<?php |
500 ?> onclick="<?php echo esc_js( $node->meta['onclick'] ); ?>"<?php |
443 endif; |
501 endif; |
444 if ( ! empty( $node->meta['target'] ) ) : |
502 if ( ! empty( $node->meta['target'] ) ) : |
445 ?> target="<?php echo esc_attr( $node->meta['target'] ); ?>"<?php |
503 ?> target="<?php echo esc_attr( $node->meta['target'] ); ?>"<?php |
448 ?> title="<?php echo esc_attr( $node->meta['title'] ); ?>"<?php |
506 ?> title="<?php echo esc_attr( $node->meta['title'] ); ?>"<?php |
449 endif; |
507 endif; |
450 if ( ! empty( $node->meta['rel'] ) ) : |
508 if ( ! empty( $node->meta['rel'] ) ) : |
451 ?> rel="<?php echo esc_attr( $node->meta['rel'] ); ?>"<?php |
509 ?> rel="<?php echo esc_attr( $node->meta['rel'] ); ?>"<?php |
452 endif; |
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; |
453 ?>><?php |
517 ?>><?php |
454 else: |
518 else: |
455 ?><div class="ab-item ab-empty-item" <?php echo $aria_attributes; |
519 ?><div class="ab-item ab-empty-item"<?php echo $aria_attributes; |
456 if ( ! empty( $node->meta['title'] ) ) : |
520 if ( ! empty( $node->meta['title'] ) ) : |
457 ?> title="<?php echo esc_attr( $node->meta['title'] ); ?>"<?php |
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 |
458 endif; |
528 endif; |
459 ?>><?php |
529 ?>><?php |
460 endif; |
530 endif; |
461 |
531 |
462 echo $node->title; |
532 echo $node->title; |
480 |
550 |
481 ?> |
551 ?> |
482 </li><?php |
552 </li><?php |
483 } |
553 } |
484 |
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 */ |
485 public function recursive_render( $id, $node ) { |
566 public function recursive_render( $id, $node ) { |
486 _deprecated_function( __METHOD__, '3.3', 'WP_Admin_bar::render(), WP_Admin_Bar::_render_item()' ); |
567 _deprecated_function( __METHOD__, '3.3.0', 'WP_Admin_bar::render(), WP_Admin_Bar::_render_item()' ); |
487 $this->_render_item( $node ); |
568 $this->_render_item( $node ); |
488 } |
569 } |
489 |
570 |
|
571 /** |
|
572 */ |
490 public function add_menus() { |
573 public function add_menus() { |
491 // User related, aligned right. |
574 // User related, aligned right. |
492 add_action( 'admin_bar_menu', 'wp_admin_bar_my_account_menu', 0 ); |
575 add_action( 'admin_bar_menu', 'wp_admin_bar_my_account_menu', 0 ); |
493 add_action( 'admin_bar_menu', 'wp_admin_bar_search_menu', 4 ); |
576 add_action( 'admin_bar_menu', 'wp_admin_bar_search_menu', 4 ); |
494 add_action( 'admin_bar_menu', 'wp_admin_bar_my_account_item', 7 ); |
577 add_action( 'admin_bar_menu', 'wp_admin_bar_my_account_item', 7 ); |
496 // Site related. |
579 // Site related. |
497 add_action( 'admin_bar_menu', 'wp_admin_bar_sidebar_toggle', 0 ); |
580 add_action( 'admin_bar_menu', 'wp_admin_bar_sidebar_toggle', 0 ); |
498 add_action( 'admin_bar_menu', 'wp_admin_bar_wp_menu', 10 ); |
581 add_action( 'admin_bar_menu', 'wp_admin_bar_wp_menu', 10 ); |
499 add_action( 'admin_bar_menu', 'wp_admin_bar_my_sites_menu', 20 ); |
582 add_action( 'admin_bar_menu', 'wp_admin_bar_my_sites_menu', 20 ); |
500 add_action( 'admin_bar_menu', 'wp_admin_bar_site_menu', 30 ); |
583 add_action( 'admin_bar_menu', 'wp_admin_bar_site_menu', 30 ); |
501 add_action( 'admin_bar_menu', 'wp_admin_bar_updates_menu', 40 ); |
584 add_action( 'admin_bar_menu', 'wp_admin_bar_customize_menu', 40 ); |
|
585 add_action( 'admin_bar_menu', 'wp_admin_bar_updates_menu', 50 ); |
502 |
586 |
503 // Content related. |
587 // Content related. |
504 if ( ! is_network_admin() && ! is_user_admin() ) { |
588 if ( ! is_network_admin() && ! is_user_admin() ) { |
505 add_action( 'admin_bar_menu', 'wp_admin_bar_comments_menu', 60 ); |
589 add_action( 'admin_bar_menu', 'wp_admin_bar_comments_menu', 60 ); |
506 add_action( 'admin_bar_menu', 'wp_admin_bar_new_content_menu', 70 ); |
590 add_action( 'admin_bar_menu', 'wp_admin_bar_new_content_menu', 70 ); |