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 Jetpack_Likes 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 Jetpack_Likes, and based on these observations, apply Extract Interface, too.
| 1 | <?php |
||
| 25 | class Jetpack_Likes { |
||
| 26 | public static function init() { |
||
| 27 | static $instance = NULL; |
||
| 28 | |||
| 29 | if ( ! $instance ) { |
||
| 30 | $instance = new Jetpack_Likes; |
||
| 31 | } |
||
| 32 | |||
| 33 | return $instance; |
||
| 34 | } |
||
| 35 | |||
| 36 | function __construct() { |
||
| 37 | $this->in_jetpack = ( defined( 'IS_WPCOM' ) && IS_WPCOM ) ? false : true; |
||
|
|
|||
| 38 | $this->settings = new Jetpack_Likes_Settings(); |
||
| 39 | |||
| 40 | add_action( 'init', array( &$this, 'action_init' ) ); |
||
| 41 | add_action( 'admin_init', array( $this, 'admin_init' ) ); |
||
| 42 | |||
| 43 | if ( $this->in_jetpack ) { |
||
| 44 | add_action( 'jetpack_activate_module_likes', array( $this, 'set_social_notifications_like' ) ); |
||
| 45 | add_action( 'jetpack_deactivate_module_likes', array( $this, 'delete_social_notifications_like' ) ); |
||
| 46 | |||
| 47 | Jetpack::enable_module_configurable( __FILE__ ); |
||
| 48 | Jetpack::module_configuration_load( __FILE__, array( $this, 'configuration_redirect' ) ); |
||
| 49 | |||
| 50 | add_action( 'admin_print_scripts-settings_page_sharing', array( &$this, 'load_jp_css' ) ); |
||
| 51 | add_filter( 'sharing_show_buttons_on_row_start', array( $this, 'configuration_target_area' ) ); |
||
| 52 | |||
| 53 | $active = Jetpack::get_active_modules(); |
||
| 54 | |||
| 55 | View Code Duplication | if ( ! in_array( 'sharedaddy', $active ) && ! in_array( 'publicize', $active ) ) { |
|
| 56 | // we don't have a sharing page yet |
||
| 57 | add_action( 'admin_menu', array( $this->settings, 'sharing_menu' ) ); |
||
| 58 | } |
||
| 59 | |||
| 60 | View Code Duplication | if ( in_array( 'publicize', $active ) && ! in_array( 'sharedaddy', $active ) ) { |
|
| 61 | // we have a sharing page but not the global options area |
||
| 62 | add_action( 'pre_admin_screen_sharing', array( $this->settings, 'sharing_block' ), 20 ); |
||
| 63 | add_action( 'pre_admin_screen_sharing', array( $this->settings, 'updated_message' ), -10 ); |
||
| 64 | } |
||
| 65 | |||
| 66 | View Code Duplication | if( ! in_array( 'sharedaddy', $active ) ) { |
|
| 67 | add_action( 'admin_init', array( $this->settings, 'process_update_requests_if_sharedaddy_not_loaded' ) ); |
||
| 68 | add_action( 'sharing_global_options', array( $this->settings, 'admin_settings_showbuttonon_init' ), 19 ); |
||
| 69 | add_action( 'sharing_admin_update', array( $this->settings, 'admin_settings_showbuttonon_callback' ), 19 ); |
||
| 70 | add_action( 'admin_init', array( $this->settings, 'add_meta_box' ) ); |
||
| 71 | } else { |
||
| 72 | add_filter( 'sharing_meta_box_title', array( $this->settings, 'add_likes_to_sharing_meta_box_title' ) ); |
||
| 73 | add_action( 'start_sharing_meta_box_content', array( $this->settings, 'meta_box_content' ) ); |
||
| 74 | } |
||
| 75 | } else { // wpcom |
||
| 76 | add_action( 'wpmu_new_blog', array( $this, 'enable_comment_likes' ), 10, 1 ); |
||
| 77 | add_action( 'admin_init', array( $this->settings, 'add_meta_box' ) ); |
||
| 78 | add_action( 'end_likes_meta_box_content', array( $this->settings, 'sharing_meta_box_content' ) ); |
||
| 79 | add_filter( 'likes_meta_box_title', array( $this->settings, 'add_likes_to_sharing_meta_box_title' ) ); |
||
| 80 | } |
||
| 81 | |||
| 82 | add_action( 'admin_init', array( $this, 'admin_discussion_likes_settings_init' ) ); // Likes notifications |
||
| 83 | |||
| 84 | add_action( 'admin_bar_menu', array( $this, 'admin_bar_likes' ), 60 ); |
||
| 85 | |||
| 86 | add_action( 'wp_enqueue_scripts', array( $this, 'load_styles_register_scripts' ) ); |
||
| 87 | |||
| 88 | add_action( 'save_post', array( $this->settings, 'meta_box_save' ) ); |
||
| 89 | add_action( 'edit_attachment', array( $this->settings, 'meta_box_save' ) ); |
||
| 90 | add_action( 'sharing_global_options', array( $this->settings, 'admin_settings_init' ), 20 ); |
||
| 91 | add_action( 'sharing_admin_update', array( $this->settings, 'admin_settings_callback' ), 20 ); |
||
| 92 | } |
||
| 93 | |||
| 94 | /** |
||
| 95 | * Set the social_notifications_like option to `on` when the Likes module is activated. |
||
| 96 | * |
||
| 97 | * @since 3.7.0 |
||
| 98 | * |
||
| 99 | * @return null |
||
| 100 | */ |
||
| 101 | function set_social_notifications_like() { |
||
| 102 | update_option( 'social_notifications_like', 'on' ); |
||
| 103 | } |
||
| 104 | |||
| 105 | /** |
||
| 106 | * Delete the social_notifications_like option that was set to `on` on module activation. |
||
| 107 | * |
||
| 108 | * @since 3.7.0 |
||
| 109 | * |
||
| 110 | * @return null |
||
| 111 | */ |
||
| 112 | function delete_social_notifications_like() { |
||
| 113 | delete_option( 'social_notifications_like' ); |
||
| 114 | } |
||
| 115 | |||
| 116 | /** |
||
| 117 | * Redirects to the likes section of the sharing page. |
||
| 118 | */ |
||
| 119 | function configuration_redirect() { |
||
| 120 | wp_safe_redirect( admin_url( 'options-general.php?page=sharing#likes' ) ); |
||
| 121 | die(); |
||
| 122 | } |
||
| 123 | |||
| 124 | /** |
||
| 125 | * Loads Jetpack's CSS on the sharing page so we can use .jetpack-targetable |
||
| 126 | */ |
||
| 127 | function load_jp_css() { |
||
| 128 | // Do we really need `admin_styles`? With the new admin UI, it's breaking some bits. |
||
| 129 | // Jetpack::init()->admin_styles(); |
||
| 130 | } |
||
| 131 | |||
| 132 | /** |
||
| 133 | * Load scripts and styles for front end. |
||
| 134 | * @return null |
||
| 135 | */ |
||
| 136 | function load_styles_register_scripts() { |
||
| 137 | if ( $this->in_jetpack ) { |
||
| 138 | wp_enqueue_style( 'jetpack_likes', plugins_url( 'likes/style.css', __FILE__ ), array(), JETPACK__VERSION ); |
||
| 139 | $this->register_scripts(); |
||
| 140 | } |
||
| 141 | } |
||
| 142 | |||
| 143 | /** |
||
| 144 | * Stub for is_likes_visible, since some themes were calling it directly from this class |
||
| 145 | * |
||
| 146 | * @deprecated 5.4 |
||
| 147 | * @return bool |
||
| 148 | */ |
||
| 149 | function is_likes_visible() { |
||
| 150 | _deprecated_function( __METHOD__, 'jetpack-5.4', 'Jetpack_Likes_Settings()->is_likes_visible' ); |
||
| 151 | |||
| 152 | $settings = new Jetpack_Likes_Settings(); |
||
| 153 | return $settings->is_likes_visible(); |
||
| 154 | } |
||
| 155 | |||
| 156 | /** |
||
| 157 | * Adds in the jetpack-targetable class so when we visit sharing#likes our like settings get highlighted by a yellow box |
||
| 158 | * @param string $html row heading for the sharedaddy "which page" setting |
||
| 159 | * @return string html with the jetpack-targetable class and likes id. tbody gets closed after the like settings |
||
| 160 | */ |
||
| 161 | function configuration_target_area( $html = '' ) { |
||
| 165 | |||
| 166 | /** |
||
| 167 | * WordPress.com: Metabox option for sharing (sharedaddy will handle this on the JP blog) |
||
| 168 | */ |
||
| 169 | function sharing_meta_box_content( $post ) { |
||
| 170 | $post_id = ! empty( $post->ID ) ? (int) $post->ID : get_the_ID(); |
||
| 171 | $disabled = get_post_meta( $post_id, 'sharing_disabled', true ); ?> |
||
| 172 | <p> |
||
| 173 | <label for="wpl_enable_post_sharing"> |
||
| 180 | |||
| 181 | /** |
||
| 182 | * Options to be added to the discussion page (see also admin_settings_init, etc below for Sharing settings page) |
||
| 183 | */ |
||
| 184 | |||
| 185 | View Code Duplication | function admin_discussion_likes_settings_init() { |
|
| 192 | |||
| 193 | function admin_discussion_likes_settings_section() { |
||
| 213 | |||
| 214 | function admin_likes_get_option( $option ) { |
||
| 223 | |||
| 224 | function admin_discussion_likes_settings_field() { |
||
| 230 | |||
| 231 | function admin_discussion_likes_settings_validate( $input ) { |
||
| 239 | |||
| 240 | function admin_init() { |
||
| 248 | |||
| 249 | function action_init() { |
||
| 280 | |||
| 281 | /** |
||
| 282 | * Register scripts |
||
| 283 | */ |
||
| 284 | function register_scripts() { |
||
| 313 | |||
| 314 | /** |
||
| 315 | * Load the CSS needed for the wp-admin area. |
||
| 316 | */ |
||
| 317 | function load_admin_css() { |
||
| 356 | |||
| 357 | /** |
||
| 358 | * Load the JS required for loading the like counts. |
||
| 359 | */ |
||
| 360 | function enqueue_admin_scripts() { |
||
| 388 | |||
| 389 | /** |
||
| 390 | * Add "Likes" column data to the post edit table in wp-admin. |
||
| 391 | * |
||
| 392 | * @param string $column_name |
||
| 393 | * @param int $post_id |
||
| 394 | */ |
||
| 395 | function likes_edit_column( $column_name, $post_id ) { |
||
| 411 | |||
| 412 | /** |
||
| 413 | * Add a "Likes" column header to the post edit table in wp-admin. |
||
| 414 | * |
||
| 415 | * @param array $columns |
||
| 416 | * @return array |
||
| 417 | */ |
||
| 418 | function add_like_count_column( $columns ) { |
||
| 427 | |||
| 428 | function post_likes( $content ) { |
||
| 473 | |||
| 474 | function post_flair_service_enabled_like( $classes ) { |
||
| 478 | |||
| 479 | function is_admin_bar_button_visible() { |
||
| 505 | |||
| 506 | function admin_bar_likes() { |
||
| 545 | } |
||
| 546 | |||
| 548 |
In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:
Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion: