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_Carousel 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_Carousel, and based on these observations, apply Extract Interface, too.
| 1 | <?php |
||
| 17 | class Jetpack_Carousel { |
||
| 18 | |||
| 19 | public $prebuilt_widths = array( 370, 700, 1000, 1200, 1400, 2000 ); |
||
| 20 | |||
| 21 | public $first_run = true; |
||
| 22 | |||
| 23 | public $in_gallery = false; |
||
| 24 | |||
| 25 | public $in_jetpack = true; |
||
| 26 | |||
| 27 | function __construct() { |
||
| 30 | |||
| 31 | function init() { |
||
| 76 | |||
| 77 | function maybe_disable_jp_carousel() { |
||
| 89 | |||
| 90 | function jetpack_configuration_load() { |
||
| 94 | |||
| 95 | function asset_version( $version ) { |
||
| 107 | |||
| 108 | function display_bail_message( $output= '' ) { |
||
| 117 | |||
| 118 | function enqueue_assets( $output ) { |
||
| 119 | if ( |
||
| 120 | ! empty( $output ) && |
||
| 121 | /** |
||
| 122 | * Allow third-party plugins or themes to force-enable Carousel. |
||
| 123 | * |
||
| 124 | * @module carousel |
||
| 125 | * |
||
| 126 | * @since 1.9.0 |
||
| 127 | * |
||
| 128 | * @param bool false Should we force enable Carousel? Default to false. |
||
| 129 | */ |
||
| 130 | ! apply_filters( 'jp_carousel_force_enable', false ) |
||
| 131 | ) { |
||
| 132 | // Bail because someone is overriding the [gallery] shortcode. |
||
| 133 | remove_filter( 'gallery_style', array( $this, 'add_data_to_container' ) ); |
||
| 134 | remove_filter( 'wp_get_attachment_image_attributes', array( $this, 'add_data_to_images' ) ); |
||
| 135 | // Display message that carousel has bailed, if user is super_admin, and if we're not on WordPress.com. |
||
| 136 | if ( |
||
| 137 | is_super_admin() && |
||
| 138 | ! ( defined( 'IS_WPCOM' ) && IS_WPCOM ) |
||
| 139 | ) { |
||
| 140 | add_filter( 'post_gallery', array( $this, 'display_bail_message' ) ); |
||
| 141 | } |
||
| 142 | return $output; |
||
| 143 | } |
||
| 144 | |||
| 145 | /** |
||
| 146 | * Fires when thumbnails are shown in Carousel. |
||
| 147 | * |
||
| 148 | * @module carousel |
||
| 149 | * |
||
| 150 | * @since 1.6.0 |
||
| 151 | **/ |
||
| 152 | do_action( 'jp_carousel_thumbnails_shown' ); |
||
| 153 | |||
| 154 | if ( $this->first_run ) { |
||
| 155 | wp_enqueue_script( 'jetpack-carousel', plugins_url( 'jetpack-carousel.js', __FILE__ ), array( 'jquery.spin' ), $this->asset_version( '20160325' ), true ); |
||
| 156 | |||
| 157 | // Note: using home_url() instead of admin_url() for ajaxurl to be sure to get same domain on wpcom when using mapped domains (also works on self-hosted) |
||
| 158 | // Also: not hardcoding path since there is no guarantee site is running on site root in self-hosted context. |
||
| 159 | $is_logged_in = is_user_logged_in(); |
||
| 160 | $current_user = wp_get_current_user(); |
||
| 161 | $comment_registration = intval( get_option( 'comment_registration' ) ); |
||
| 162 | $require_name_email = intval( get_option( 'require_name_email' ) ); |
||
| 163 | $localize_strings = array( |
||
| 164 | 'widths' => $this->prebuilt_widths, |
||
| 165 | 'is_logged_in' => $is_logged_in, |
||
| 166 | 'lang' => strtolower( substr( get_locale(), 0, 2 ) ), |
||
| 167 | 'ajaxurl' => set_url_scheme( admin_url( 'admin-ajax.php' ) ), |
||
| 168 | 'nonce' => wp_create_nonce( 'carousel_nonce' ), |
||
| 169 | 'display_exif' => $this->test_1or0_option( Jetpack_Options::get_option_and_ensure_autoload( 'carousel_display_exif', true ) ), |
||
| 170 | 'display_geo' => $this->test_1or0_option( Jetpack_Options::get_option_and_ensure_autoload( 'carousel_display_geo', true ) ), |
||
| 171 | 'background_color' => $this->carousel_background_color_sanitize( Jetpack_Options::get_option_and_ensure_autoload( 'carousel_background_color', '' ) ), |
||
| 172 | 'comment' => __( 'Comment', 'jetpack' ), |
||
| 173 | 'post_comment' => __( 'Post Comment', 'jetpack' ), |
||
| 174 | 'write_comment' => __( 'Write a Comment...', 'jetpack' ), |
||
| 175 | 'loading_comments' => __( 'Loading Comments...', 'jetpack' ), |
||
| 176 | 'download_original' => sprintf( __( 'View full size <span class="photo-size">%1$s<span class="photo-size-times">×</span>%2$s</span>', 'jetpack' ), '{0}', '{1}' ), |
||
| 177 | 'no_comment_text' => __( 'Please be sure to submit some text with your comment.', 'jetpack' ), |
||
| 178 | 'no_comment_email' => __( 'Please provide an email address to comment.', 'jetpack' ), |
||
| 179 | 'no_comment_author' => __( 'Please provide your name to comment.', 'jetpack' ), |
||
| 180 | 'comment_post_error' => __( 'Sorry, but there was an error posting your comment. Please try again later.', 'jetpack' ), |
||
| 181 | 'comment_approved' => __( 'Your comment was approved.', 'jetpack' ), |
||
| 182 | 'comment_unapproved' => __( 'Your comment is in moderation.', 'jetpack' ), |
||
| 183 | 'camera' => __( 'Camera', 'jetpack' ), |
||
| 184 | 'aperture' => __( 'Aperture', 'jetpack' ), |
||
| 185 | 'shutter_speed' => __( 'Shutter Speed', 'jetpack' ), |
||
| 186 | 'focal_length' => __( 'Focal Length', 'jetpack' ), |
||
| 187 | 'comment_registration' => $comment_registration, |
||
| 188 | 'require_name_email' => $require_name_email, |
||
| 189 | /** This action is documented in core/src/wp-includes/link-template.php */ |
||
| 190 | 'login_url' => wp_login_url( apply_filters( 'the_permalink', get_permalink() ) ), |
||
| 191 | ); |
||
| 192 | |||
| 193 | if ( ! isset( $localize_strings['jetpack_comments_iframe_src'] ) || empty( $localize_strings['jetpack_comments_iframe_src'] ) ) { |
||
| 194 | // We're not using Comments after all, so fallback to standard local comments. |
||
| 195 | |||
| 196 | if ( $is_logged_in ) { |
||
| 197 | $localize_strings['local_comments_commenting_as'] = '<p id="jp-carousel-commenting-as">' . sprintf( __( 'Commenting as %s', 'jetpack' ), $current_user->data->display_name ) . '</p>'; |
||
| 198 | } else { |
||
| 199 | if ( $comment_registration ) { |
||
| 200 | $localize_strings['local_comments_commenting_as'] = '<p id="jp-carousel-commenting-as">' . __( 'You must be <a href="#" class="jp-carousel-comment-login">logged in</a> to post a comment.', 'jetpack' ) . '</p>'; |
||
| 201 | } else { |
||
| 202 | $required = ( $require_name_email ) ? __( '%s (Required)', 'jetpack' ) : '%s'; |
||
| 203 | $localize_strings['local_comments_commenting_as'] = '' |
||
| 204 | . '<fieldset><label for="email">' . sprintf( $required, __( 'Email', 'jetpack' ) ) . '</label> ' |
||
| 205 | . '<input type="text" name="email" class="jp-carousel-comment-form-field jp-carousel-comment-form-text-field" id="jp-carousel-comment-form-email-field" /></fieldset>' |
||
| 206 | . '<fieldset><label for="author">' . sprintf( $required, __( 'Name', 'jetpack' ) ) . '</label> ' |
||
| 207 | . '<input type="text" name="author" class="jp-carousel-comment-form-field jp-carousel-comment-form-text-field" id="jp-carousel-comment-form-author-field" /></fieldset>' |
||
| 208 | . '<fieldset><label for="url">' . __( 'Website', 'jetpack' ) . '</label> ' |
||
| 209 | . '<input type="text" name="url" class="jp-carousel-comment-form-field jp-carousel-comment-form-text-field" id="jp-carousel-comment-form-url-field" /></fieldset>'; |
||
| 210 | } |
||
| 211 | } |
||
| 212 | } |
||
| 213 | |||
| 214 | /** |
||
| 215 | * Handle WP stats for images in full-screen. |
||
| 216 | * Build string with tracking info. |
||
| 217 | */ |
||
| 218 | |||
| 219 | /** |
||
| 220 | * Filter if Jetpack should enable stats collection on carousel views |
||
| 221 | * |
||
| 222 | * @module carousel |
||
| 223 | * |
||
| 224 | * @since 4.3.2 |
||
| 225 | * |
||
| 226 | * @param bool Enable Jetpack Carousel stat collection. Default false. |
||
| 227 | */ |
||
| 228 | if ( apply_filters( 'jetpack_enable_carousel_stats', false ) && in_array( 'stats', Jetpack::get_active_modules() ) && ! Jetpack::is_development_mode() ) { |
||
| 229 | $localize_strings['stats'] = 'blog=' . Jetpack_Options::get_option( 'id' ) . '&host=' . parse_url( get_option( 'home' ), PHP_URL_HOST ) . '&v=ext&j=' . JETPACK__API_VERSION . ':' . JETPACK__VERSION; |
||
| 230 | |||
| 231 | // Set the stats as empty if user is logged in but logged-in users shouldn't be tracked. |
||
| 232 | View Code Duplication | if ( is_user_logged_in() && function_exists( 'stats_get_options' ) ) { |
|
| 233 | $stats_options = stats_get_options(); |
||
| 234 | $track_loggedin_users = isset( $stats_options['reg_users'] ) ? (bool) $stats_options['reg_users'] : false; |
||
| 235 | |||
| 236 | if ( ! $track_loggedin_users ) { |
||
| 237 | $localize_strings['stats'] = ''; |
||
| 238 | } |
||
| 239 | } |
||
| 240 | } |
||
| 241 | |||
| 242 | /** |
||
| 243 | * Filter the strings passed to the Carousel's js file. |
||
| 244 | * |
||
| 245 | * @module carousel |
||
| 246 | * |
||
| 247 | * @since 1.6.0 |
||
| 248 | * |
||
| 249 | * @param array $localize_strings Array of strings passed to the Jetpack js file. |
||
| 250 | */ |
||
| 251 | $localize_strings = apply_filters( 'jp_carousel_localize_strings', $localize_strings ); |
||
| 252 | wp_localize_script( 'jetpack-carousel', 'jetpackCarouselStrings', $localize_strings ); |
||
| 253 | if( is_rtl() ) { |
||
| 254 | wp_enqueue_style( 'jetpack-carousel', plugins_url( '/rtl/jetpack-carousel-rtl.css', __FILE__ ), array(), $this->asset_version( '20120629' ) ); |
||
| 255 | } else { |
||
| 256 | wp_enqueue_style( 'jetpack-carousel', plugins_url( 'jetpack-carousel.css', __FILE__ ), array(), $this->asset_version( '20120629' ) ); |
||
| 257 | } |
||
| 258 | |||
| 259 | wp_register_style( 'jetpack-carousel-ie8fix', plugins_url( 'jetpack-carousel-ie8fix.css', __FILE__ ), array(), $this->asset_version( '20121024' ) ); |
||
| 260 | $GLOBALS['wp_styles']->add_data( 'jetpack-carousel-ie8fix', 'conditional', 'lte IE 8' ); |
||
| 261 | wp_enqueue_style( 'jetpack-carousel-ie8fix' ); |
||
| 262 | |||
| 263 | /** |
||
| 264 | * Fires after carousel assets are enqueued for the first time. |
||
| 265 | * Allows for adding additional assets to the carousel page. |
||
| 266 | * |
||
| 267 | * @module carousel |
||
| 268 | * |
||
| 269 | * @since 1.6.0 |
||
| 270 | * |
||
| 271 | * @param bool $first_run First load if Carousel on the page. |
||
| 272 | * @param array $localized_strings Array of strings passed to the Jetpack js file. |
||
| 273 | */ |
||
| 274 | do_action( 'jp_carousel_enqueue_assets', $this->first_run, $localize_strings ); |
||
| 275 | |||
| 276 | $this->first_run = false; |
||
| 277 | } |
||
| 278 | |||
| 279 | return $output; |
||
| 280 | } |
||
| 281 | |||
| 282 | function set_in_gallery( $output ) { |
||
| 286 | |||
| 287 | function add_data_to_images( $attr, $attachment = null ) { |
||
| 354 | |||
| 355 | function add_data_to_container( $html ) { |
||
| 385 | |||
| 386 | function get_attachment_comments() { |
||
| 439 | |||
| 440 | function post_attachment_comment() { |
||
| 531 | |||
| 532 | function register_settings() { |
||
| 550 | |||
| 551 | // Fulfill the settings section callback requirement by returning nothing |
||
| 552 | function carousel_section_callback() { |
||
| 555 | |||
| 556 | function test_1or0_option( $value, $default_to_1 = true ) { |
||
| 564 | |||
| 565 | function sanitize_1or0_option( $value ) { |
||
| 568 | |||
| 569 | function settings_checkbox($name, $label_text, $extra_text = '', $default_to_checked = true) { |
||
| 581 | |||
| 582 | function settings_select($name, $values, $extra_text = '') { |
||
| 598 | |||
| 599 | function carousel_display_exif_callback() { |
||
| 602 | |||
| 603 | function carousel_display_exif_sanitize( $value ) { |
||
| 606 | |||
| 607 | function carousel_display_geo_callback() { |
||
| 610 | |||
| 611 | function carousel_display_geo_sanitize( $value ) { |
||
| 614 | |||
| 615 | function carousel_background_color_callback() { |
||
| 618 | |||
| 619 | function carousel_background_color_sanitize( $value ) { |
||
| 622 | |||
| 623 | function carousel_enable_it_callback() { |
||
| 626 | |||
| 627 | function carousel_enable_it_sanitize( $value ) { |
||
| 630 | } |
||
| 631 | |||
| 633 |
An exit expression should only be used in rare cases. For example, if you write a short command line script.
In most cases however, using an
exitexpression makes the code untestable and often causes incompatibilities with other libraries. Thus, unless you are absolutely sure it is required here, we recommend to refactor your code to avoid its usage.