Completed
Push — branch-4.5 ( a840a8...c54d36 )
by
unknown
24:18 queued 16:13
created

Jetpack_Carousel   D

Complexity

Total Complexity 116

Size/Duplication

Total Lines 697
Duplicated Lines 2.01 %

Coupling/Cohesion

Components 3
Dependencies 2

Importance

Changes 0
Metric Value
dl 14
loc 697
rs 4.4582
c 0
b 0
f 0
wmc 116
lcom 3
cbo 2

30 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 3 1
C init() 0 52 12
A maybe_disable_jp_carousel() 0 12 1
A maybe_disable_jp_carousel_single_images() 0 12 1
A maybe_enable_jp_carousel_single_images_media_file() 0 13 1
A jetpack_configuration_load() 0 4 1
A asset_version() 0 12 1
A display_bail_message() 0 9 1
B check_if_shortcode_processed_and_enqueue_assets() 0 41 6
D enqueue_assets() 8 129 15
A set_in_gallery() 0 4 1
C add_data_img_tags_and_enqueue_assets() 0 31 7
C add_data_to_images() 6 62 11
B add_data_to_container() 0 30 3
C get_attachment_comments() 0 53 9
D post_attachment_comment() 0 91 18
A register_settings() 0 18 2
A carousel_section_callback() 0 3 1
A test_1or0_option() 0 8 4
A sanitize_1or0_option() 0 3 2
A settings_checkbox() 0 12 3
B settings_select() 0 16 6
A carousel_display_exif_callback() 0 3 1
A carousel_display_exif_sanitize() 0 3 1
A carousel_display_geo_callback() 0 3 1
A carousel_display_geo_sanitize() 0 3 1
A carousel_background_color_callback() 0 3 1
A carousel_background_color_sanitize() 0 3 2
A carousel_enable_it_callback() 0 3 1
A carousel_enable_it_sanitize() 0 3 1

How to fix   Duplicated Code    Complexity   

Duplicated Code

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 Class

 Tip:   Before tackling complexity, make sure that you eliminate any duplication first. This often can reduce the size of classes significantly.

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
2
3
/*
4
Plugin Name: Jetpack Carousel
5
Plugin URL: https://wordpress.com/
6
Description: Transform your standard image galleries into an immersive full-screen experience.
7
Version: 0.1
8
Author: Automattic
9
10
Released under the GPL v.2 license.
11
12
This program is distributed in the hope that it will be useful,
13
but WITHOUT ANY WARRANTY; without even the implied warranty of
14
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15
GNU General Public License for more details.
16
*/
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
	public $single_image_gallery_enabled = false;
28
29
	public $single_image_gallery_enabled_media_file = false;
30
31
	function __construct() {
32
		add_action( 'init', array( $this, 'init' ) );
33
	}
34
35
	function init() {
36
		if ( $this->maybe_disable_jp_carousel() )
37
			return;
38
39
		$this->in_jetpack = ( class_exists( 'Jetpack' ) && method_exists( 'Jetpack', 'enable_module_configurable' ) ) ? true : false;
40
41
		$this->single_image_gallery_enabled = !$this->maybe_disable_jp_carousel_single_images();
42
		$this->single_image_gallery_enabled_media_file = $this->maybe_enable_jp_carousel_single_images_media_file();
43
44
		if ( is_admin() ) {
45
			// Register the Carousel-related related settings
46
			add_action( 'admin_init', array( $this, 'register_settings' ), 5 );
47
			if ( ! $this->in_jetpack ) {
48
				if ( 0 == $this->test_1or0_option( get_option( 'carousel_enable_it' ), true ) )
49
					return; // Carousel disabled, abort early, but still register setting so user can switch it back on
50
			}
51
			// If in admin, register the ajax endpoints.
52
			add_action( 'wp_ajax_get_attachment_comments', array( $this, 'get_attachment_comments' ) );
53
			add_action( 'wp_ajax_nopriv_get_attachment_comments', array( $this, 'get_attachment_comments' ) );
54
			add_action( 'wp_ajax_post_attachment_comment', array( $this, 'post_attachment_comment' ) );
55
			add_action( 'wp_ajax_nopriv_post_attachment_comment', array( $this, 'post_attachment_comment' ) );
56
		} else {
57
			if ( ! $this->in_jetpack ) {
58
				if ( 0 == $this->test_1or0_option( get_option( 'carousel_enable_it' ), true ) )
59
					return; // Carousel disabled, abort early
60
			}
61
			// If on front-end, do the Carousel thang.
62
			/**
63
			 * Filter the array of default prebuilt widths used in Carousel.
64
			 *
65
			 * @module carousel
66
			 *
67
			 * @since 1.6.0
68
			 *
69
			 * @param array $this->prebuilt_widths Array of default widths.
70
			 */
71
			$this->prebuilt_widths = apply_filters( 'jp_carousel_widths', $this->prebuilt_widths );
72
			// below: load later than other callbacks hooked it (e.g. 3rd party plugins handling gallery shortcode)
73
			add_filter( 'post_gallery', array( $this, 'check_if_shortcode_processed_and_enqueue_assets' ), 1000, 2 );
74
			add_filter( 'post_gallery', array( $this, 'set_in_gallery' ), -1000 );
75
			add_filter( 'gallery_style', array( $this, 'add_data_to_container' ) );
76
			add_filter( 'wp_get_attachment_image_attributes', array( $this, 'add_data_to_images' ), 10, 2 );
77
			if ( $this->single_image_gallery_enabled ) {
78
				add_filter( 'the_content', array( $this, 'add_data_img_tags_and_enqueue_assets' ) );
79
			}
80
		}
81
82
		if ( $this->in_jetpack && method_exists( 'Jetpack', 'module_configuration_load' ) ) {
83
			Jetpack::enable_module_configurable( dirname( dirname( __FILE__ ) ) . '/carousel.php' );
84
			Jetpack::module_configuration_load( dirname( dirname( __FILE__ ) ) . '/carousel.php', array( $this, 'jetpack_configuration_load' ) );
85
		}
86
	}
87
88
	function maybe_disable_jp_carousel() {
89
		/**
90
		 * Allow third-party plugins or themes to disable Carousel.
91
		 *
92
		 * @module carousel
93
		 *
94
		 * @since 1.6.0
95
		 *
96
		 * @param bool false Should Carousel be disabled? Default to false.
97
		 */
98
		return apply_filters( 'jp_carousel_maybe_disable', false );
99
	}
100
101
	function maybe_disable_jp_carousel_single_images() {
102
		/**
103
		 * Allow third-party plugins or themes to disable Carousel for single images.
104
		 *
105
		 * @module carousel
106
		 *
107
		 * @since 4.5.0
108
		 *
109
		 * @param bool false Should Carousel be disabled for single images? Default to false.
110
		 */
111
		return apply_filters( 'jp_carousel_maybe_disable_single_images', false );
112
	}
113
114
	function maybe_enable_jp_carousel_single_images_media_file() {
115
		/**
116
		 * Allow third-party plugins or themes to enable Carousel
117
		 * for single images linking to 'Media File' (full size image).
118
		 *
119
		 * @module carousel
120
		 *
121
		 * @since 4.5.0
122
		 *
123
		 * @param bool false Should Carousel be enabled for single images linking to 'Media File'? Default to false.
124
		 */
125
		return apply_filters( 'jp_carousel_load_for_images_linked_to_file', false );
126
	}
127
128
	function jetpack_configuration_load() {
129
		wp_safe_redirect( admin_url( 'options-media.php#carousel_background_color' ) );
130
		exit;
0 ignored issues
show
Coding Style Compatibility introduced by
The method jetpack_configuration_load() contains an exit expression.

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 exit expression 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.

Loading history...
131
	}
132
133
	function asset_version( $version ) {
134
		/**
135
		 * Filter the version string used when enqueuing Carousel assets.
136
		 *
137
		 * @module carousel
138
		 *
139
		 * @since 1.6.0
140
		 *
141
		 * @param string $version Asset version.
142
		 */
143
		return apply_filters( 'jp_carousel_asset_version', $version );
144
	}
145
146
	function display_bail_message( $output= '' ) {
147
		// Displays a message on top of gallery if carousel has bailed
148
		$message = '<div class="jp-carousel-msg"><p>';
149
		$message .= __( 'Jetpack\'s Carousel has been disabled, because another plugin or your theme is overriding the [gallery] shortcode.', 'jetpack' );
150
		$message .= '</p></div>';
151
		// put before gallery output
152
		$output = $message . $output;
153
		return $output;
154
	}
155
156
	function check_if_shortcode_processed_and_enqueue_assets( $output ) {
157
		if (
158
			! empty( $output ) &&
159
			/**
160
			 * Allow third-party plugins or themes to force-enable Carousel.
161
			 *
162
			 * @module carousel
163
			 *
164
			 * @since 1.9.0
165
			 *
166
			 * @param bool false Should we force enable Carousel? Default to false.
167
			 */
168
			! apply_filters( 'jp_carousel_force_enable', false )
169
		) {
170
			// Bail because someone is overriding the [gallery] shortcode.
171
			remove_filter( 'gallery_style', array( $this, 'add_data_to_container' ) );
172
			remove_filter( 'wp_get_attachment_image_attributes', array( $this, 'add_data_to_images' ) );
173
			remove_filter( 'the_content', array( $this, 'add_data_img_tags_and_enqueue_assets' ) );
174
			// Display message that carousel has bailed, if user is super_admin, and if we're not on WordPress.com.
175
			if (
176
				is_super_admin() &&
177
				! ( defined( 'IS_WPCOM' ) && IS_WPCOM )
178
			) {
179
				add_filter( 'post_gallery', array( $this, 'display_bail_message' ) );
180
			}
181
			return $output;
182
		}
183
184
		/**
185
		 * Fires when thumbnails are shown in Carousel.
186
		 *
187
		 * @module carousel
188
		 *
189
		 * @since 1.6.0
190
		 **/
191
		do_action( 'jp_carousel_thumbnails_shown' );
192
193
		$this->enqueue_assets();
194
195
		return $output;
196
	}
197
198
	function enqueue_assets() {
199
		if ( $this->first_run ) {
200
			wp_enqueue_script( 'jetpack-carousel', plugins_url( 'jetpack-carousel.js', __FILE__ ), array( 'jquery.spin' ), $this->asset_version( '20160325' ), true );
201
202
			// 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)
203
			// Also: not hardcoding path since there is no guarantee site is running on site root in self-hosted context.
204
			$is_logged_in = is_user_logged_in();
205
			$current_user = wp_get_current_user();
206
			$comment_registration = intval( get_option( 'comment_registration' ) );
207
			$require_name_email   = intval( get_option( 'require_name_email' ) );
208
			$localize_strings = array(
209
				'widths'               => $this->prebuilt_widths,
210
				'is_logged_in'         => $is_logged_in,
211
				'lang'                 => strtolower( substr( get_locale(), 0, 2 ) ),
212
				'ajaxurl'              => set_url_scheme( admin_url( 'admin-ajax.php' ) ),
213
				'nonce'                => wp_create_nonce( 'carousel_nonce' ),
214
				'display_exif'         => $this->test_1or0_option( Jetpack_Options::get_option_and_ensure_autoload( 'carousel_display_exif', true ) ),
215
				'display_geo'          => $this->test_1or0_option( Jetpack_Options::get_option_and_ensure_autoload( 'carousel_display_geo', true ) ),
216
				'single_image_gallery' => $this->single_image_gallery_enabled,
217
				'single_image_gallery_media_file' => $this->single_image_gallery_enabled_media_file,
218
				'background_color'     => $this->carousel_background_color_sanitize( Jetpack_Options::get_option_and_ensure_autoload( 'carousel_background_color', '' ) ),
219
				'comment'              => __( 'Comment', 'jetpack' ),
220
				'post_comment'         => __( 'Post Comment', 'jetpack' ),
221
				'write_comment'        => __( 'Write a Comment...', 'jetpack' ),
222
				'loading_comments'     => __( 'Loading Comments...', 'jetpack' ),
223
				'download_original'    => sprintf( __( 'View full size <span class="photo-size">%1$s<span class="photo-size-times">&times;</span>%2$s</span>', 'jetpack' ), '{0}', '{1}' ),
224
				'no_comment_text'      => __( 'Please be sure to submit some text with your comment.', 'jetpack' ),
225
				'no_comment_email'     => __( 'Please provide an email address to comment.', 'jetpack' ),
226
				'no_comment_author'    => __( 'Please provide your name to comment.', 'jetpack' ),
227
				'comment_post_error'   => __( 'Sorry, but there was an error posting your comment. Please try again later.', 'jetpack' ),
228
				'comment_approved'     => __( 'Your comment was approved.', 'jetpack' ),
229
				'comment_unapproved'   => __( 'Your comment is in moderation.', 'jetpack' ),
230
				'camera'               => __( 'Camera', 'jetpack' ),
231
				'aperture'             => __( 'Aperture', 'jetpack' ),
232
				'shutter_speed'        => __( 'Shutter Speed', 'jetpack' ),
233
				'focal_length'         => __( 'Focal Length', 'jetpack' ),
234
				'comment_registration' => $comment_registration,
235
				'require_name_email'   => $require_name_email,
236
				/** This action is documented in core/src/wp-includes/link-template.php */
237
				'login_url'            => wp_login_url( apply_filters( 'the_permalink', get_permalink() ) ),
238
				'blog_id'              => (int) get_current_blog_id(),
239
			);
240
241
			if ( ! isset( $localize_strings['jetpack_comments_iframe_src'] ) || empty( $localize_strings['jetpack_comments_iframe_src'] ) ) {
242
				// We're not using Comments after all, so fallback to standard local comments.
243
244
				if ( $is_logged_in ) {
245
					$localize_strings['local_comments_commenting_as'] = '<p id="jp-carousel-commenting-as">' . sprintf( __( 'Commenting as %s', 'jetpack' ), $current_user->data->display_name ) . '</p>';
246
				} else {
247
					if ( $comment_registration ) {
248
						$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>';
249
					} else {
250
						$required = ( $require_name_email ) ? __( '%s (Required)', 'jetpack' ) : '%s';
251
						$localize_strings['local_comments_commenting_as'] = ''
252
							. '<fieldset><label for="email">' . sprintf( $required, __( 'Email', 'jetpack' ) ) . '</label> '
253
							. '<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>'
254
							. '<fieldset><label for="author">' . sprintf( $required, __( 'Name', 'jetpack' ) ) . '</label> '
255
							. '<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>'
256
							. '<fieldset><label for="url">' . __( 'Website', 'jetpack' ) . '</label> '
257
							. '<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>';
258
						}
259
				}
260
			}
261
262
			/**
263
			 * Handle WP stats for images in full-screen.
264
			 * Build string with tracking info.
265
			 */
266
267
			/**
268
			 * Filter if Jetpack should enable stats collection on carousel views
269
			 *
270
			 * @module carousel
271
			 *
272
			 * @since 4.3.2
273
			 *
274
			 * @param bool Enable Jetpack Carousel stat collection. Default false.
275
			 */
276
			if ( apply_filters( 'jetpack_enable_carousel_stats', false ) && in_array( 'stats', Jetpack::get_active_modules() ) && ! Jetpack::is_development_mode() ) {
277
				$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;
278
279
				// Set the stats as empty if user is logged in but logged-in users shouldn't be tracked.
280 View Code Duplication
				if ( is_user_logged_in() && function_exists( 'stats_get_options' ) ) {
281
					$stats_options = stats_get_options();
282
					$track_loggedin_users = isset( $stats_options['reg_users'] ) ? (bool) $stats_options['reg_users'] : false;
283
284
					if ( ! $track_loggedin_users ) {
285
						$localize_strings['stats'] = '';
286
					}
287
				}
288
			}
289
290
			/**
291
			 * Filter the strings passed to the Carousel's js file.
292
			 *
293
			 * @module carousel
294
			 *
295
			 * @since 1.6.0
296
			 *
297
			 * @param array $localize_strings Array of strings passed to the Jetpack js file.
298
			 */
299
			$localize_strings = apply_filters( 'jp_carousel_localize_strings', $localize_strings );
300
			wp_localize_script( 'jetpack-carousel', 'jetpackCarouselStrings', $localize_strings );
301
			if( is_rtl() ) {
302
				wp_enqueue_style( 'jetpack-carousel', plugins_url( '/rtl/jetpack-carousel-rtl.css', __FILE__ ), array(), $this->asset_version( '20120629' ) );
303
			} else {
304
				wp_enqueue_style( 'jetpack-carousel', plugins_url( 'jetpack-carousel.css', __FILE__ ), array(), $this->asset_version( '20120629' ) );
305
			}
306
307
			wp_register_style( 'jetpack-carousel-ie8fix', plugins_url( 'jetpack-carousel-ie8fix.css', __FILE__ ), array(), $this->asset_version( '20121024' ) );
308
			$GLOBALS['wp_styles']->add_data( 'jetpack-carousel-ie8fix', 'conditional', 'lte IE 8' );
309
			wp_enqueue_style( 'jetpack-carousel-ie8fix' );
310
311
			/**
312
			 * Fires after carousel assets are enqueued for the first time.
313
			 * Allows for adding additional assets to the carousel page.
314
			 *
315
			 * @module carousel
316
			 *
317
			 * @since 1.6.0
318
			 *
319
			 * @param bool $first_run First load if Carousel on the page.
320
			 * @param array $localized_strings Array of strings passed to the Jetpack js file.
321
			 */
322
			do_action( 'jp_carousel_enqueue_assets', $this->first_run, $localize_strings );
323
324
			$this->first_run = false;
325
		}
326
	}
327
328
	function set_in_gallery( $output ) {
329
		$this->in_gallery = true;
330
		return $output;
331
	}
332
333
	/**
334
	 * Adds data-* attributes required by carousel to img tags in post HTML
335
	 * content. To be used by 'the_content' filter.
336
	 *
337
	 * @see add_data_to_images()
338
	 * @see wp_make_content_images_responsive() in wp-includes/media.php
339
	 *
340
	 * @param string $content HTML content of the post
341
	 * @return string Modified HTML content of the post
342
	 */
343
	function add_data_img_tags_and_enqueue_assets( $content ) {
344
		if ( ! preg_match_all( '/<img [^>]+>/', $content, $matches ) ) {
345
			return $content;
346
		}
347
		$selected_images = array();
348
349
		foreach( $matches[0] as $image_html ) {
350
			if ( preg_match( '/wp-image-([0-9]+)/i', $image_html, $class_id ) &&
351
				( $attachment_id = absint( $class_id[1] ) ) ) {
352
353
				/*
354
				 * If exactly the same image tag is used more than once, overwrite it.
355
				 * All identical tags will be replaced later with 'str_replace()'.
356
				 */
357
				$selected_images[ $attachment_id  ] = $image_html;
358
			}
359
		}
360
361
		foreach ( $selected_images as $attachment_id => $image_html ) {
362
			$attachment = get_post( $attachment_id );
363
			$attributes = $this->add_data_to_images( array(), $attachment );
364
			$attributes_html = '';
365
			foreach( $attributes as $k => $v ) {
366
				$attributes_html .= esc_attr( $k ) . '="' . esc_attr( $v ) . '"';
367
			}
368
			$image_html_with_data = str_replace( '<img ', "<img $attributes_html", $image_html );
369
			$content = str_replace( $image_html, $image_html_with_data, $content );
370
		}
371
		$this->enqueue_assets();
372
		return $content;
373
	}
