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_Customize_Nav_Menu_Item_Setting 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_Customize_Nav_Menu_Item_Setting, and based on these observations, apply Extract Interface, too.
| 1 | <?php |
||
| 20 | class WP_Customize_Nav_Menu_Item_Setting extends WP_Customize_Setting { |
||
| 21 | |||
| 22 | const ID_PATTERN = '/^nav_menu_item\[(?P<id>-?\d+)\]$/'; |
||
| 23 | |||
| 24 | const POST_TYPE = 'nav_menu_item'; |
||
| 25 | |||
| 26 | const TYPE = 'nav_menu_item'; |
||
| 27 | |||
| 28 | /** |
||
| 29 | * Setting type. |
||
| 30 | * |
||
| 31 | * @since 4.3.0 |
||
| 32 | * @access public |
||
| 33 | * @var string |
||
| 34 | */ |
||
| 35 | public $type = self::TYPE; |
||
| 36 | |||
| 37 | /** |
||
| 38 | * Default setting value. |
||
| 39 | * |
||
| 40 | * @since 4.3.0 |
||
| 41 | * @access public |
||
| 42 | * @var array |
||
| 43 | * |
||
| 44 | * @see wp_setup_nav_menu_item() |
||
| 45 | */ |
||
| 46 | public $default = array( |
||
| 47 | // The $menu_item_data for wp_update_nav_menu_item(). |
||
| 48 | 'object_id' => 0, |
||
| 49 | 'object' => '', // Taxonomy name. |
||
| 50 | 'menu_item_parent' => 0, // A.K.A. menu-item-parent-id; note that post_parent is different, and not included. |
||
| 51 | 'position' => 0, // A.K.A. menu_order. |
||
| 52 | 'type' => 'custom', // Note that type_label is not included here. |
||
| 53 | 'title' => '', |
||
| 54 | 'url' => '', |
||
| 55 | 'target' => '', |
||
| 56 | 'attr_title' => '', |
||
| 57 | 'description' => '', |
||
| 58 | 'classes' => '', |
||
| 59 | 'xfn' => '', |
||
| 60 | 'status' => 'publish', |
||
| 61 | 'original_title' => '', |
||
| 62 | 'nav_menu_term_id' => 0, // This will be supplied as the $menu_id arg for wp_update_nav_menu_item(). |
||
| 63 | '_invalid' => false, |
||
| 64 | ); |
||
| 65 | |||
| 66 | /** |
||
| 67 | * Default transport. |
||
| 68 | * |
||
| 69 | * @since 4.3.0 |
||
| 70 | * @since 4.5.0 Default changed to 'refresh' |
||
| 71 | * @access public |
||
| 72 | * @var string |
||
| 73 | */ |
||
| 74 | public $transport = 'refresh'; |
||
| 75 | |||
| 76 | /** |
||
| 77 | * The post ID represented by this setting instance. This is the db_id. |
||
| 78 | * |
||
| 79 | * A negative value represents a placeholder ID for a new menu not yet saved. |
||
| 80 | * |
||
| 81 | * @since 4.3.0 |
||
| 82 | * @access public |
||
| 83 | * @var int |
||
| 84 | */ |
||
| 85 | public $post_id; |
||
| 86 | |||
| 87 | /** |
||
| 88 | * Storage of pre-setup menu item to prevent wasted calls to wp_setup_nav_menu_item(). |
||
| 89 | * |
||
| 90 | * @since 4.3.0 |
||
| 91 | * @access protected |
||
| 92 | * @var array |
||
| 93 | */ |
||
| 94 | protected $value; |
||
| 95 | |||
| 96 | /** |
||
| 97 | * Previous (placeholder) post ID used before creating a new menu item. |
||
| 98 | * |
||
| 99 | * This value will be exported to JS via the customize_save_response filter |
||
| 100 | * so that JavaScript can update the settings to refer to the newly-assigned |
||
| 101 | * post ID. This value is always negative to indicate it does not refer to |
||
| 102 | * a real post. |
||
| 103 | * |
||
| 104 | * @since 4.3.0 |
||
| 105 | * @access public |
||
| 106 | * @var int |
||
| 107 | * |
||
| 108 | * @see WP_Customize_Nav_Menu_Item_Setting::update() |
||
| 109 | * @see WP_Customize_Nav_Menu_Item_Setting::amend_customize_save_response() |
||
| 110 | */ |
||
| 111 | public $previous_post_id; |
||
| 112 | |||
| 113 | /** |
||
| 114 | * When previewing or updating a menu item, this stores the previous nav_menu_term_id |
||
| 115 | * which ensures that we can apply the proper filters. |
||
| 116 | * |
||
| 117 | * @since 4.3.0 |
||
| 118 | * @access public |
||
| 119 | * @var int |
||
| 120 | */ |
||
| 121 | public $original_nav_menu_term_id; |
||
| 122 | |||
| 123 | /** |
||
| 124 | * Whether or not update() was called. |
||
| 125 | * |
||
| 126 | * @since 4.3.0 |
||
| 127 | * @access protected |
||
| 128 | * @var bool |
||
| 129 | */ |
||
| 130 | protected $is_updated = false; |
||
| 131 | |||
| 132 | /** |
||
| 133 | * Status for calling the update method, used in customize_save_response filter. |
||
| 134 | * |
||
| 135 | * See {@see 'customize_save_response'}. |
||
| 136 | * |
||
| 137 | * When status is inserted, the placeholder post ID is stored in $previous_post_id. |
||
| 138 | * When status is error, the error is stored in $update_error. |
||
| 139 | * |
||
| 140 | * @since 4.3.0 |
||
| 141 | * @access public |
||
| 142 | * @var string updated|inserted|deleted|error |
||
| 143 | * |
||
| 144 | * @see WP_Customize_Nav_Menu_Item_Setting::update() |
||
| 145 | * @see WP_Customize_Nav_Menu_Item_Setting::amend_customize_save_response() |
||
| 146 | */ |
||
| 147 | public $update_status; |
||
| 148 | |||
| 149 | /** |
||
| 150 | * Any error object returned by wp_update_nav_menu_item() when setting is updated. |
||
| 151 | * |
||
| 152 | * @since 4.3.0 |
||
| 153 | * @access public |
||
| 154 | * @var WP_Error |
||
| 155 | * |
||
| 156 | * @see WP_Customize_Nav_Menu_Item_Setting::update() |
||
| 157 | * @see WP_Customize_Nav_Menu_Item_Setting::amend_customize_save_response() |
||
| 158 | */ |
||
| 159 | public $update_error; |
||
| 160 | |||
| 161 | /** |
||
| 162 | * Constructor. |
||
| 163 | * |
||
| 164 | * Any supplied $args override class property defaults. |
||
| 165 | * |
||
| 166 | * @since 4.3.0 |
||
| 167 | * @access public |
||
| 168 | * |
||
| 169 | * @param WP_Customize_Manager $manager Bootstrap Customizer instance. |
||
| 170 | * @param string $id An specific ID of the setting. Can be a |
||
| 171 | * theme mod or option name. |
||
| 172 | * @param array $args Optional. Setting arguments. |
||
| 173 | * |
||
| 174 | * @throws Exception If $id is not valid for this setting type. |
||
| 175 | */ |
||
| 176 | public function __construct( WP_Customize_Manager $manager, $id, array $args = array() ) { |
||
| 199 | |||
| 200 | /** |
||
| 201 | * Clear the cached value when this nav menu item is updated. |
||
| 202 | * |
||
| 203 | * @since 4.3.0 |
||
| 204 | * @access public |
||
| 205 | * |
||
| 206 | * @param int $menu_id The term ID for the menu. |
||
| 207 | * @param int $menu_item_id The post ID for the menu item. |
||
| 208 | */ |
||
| 209 | public function flush_cached_value( $menu_id, $menu_item_id ) { |
||
| 215 | |||
| 216 | /** |
||
| 217 | * Get the instance data for a given nav_menu_item setting. |
||
| 218 | * |
||
| 219 | * @since 4.3.0 |
||
| 220 | * @access public |
||
| 221 | * |
||
| 222 | * @see wp_setup_nav_menu_item() |
||
| 223 | * |
||
| 224 | * @return array|false Instance data array, or false if the item is marked for deletion. |
||
| 225 | */ |
||
| 226 | public function value() { |
||
| 272 | |||
| 273 | /** |
||
| 274 | * Get original title. |
||
| 275 | * |
||
| 276 | * @since 4.7.0 |
||
| 277 | * @access protected |
||
| 278 | * |
||
| 279 | * @param object $item Nav menu item. |
||
| 280 | * @return string The original title. |
||
| 281 | */ |
||
| 282 | protected function get_original_title( $item ) { |
||
| 309 | |||
| 310 | /** |
||
| 311 | * Get type label. |
||
| 312 | * |
||
| 313 | * @since 4.7.0 |
||
| 314 | * @access protected |
||
| 315 | * |
||
| 316 | * @param object $item Nav menu item. |
||
| 317 | * @returns string The type label. |
||
| 318 | */ |
||
| 319 | protected function get_type_label( $item ) { |
||
| 341 | |||
| 342 | /** |
||
| 343 | * Ensure that the value is fully populated with the necessary properties. |
||
| 344 | * |
||
| 345 | * Translates some properties added by wp_setup_nav_menu_item() and removes others. |
||
| 346 | * |
||
| 347 | * @since 4.3.0 |
||
| 348 | * @access protected |
||
| 349 | * |
||
| 350 | * @see WP_Customize_Nav_Menu_Item_Setting::value() |
||
| 351 | */ |
||
| 352 | protected function populate_value() { |
||
| 438 | |||
| 439 | /** |
||
| 440 | * Handle previewing the setting. |
||
| 441 | * |
||
| 442 | * @since 4.3.0 |
||
| 443 | * @since 4.4.0 Added boolean return value. |
||
| 444 | * @access public |
||
| 445 | * |
||
| 446 | * @see WP_Customize_Manager::post_value() |
||
| 447 | * |
||
| 448 | * @return bool False if method short-circuited due to no-op. |
||
| 449 | */ |
||
| 450 | public function preview() { |
||
| 478 | |||
| 479 | /** |
||
| 480 | * Filters the wp_get_nav_menu_items() result to supply the previewed menu items. |
||
| 481 | * |
||
| 482 | * @since 4.3.0 |
||
| 483 | * @access public |
||
| 484 | * |
||
| 485 | * @see wp_get_nav_menu_items() |
||
| 486 | * |
||
| 487 | * @param array $items An array of menu item post objects. |
||
| 488 | * @param object $menu The menu object. |
||
| 489 | * @param array $args An array of arguments used to retrieve menu item objects. |
||
| 490 | * @return array Array of menu items, |
||
| 491 | */ |
||
| 492 | public function filter_wp_get_nav_menu_items( $items, $menu, $args ) { |
||
| 552 | |||
| 553 | /** |
||
| 554 | * Re-apply the tail logic also applied on $items by wp_get_nav_menu_items(). |
||
| 555 | * |
||
| 556 | * @since 4.3.0 |
||
| 557 | * @access public |
||
| 558 | * @static |
||
| 559 | * |
||
| 560 | * @see wp_get_nav_menu_items() |
||
| 561 | * |
||
| 562 | * @param array $items An array of menu item post objects. |
||
| 563 | * @param object $menu The menu object. |
||
| 564 | * @param array $args An array of arguments used to retrieve menu item objects. |
||
| 565 | * @return array Array of menu items, |
||
| 566 | */ |
||
| 567 | public static function sort_wp_get_nav_menu_items( $items, $menu, $args ) { |
||
| 589 | |||
| 590 | /** |
||
| 591 | * Get the value emulated into a WP_Post and set up as a nav_menu_item. |
||
| 592 | * |
||
| 593 | * @since 4.3.0 |
||
| 594 | * @access public |
||
| 595 | * |
||
| 596 | * @return WP_Post With wp_setup_nav_menu_item() applied. |
||
| 597 | */ |
||
| 598 | public function value_as_wp_post_nav_menu_item() { |
||
| 654 | |||
| 655 | /** |
||
| 656 | * Sanitize an input. |
||
| 657 | * |
||
| 658 | * Note that parent::sanitize() erroneously does wp_unslash() on $value, but |
||
| 659 | * we remove that in this override. |
||
| 660 | * |
||
| 661 | * @since 4.3.0 |
||
| 662 | * @access public |
||
| 663 | * |
||
| 664 | * @param array $menu_item_value The value to sanitize. |
||
| 665 | * @return array|false|null Null if an input isn't valid. False if it is marked for deletion. |
||
| 666 | * Otherwise the sanitized value. |
||
| 667 | */ |
||
| 668 | public function sanitize( $menu_item_value ) { |
||
| 735 | |||
| 736 | /** |
||
| 737 | * Creates/updates the nav_menu_item post for this setting. |
||
| 738 | * |
||
| 739 | * Any created menu items will have their assigned post IDs exported to the client |
||
| 740 | * via the {@see 'customize_save_response'} filter. Likewise, any errors will be |
||
| 741 | * exported to the client via the customize_save_response() filter. |
||
| 742 | * |
||
| 743 | * To delete a menu, the client can send false as the value. |
||
| 744 | * |
||
| 745 | * @since 4.3.0 |
||
| 746 | * @access protected |
||
| 747 | * |
||
| 748 | * @see wp_update_nav_menu_item() |
||
| 749 | * |
||
| 750 | * @param array|false $value The menu item array to update. If false, then the menu item will be deleted |
||
| 751 | * entirely. See WP_Customize_Nav_Menu_Item_Setting::$default for what the value |
||
| 752 | * should consist of. |
||
| 753 | * @return null|void |
||
| 754 | */ |
||
| 755 | protected function update( $value ) { |
||
| 876 | |||
| 877 | /** |
||
| 878 | * Export data for the JS client. |
||
| 879 | * |
||
| 880 | * @since 4.3.0 |
||
| 881 | * @access public |
||
| 882 | * |
||
| 883 | * @see WP_Customize_Nav_Menu_Item_Setting::update() |
||
| 884 | * |
||
| 885 | * @param array $data Additional information passed back to the 'saved' event on `wp.customize`. |
||
| 886 | * @return array Save response data. |
||
| 887 | */ |
||
| 888 | public function amend_customize_save_response( $data ) { |
||
| 901 | } |
||
| 902 |
Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.
Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..