Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.
Common duplication problems, and corresponding solutions are:
Complex classes like WP_Admin_Bar often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.
Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.
While breaking up the class, it is a good idea to analyze how other classes use WP_Admin_Bar, and based on these observations, apply Extract Interface, too.
| 1 | <?php |
||
| 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 ) { |
||
| 34 | |||
| 35 | /** |
||
| 36 | * @access public |
||
| 37 | */ |
||
| 38 | public function initialize() { |
||
| 83 | |||
| 84 | /** |
||
| 85 | * @param array $node |
||
| 86 | */ |
||
| 87 | public function add_menu( $node ) { |
||
| 90 | |||
| 91 | /** |
||
| 92 | * @param string $id |
||
| 93 | */ |
||
| 94 | public function remove_menu( $id ) { |
||
| 97 | |||
| 98 | /** |
||
| 99 | * Adds a node to the menu. |
||
| 100 | * |
||
| 101 | * @since 3.1.0 |
||
| 102 | * @since 4.5.0 Added the ability to pass 'lang' and 'dir' meta data. |
||
| 103 | * @access public |
||
| 104 | * |
||
| 105 | * @param array $args { |
||
| 106 | * Arguments for adding a node. |
||
| 107 | * |
||
| 108 | * @type string $id ID of the item. |
||
| 109 | * @type string $title Title of the node. |
||
| 110 | * @type string $parent Optional. ID of the parent node. |
||
| 111 | * @type string $href Optional. Link for the item. |
||
| 112 | * @type bool $group Optional. Whether or not the node is a group. Default false. |
||
| 113 | * @type array $meta Meta data including the following keys: 'html', 'class', 'rel', 'lang', 'dir', |
||
| 114 | * 'onclick', 'target', 'title', 'tabindex'. Default empty. |
||
| 115 | * } |
||
| 116 | */ |
||
| 117 | public function add_node( $args ) { |
||
| 167 | |||
| 168 | /** |
||
| 169 | * @param array $args |
||
| 170 | */ |
||
| 171 | final protected function _set_node( $args ) { |
||
| 174 | |||
| 175 | /** |
||
| 176 | * Gets a node. |
||
| 177 | * |
||
| 178 | * @param string $id |
||
| 179 | * @return object Node. |
||
|
|
|||
| 180 | */ |
||
| 181 | final public function get_node( $id ) { |
||
| 185 | |||
| 186 | /** |
||
| 187 | * @param string $id |
||
| 188 | * @return object|void |
||
| 189 | */ |
||
| 190 | final protected function _get_node( $id ) { |
||
| 200 | |||
| 201 | /** |
||
| 202 | * @return array|void |
||
| 203 | */ |
||
| 204 | final public function get_nodes() { |
||
| 213 | |||
| 214 | /** |
||
| 215 | * @return array|void |
||
| 216 | */ |
||
| 217 | final protected function _get_nodes() { |
||
| 223 | |||
| 224 | /** |
||
| 225 | * Add a group to a menu node. |
||
| 226 | * |
||
| 227 | * @since 3.3.0 |
||
| 228 | * |
||
| 229 | * @param array $args { |
||
| 230 | * Array of arguments for adding a group. |
||
| 231 | * |
||
| 232 | * @type string $id ID of the item. |
||
| 233 | * @type string $parent Optional. ID of the parent node. Default 'root'. |
||
| 234 | * @type array $meta Meta data for the group including the following keys: |
||
| 235 | * 'class', 'onclick', 'target', and 'title'. |
||
| 236 | * } |
||
| 237 | */ |
||
| 238 | final public function add_group( $args ) { |
||
| 243 | |||
| 244 | /** |
||
| 245 | * Remove a node. |
||
| 246 | * |
||
| 247 | * @param string $id The ID of the item. |
||
| 248 | */ |
||
| 249 | public function remove_node( $id ) { |
||
| 252 | |||
| 253 | /** |
||
| 254 | * @param string $id |
||
| 255 | */ |
||
| 256 | final protected function _unset_node( $id ) { |
||
| 259 | |||
| 260 | /** |
||
| 261 | * @access public |
||
| 262 | */ |
||
| 263 | public function render() { |
||
| 268 | |||
| 269 | /** |
||
| 270 | * @return object|void |
||
| 271 | */ |
||
| 272 | final protected function _bind() { |
||
| 392 | |||
| 393 | /** |
||
| 394 | * |
||
| 395 | * @global bool $is_IE |
||
| 396 | * @param object $root |
||
| 397 | */ |
||
| 398 | final protected function _render( $root ) { |
||
| 432 | |||
| 433 | /** |
||
| 434 | * @param object $node |
||
| 435 | */ |
||
| 436 | final protected function _render_container( $node ) { |
||
| 446 | |||
| 447 | /** |
||
| 448 | * @param object $node |
||
| 449 | */ |
||
| 450 | final protected function _render_group( $node ) { |
||
| 469 | |||
| 470 | /** |
||
| 471 | * @param object $node |
||
| 472 | */ |
||
| 473 | final protected function _render_item( $node ) { |
||
| 474 | if ( $node->type != 'item' ) |
||
| 475 | return; |
||
| 476 | |||
| 477 | $is_parent = ! empty( $node->children ); |
||
| 478 | $has_link = ! empty( $node->href ); |
||
| 479 | |||
| 480 | // Allow only numeric values, then casted to integers, and allow a tabindex value of `0` for a11y. |
||
| 481 | $tabindex = ( isset( $node->meta['tabindex'] ) && is_numeric( $node->meta['tabindex'] ) ) ? (int) $node->meta['tabindex'] : ''; |
||
| 482 | $aria_attributes = ( '' !== $tabindex ) ? ' tabindex="' . $tabindex . '"' : ''; |
||
| 483 | |||
| 484 | $menuclass = ''; |
||
| 485 | |||
| 486 | if ( $is_parent ) { |
||
| 487 | $menuclass = 'menupop '; |
||
| 488 | $aria_attributes .= ' aria-haspopup="true"'; |
||
| 489 | } |
||
| 490 | |||
| 491 | if ( ! empty( $node->meta['class'] ) ) |
||
| 492 | $menuclass .= $node->meta['class']; |
||
| 493 | |||
| 494 | if ( $menuclass ) |
||
| 495 | $menuclass = ' class="' . esc_attr( trim( $menuclass ) ) . '"'; |
||
| 496 | |||
| 497 | ?> |
||
| 498 | |||
| 499 | <li id="<?php echo esc_attr( 'wp-admin-bar-' . $node->id ); ?>"<?php echo $menuclass; ?>><?php |
||
| 500 | if ( $has_link ): |
||
| 501 | ?><a class="ab-item"<?php echo $aria_attributes; ?> href="<?php echo esc_url( $node->href ) ?>"<?php |
||
| 502 | if ( ! empty( $node->meta['onclick'] ) ) : |
||
| 503 | ?> onclick="<?php echo esc_js( $node->meta['onclick'] ); ?>"<?php |
||
| 504 | endif; |
||
| 505 | if ( ! empty( $node->meta['target'] ) ) : |
||
| 506 | ?> target="<?php echo esc_attr( $node->meta['target'] ); ?>"<?php |
||
| 507 | endif; |
||
| 508 | View Code Duplication | if ( ! empty( $node->meta['title'] ) ) : |
|
| 509 | ?> title="<?php echo esc_attr( $node->meta['title'] ); ?>"<?php |
||
| 510 | endif; |
||
| 511 | View Code Duplication | if ( ! empty( $node->meta['rel'] ) ) : |
|
| 512 | ?> rel="<?php echo esc_attr( $node->meta['rel'] ); ?>"<?php |
||
| 513 | endif; |
||
| 514 | View Code Duplication | if ( ! empty( $node->meta['lang'] ) ) : |
|
| 515 | ?> lang="<?php echo esc_attr( $node->meta['lang'] ); ?>"<?php |
||
| 516 | endif; |
||
| 517 | View Code Duplication | if ( ! empty( $node->meta['dir'] ) ) : |
|
| 518 | ?> dir="<?php echo esc_attr( $node->meta['dir'] ); ?>"<?php |
||
| 519 | endif; |
||
| 520 | ?>><?php |
||
| 521 | else: |
||
| 522 | ?><div class="ab-item ab-empty-item"<?php echo $aria_attributes; |
||
| 523 | View Code Duplication | if ( ! empty( $node->meta['title'] ) ) : |
|
| 524 | ?> title="<?php echo esc_attr( $node->meta['title'] ); ?>"<?php |
||
| 525 | endif; |
||
| 526 | View Code Duplication | if ( ! empty( $node->meta['lang'] ) ) : |
|
| 527 | ?> lang="<?php echo esc_attr( $node->meta['lang'] ); ?>"<?php |
||
| 528 | endif; |
||
| 529 | View Code Duplication | if ( ! empty( $node->meta['dir'] ) ) : |
|
| 530 | ?> dir="<?php echo esc_attr( $node->meta['dir'] ); ?>"<?php |
||
| 531 | endif; |
||
| 532 | ?>><?php |
||
| 533 | endif; |
||
| 534 | |||
| 535 | echo $node->title; |
||
| 536 | |||
| 537 | if ( $has_link ) : |
||
| 538 | ?></a><?php |
||
| 539 | else: |
||
| 540 | ?></div><?php |
||
| 541 | endif; |
||
| 542 | |||
| 543 | if ( $is_parent ) : |
||
| 544 | ?><div class="ab-sub-wrapper"><?php |
||
| 545 | foreach ( $node->children as $group ) { |
||
| 546 | $this->_render_group( $group ); |
||
| 547 | } |
||
| 548 | ?></div><?php |
||
| 549 | endif; |
||
| 550 | |||
| 551 | if ( ! empty( $node->meta['html'] ) ) |
||
| 552 | echo $node->meta['html']; |
||
| 553 | |||
| 554 | ?> |
||
| 555 | </li><?php |
||
| 556 | } |
||
| 557 | |||
| 558 | /** |
||
| 559 | * @param string $id Unused. |
||
| 560 | * @param object $node |
||
| 561 | */ |
||
| 562 | public function recursive_render( $id, $node ) { |
||
| 566 | |||
| 567 | /** |
||
| 568 | * @access public |
||
| 569 | */ |
||
| 570 | public function add_menus() { |
||
| 600 | } |
||
| 601 |
This check compares the return type specified in the
@returnannotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.