374
375
	function add_data_to_images( $attr, $attachment = null ) {
376
		$attachment_id   = intval( $attachment->ID );
377
		$orig_file       = wp_get_attachment_image_src( $attachment_id, 'full' );
378
		$orig_file       = isset( $orig_file[0] ) ? $orig_file[0] : wp_get_attachment_url( $attachment_id );
379
		$meta            = wp_get_attachment_metadata( $attachment_id );
380
		$size            = isset( $meta['width'] ) ? intval( $meta['width'] ) . ',' . intval( $meta['height'] ) : '';
381
		$img_meta        = ( ! empty( $meta['image_meta'] ) ) ? (array) $meta['image_meta'] : array();
382
		$comments_opened = intval( comments_open( $attachment_id ) );
383
384
		 /*
385
		 * Note: Cannot generate a filename from the width and height wp_get_attachment_image_src() returns because
386
		 * it takes the $content_width global variable themes can set in consideration, therefore returning sizes
387
		 * which when used to generate a filename will likely result in a 404 on the image.
388
		 * $content_width has no filter we could temporarily de-register, run wp_get_attachment_image_src(), then
389
		 * re-register. So using returned file URL instead, which we can define the sizes from through filename
390
		 * parsing in the JS, as this is a failsafe file reference.
391
		 *
392
		 * EG with Twenty Eleven activated:
393
		 * array(4) { [0]=> string(82) "http://vanillawpinstall.blah/wp-content/uploads/2012/06/IMG_3534-1024x764.jpg" [1]=> int(584) [2]=> int(435) [3]=> bool(true) }
394
		 *
395
		 * EG with Twenty Ten activated:
396
		 * array(4) { [0]=> string(82) "http://vanillawpinstall.blah/wp-content/uploads/2012/06/IMG_3534-1024x764.jpg" [1]=> int(640) [2]=> int(477) [3]=> bool(true) }
397
		 */
398
399
		$medium_file_info = wp_get_attachment_image_src( $attachment_id, 'medium' );
400
		$medium_file      = isset( $medium_file_info[0] ) ? $medium_file_info[0] : '';
401
402
		$large_file_info  = wp_get_attachment_image_src( $attachment_id, 'large' );
403
		$large_file       = isset( $large_file_info[0] ) ? $large_file_info[0] : '';
404
405
		$attachment       = get_post( $attachment_id );
406
		$attachment_title = wptexturize( $attachment->post_title );
407
		$attachment_desc  = wpautop( wptexturize( $attachment->post_content ) );
408
409
		// Not yet providing geo-data, need to "fuzzify" for privacy
410 View Code Duplication
		if ( ! empty( $img_meta ) ) {
411
			foreach ( $img_meta as $k => $v ) {
412
				if ( 'latitude' == $k || 'longitude' == $k )
413
					unset( $img_meta[$k] );
414
			}
415
		}
416
417
		// See https://github.com/Automattic/jetpack/issues/2765
418
		if ( isset( $img_meta['keywords'] ) ) {
419
			unset( $img_meta['keywords'] );
420
		}
421
422
		$img_meta = json_encode( array_map( 'strval', $img_meta ) );
423
424
		$attr['data-attachment-id']     = $attachment_id;
425
		$attr['data-permalink']         = esc_attr( get_permalink( $attachment->ID ) );
426
		$attr['data-orig-file']         = esc_attr( $orig_file );
427
		$attr['data-orig-size']         = $size;
428
		$attr['data-comments-opened']   = $comments_opened;
429
		$attr['data-image-meta']        = esc_attr( $img_meta );
430
		$attr['data-image-title']       = esc_attr( $attachment_title );
431
		$attr['data-image-description'] = esc_attr( $attachment_desc );
432
		$attr['data-medium-file']       = esc_attr( $medium_file );
433
		$attr['data-large-file']        = esc_attr( $large_file );
434
435
		return $attr;
436
	}
437
438
	function add_data_to_container( $html ) {
439
		global $post;
440
441
		if ( isset( $post ) ) {
442
			$blog_id = (int) get_current_blog_id();
443
444
			$extra_data = array(
445
				'data-carousel-extra' => array(
446
					'blog_id' => $blog_id,
447
					'permalink' => get_permalink( $post->ID ),
448
					)
449
				);
450
451
			/**
452
			 * Filter the data added to the Gallery container.
453
			 *
454
			 * @module carousel
455
			 *
456
			 * @since 1.6.0
457
			 *
458
			 * @param array $extra_data Array of data about the site and the post.
459
			 */
460
			$extra_data = apply_filters( 'jp_carousel_add_data_to_container', $extra_data );
461
			foreach ( (array) $extra_data as $data_key => $data_values ) {
462
				$html = str_replace( '<div ', '<div ' . esc_attr( $data_key ) . "='" . json_encode( $data_values ) . "' ", $html );
463
			}
464
		}
465
466
		return $html;
467
	}
468
469
	function get_attachment_comments() {
470
		if ( ! headers_sent() )
471
			header('Content-type: text/javascript');
472
473
		/**
474
		 * Allows for the checking of privileges of the blog user before comments
475
		 * are packaged as JSON and sent back from the get_attachment_comments
476
		 * AJAX endpoint
477
		 *
478
		 * @module carousel
479
		 *
480
		 * @since 1.6.0
481
		 */
482
		do_action('jp_carousel_check_blog_user_privileges');
483
484
		$attachment_id = ( isset( $_REQUEST['id'] ) ) ? (int) $_REQUEST['id'] : 0;
485
		$offset        = ( isset( $_REQUEST['offset'] ) ) ? (int) $_REQUEST['offset'] : 0;
486
487
		if ( ! $attachment_id ) {
488
			echo json_encode( __( 'Missing attachment ID.', 'jetpack' ) );
489
			die();
0 ignored issues
show
Coding Style Compatibility introduced by
The method get_attachment_comments() contains an exit expression.

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 exit expression 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.

Loading history...
490
		}
491
492
		if ( $offset < 1 )
493
			$offset = 0;
494
495
		$comments = get_comments( array(
496
			'status'  => 'approve',
497
			'order'   => ( 'asc' == get_option('comment_order') ) ? 'ASC' : 'DESC',
498
			'number'  => 10,
499
			'offset'  => $offset,
500
			'post_id' => $attachment_id,
501
		) );
502
503
		$out      = array();
0 ignored issues
show
Coding Style introduced by
Equals sign not aligned correctly; expected 1 space but found 6 spaces

This check looks for improperly formatted assignments.

Every assignment must have exactly one space before and one space after the equals operator.

To illustrate:

$a = "a";
$ab = "ab";
$abc = "abc";

will have no issues, while

$a   = "a";
$ab  = "ab";
$abc = "abc";

will report issues in lines 1 and 2.

Loading history...
504
505
		// Can't just send the results, they contain the commenter's email address.
506
		foreach ( $comments as $comment ) {
507
			$avatar = get_avatar( $comment->comment_author_email, 64 );
508
			if( ! $avatar )
509
				$avatar = '';
510
			$out[] = array(
511
				'id'              => $comment->comment_ID,
512
				'parent_id'       => $comment->comment_parent,
513
				'author_markup'   => get_comment_author_link( $comment->comment_ID ),
514
				'gravatar_markup' => $avatar,
515
				'date_gmt'        => $comment->comment_date_gmt,
516
				'content'         => wpautop($comment->comment_content),
517
			);
518
		}
519
520
		die( json_encode( $out ) );
0 ignored issues
show
Coding Style Compatibility introduced by
The method get_attachment_comments() contains an exit expression.

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 exit expression 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.

Loading history...
521
	}
522
523
	function post_attachment_comment() {
524
		if ( ! headers_sent() )
525
			header('Content-type: text/javascript');
526
527
		if ( empty( $_POST['nonce'] ) || ! wp_verify_nonce($_POST['nonce'], 'carousel_nonce') )
528
			die( json_encode( array( 'error' => __( 'Nonce verification failed.', 'jetpack' ) ) ) );
0 ignored issues
show
Coding Style Compatibility introduced by
The method post_attachment_comment() contains an exit expression.

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 exit expression 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.

Loading history...
529
530
		$_blog_id = (int) $_POST['blog_id'];
531
		$_post_id = (int) $_POST['id'];
532
		$comment = $_POST['comment'];
533
534
		if ( empty( $_blog_id ) )
535
			die( json_encode( array( 'error' => __( 'Missing target blog ID.', 'jetpack' ) ) ) );
0 ignored issues
show
Coding Style Compatibility introduced by
The method post_attachment_comment() contains an exit expression.

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 exit expression 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.

Loading history...
536
537
		if ( empty( $_post_id ) )
538
			die( json_encode( array( 'error' => __( 'Missing target post ID.', 'jetpack' ) ) ) );
0 ignored issues
show
Coding Style Compatibility introduced by
The method post_attachment_comment() contains an exit expression.

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 exit expression 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.

Loading history...
539
540
		if ( empty( $comment ) )
541
			die( json_encode( array( 'error' => __( 'No comment text was submitted.', 'jetpack' ) ) ) );
0 ignored issues
show
Coding Style Compatibility introduced by
The method post_attachment_comment() contains an exit expression.

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 exit expression 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.

Loading history...
542
543
		// Used in context like NewDash
544
		$switched = false;
545
		if ( is_multisite() && $_blog_id != get_current_blog_id() ) {
546
			switch_to_blog( $_blog_id );
547
			$switched = true;
548
		}
549
550
		/** This action is documented in modules/carousel/jetpack-carousel.php */
551
		do_action('jp_carousel_check_blog_user_privileges');
552
553
		if ( ! comments_open( $_post_id ) )
554
			die( json_encode( array( 'error' => __( 'Comments on this post are closed.', 'jetpack' ) ) ) );
0 ignored issues
show
Coding Style Compatibility introduced by
The method post_attachment_comment() contains an exit expression.

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 exit expression 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.

Loading history...
555
556
		if ( is_user_logged_in() ) {
557
			$user         = wp_get_current_user();
558
			$user_id      = $user->ID;
559
			$display_name = $user->display_name;
560
			$email        = $user->user_email;
561
			$url          = $user->user_url;
562
563
			if ( empty( $user_id ) )
564
				die( json_encode( array( 'error' => __( 'Sorry, but we could not authenticate your request.', 'jetpack' ) ) ) );
0 ignored issues
show
Coding Style Compatibility introduced by
The method post_attachment_comment() contains an exit expression.

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 exit expression 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.

Loading history...
565
		} else {
566
			$user_id      = 0;
567
			$display_name = $_POST['author'];
568
			$email        = $_POST['email'];
569
			$url          = $_POST['url'];
570
571
			if ( get_option( 'require_name_email' ) ) {
572
				if ( empty( $display_name ) )
573
					die( json_encode( array( 'error' => __( 'Please provide your name.', 'jetpack' ) ) ) );
0 ignored issues
show
Coding Style Compatibility introduced by
The method post_attachment_comment() contains an exit expression.

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 exit expression 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.

Loading history...
574
575
				if ( empty( $email ) )
576
					die( json_encode( array( 'error' => __( 'Please provide an email address.', 'jetpack' ) ) ) );
0 ignored issues
show
Coding Style Compatibility introduced by
The method post_attachment_comment() contains an exit expression.

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 exit expression 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.

Loading history...
577
578
				if ( ! is_email( $email ) )
579
					die( json_encode( array( 'error' => __( 'Please provide a valid email address.', 'jetpack' ) ) ) );
0 ignored issues
show
Coding Style Compatibility introduced by
The method post_attachment_comment() contains an exit expression.

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 exit expression 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.

Loading history...
580
			}
581
		}
582
583
		$comment_data =  array(
584
			'comment_content'      => $comment,
585
			'comment_post_ID'      => $_post_id,
586
			'comment_author'       => $display_name,
587
			'comment_author_email' => $email,
588
			'comment_author_url'   => $url,
589
			'comment_approved'     => 0,
590
			'comment_type'         => '',
591
		);
592
593
		if ( ! empty( $user_id ) )
594
			$comment_data['user_id'] = $user_id;
595
596
		// Note: wp_new_comment() sanitizes and validates the values (too).
597
		$comment_id = wp_new_comment( $comment_data );
598
599
		/**
600
		 * Fires before adding a new comment to the database via the get_attachment_comments ajax endpoint.
601
		 *
602
		 * @module carousel
603
		 *
604
		 * @since 1.6.0
605
		 */
606
		do_action( 'jp_carousel_post_attachment_comment' );
607
		$comment_status = wp_get_comment_status( $comment_id );
608
609
		if ( true == $switched )
0 ignored issues
show
Coding Style Best Practice introduced by
It seems like you are loosely comparing two booleans. Considering using the strict comparison === instead.

When comparing two booleans, it is generally considered safer to use the strict comparison operator.

Loading history...
610
			restore_current_blog();
611
612
		die( json_encode( array( 'comment_id' => $comment_id, 'comment_status' => $comment_status ) ) );
0 ignored issues
show
Coding Style Compatibility introduced by
The method post_attachment_comment() contains an exit expression.

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 exit expression 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.

Loading history...
613
	}
614
615
	function register_settings() {
616
		add_settings_section('carousel_section', __( 'Image Gallery Carousel', 'jetpack' ), array( $this, 'carousel_section_callback' ), 'media');
617
618
		if ( ! $this->in_jetpack ) {
619
			add_settings_field('carousel_enable_it', __( 'Enable carousel', 'jetpack' ), array( $this, 'carousel_enable_it_callback' ), 'media', 'carousel_section' );
620
			register_setting( 'media', 'carousel_enable_it', array( $this, 'carousel_enable_it_sanitize' ) );
621
		}
622
623
		add_settings_field('carousel_background_color', __( 'Background color', 'jetpack' ), array( $this, 'carousel_background_color_callback' ), 'media', 'carousel_section' );
624
		register_setting( 'media', 'carousel_background_color', array( $this, 'carousel_background_color_sanitize' ) );
625
626
		add_settings_field('carousel_display_exif', __( 'Metadata', 'jetpack'), array( $this, 'carousel_display_exif_callback' ), 'media', 'carousel_section' );
627
		register_setting( 'media', 'carousel_display_exif', array( $this, 'carousel_display_exif_sanitize' ) );
628
629
		// No geo setting yet, need to "fuzzify" data first, for privacy
630
		// add_settings_field('carousel_display_geo', __( 'Geolocation', 'jetpack' ), array( $this, 'carousel_display_geo_callback' ), 'media', 'carousel_section' );
631
		// register_setting( 'media', 'carousel_display_geo', array( $this, 'carousel_display_geo_sanitize' ) );
632
	}
633
634
	// Fulfill the settings section callback requirement by returning nothing
635
	function carousel_section_callback() {
636
		return;
637
	}
638
639
	function test_1or0_option( $value, $default_to_1 = true ) {
640
		if ( true == $default_to_1 ) {
0 ignored issues
show
Coding Style Best Practice introduced by
It seems like you are loosely comparing two booleans. Considering using the strict comparison === instead.

When comparing two booleans, it is generally considered safer to use the strict comparison operator.

Loading history...
641
			// Binary false (===) of $value means it has not yet been set, in which case we do want to default sites to 1
642
			if ( false === $value )
643
				$value = 1;
644
		}
645
		return ( 1 == $value ) ? 1 : 0;
646
	}
647
648
	function sanitize_1or0_option( $value ) {
649
		return ( 1 == $value ) ? 1 : 0;
650
	}
651
652
	function settings_checkbox($name, $label_text, $extra_text = '', $default_to_checked = true) {
653
		if ( empty( $name ) )
654
			return;
655
		$option = $this->test_1or0_option( get_option( $name ), $default_to_checked );
656
		echo '<fieldset>';
657
		echo '<input type="checkbox" name="'.esc_attr($name).'" id="'.esc_attr($name).'" value="1" ';
658
		checked( '1', $option );
659
		echo '/> <label for="'.esc_attr($name).'">'.$label_text.'</label>';
660
		if ( ! empty( $extra_text ) )
661
			echo '<p class="description">'.$extra_text.'</p>';
662
		echo '</fieldset>';
663
	}
664
665
	function settings_select($name, $values, $extra_text = '') {
666
		if ( empty( $name ) || ! is_array( $values ) || empty( $values ) )
667
			return;
668
		$option = get_option( $name );
669
		echo '<fieldset>';
670
		echo '<select name="'.esc_attr($name).'" id="'.esc_attr($name).'">';
671
		foreach( $values as $key => $value ) {
672
			echo '<option value="'.esc_attr($key).'" ';
673
			selected( $key, $option );
674
			echo '>'.esc_html($value).'</option>';
675
		}
676
		echo '</select>';
677
		if ( ! empty( $extra_text ) )
678
			echo '<p class="description">'.$extra_text.'</p>';
679
		echo '</fieldset>';
680
	}
681
682
	function carousel_display_exif_callback() {
683
		$this->settings_checkbox( 'carousel_display_exif', __( 'Show photo metadata (<a href="http://en.wikipedia.org/wiki/Exchangeable_image_file_format" target="_blank">Exif</a>) in carousel, when available.', 'jetpack' ) );
684
	}
685
686
	function carousel_display_exif_sanitize( $value ) {
687
		return $this->sanitize_1or0_option( $value );
688
	}
689
690
	function carousel_display_geo_callback() {
691
		$this->settings_checkbox( 'carousel_display_geo', __( 'Show map of photo location in carousel, when available.', 'jetpack' ) );
692
	}
693
694
	function carousel_display_geo_sanitize( $value ) {
695
		return $this->sanitize_1or0_option( $value );
696
	}
697
698
	function carousel_background_color_callback() {
699
		$this->settings_select( 'carousel_background_color', array( 'black' => __( 'Black', 'jetpack' ), 'white' => __( 'White', 'jetpack', 'jetpack' ) ) );
700
	}
701
702
	function carousel_background_color_sanitize( $value ) {
703
		return ( 'white' == $value ) ? 'white' : 'black';
704
	}
705
706
	function carousel_enable_it_callback() {
707
		$this->settings_checkbox( 'carousel_enable_it', __( 'Display images in full-size carousel slideshow.', 'jetpack' ) );
708
	}
709
710
	function carousel_enable_it_sanitize( $value ) {
711
		return $this->sanitize_1or0_option( $value );
712
	}
713
}
714
715
new Jetpack_Carousel;
716