Completed
Push — add/carousel-media-notice ( 2f48d4 )
by
unknown
08:33
created

Jetpack_Carousel::print_carousel_media_template()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 9
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 4
nc 1
nop 0
dl 0
loc 9
rs 9.6666
c 0
b 0
f 0
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
57
			// Enqueue admin-only scripts
58
			add_action( 'admin_enqueue_scripts', array( $this, 'enqueue_admin_assets' ), 1 );
59
			add_action( 'print_media_templates', array( $this, 'print_carousel_media_template' ) );
60
		} else {
61
			if ( ! $this->in_jetpack ) {
62
				if ( 0 == $this->test_1or0_option( get_option( 'carousel_enable_it' ), true ) )
63
					return; // Carousel disabled, abort early
64
			}
65
			// If on front-end, do the Carousel thang.
66
			/**
67
			 * Filter the array of default prebuilt widths used in Carousel.
68
			 *
69
			 * @module carousel
70
			 *
71
			 * @since 1.6.0
72
			 *
73
			 * @param array $this->prebuilt_widths Array of default widths.
74
			 */
75
			$this->prebuilt_widths = apply_filters( 'jp_carousel_widths', $this->prebuilt_widths );
76
			// below: load later than other callbacks hooked it (e.g. 3rd party plugins handling gallery shortcode)
77
			add_filter( 'post_gallery', array( $this, 'check_if_shortcode_processed_and_enqueue_assets' ), 1000, 2 );
78
			add_filter( 'post_gallery', array( $this, 'set_in_gallery' ), -1000 );
79
			add_filter( 'gallery_style', array( $this, 'add_data_to_container' ) );
80
			add_filter( 'wp_get_attachment_image_attributes', array( $this, 'add_data_to_images' ), 10, 2 );
81
			if ( $this->single_image_gallery_enabled ) {
82
				add_filter( 'the_content', array( $this, 'add_data_img_tags_and_enqueue_assets' ) );
83
			}
84
		}
85
86
		if ( $this->in_jetpack && method_exists( 'Jetpack', 'module_configuration_load' ) ) {
87
			Jetpack::enable_module_configurable( dirname( dirname( __FILE__ ) ) . '/carousel.php' );
88
			Jetpack::module_configuration_load( dirname( dirname( __FILE__ ) ) . '/carousel.php', array( $this, 'jetpack_configuration_load' ) );
89
		}
90
	}
91
92
	function maybe_disable_jp_carousel() {
93
		/**
94
		 * Allow third-party plugins or themes to disable Carousel.
95
		 *
96
		 * @module carousel
97
		 *
98
		 * @since 1.6.0
99
		 *
100
		 * @param bool false Should Carousel be disabled? Default to false.
101
		 */
102
		return apply_filters( 'jp_carousel_maybe_disable', false );
103
	}
104
105
	function maybe_disable_jp_carousel_single_images() {
106
		/**
107
		 * Allow third-party plugins or themes to disable Carousel for single images.
108
		 *
109
		 * @module carousel
110
		 *
111
		 * @since 4.5.0
112
		 *
113
		 * @param bool false Should Carousel be disabled for single images? Default to false.
114
		 */
115
		return apply_filters( 'jp_carousel_maybe_disable_single_images', false );
116
	}
117
118
	function maybe_enable_jp_carousel_single_images_media_file() {
119
		/**
120
		 * Allow third-party plugins or themes to enable Carousel
121
		 * for single images linking to 'Media File' (full size image).
122
		 *
123
		 * @module carousel
124
		 *
125
		 * @since 4.5.0
126
		 *
127
		 * @param bool false Should Carousel be enabled for single images linking to 'Media File'? Default to false.
128
		 */
129
		return apply_filters( 'jp_carousel_load_for_images_linked_to_file', false );
130
	}
131
132
	function jetpack_configuration_load() {
133
		wp_safe_redirect( admin_url( 'options-media.php#carousel_background_color' ) );
134
		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...
135
	}
136
137
	function asset_version( $version ) {
138
		/**
139
		 * Filter the version string used when enqueuing Carousel assets.
140
		 *
141
		 * @module carousel
142
		 *
143
		 * @since 1.6.0
144
		 *
145
		 * @param string $version Asset version.
146
		 */
147
		return apply_filters( 'jp_carousel_asset_version', $version );
148
	}
149
150
	function display_bail_message( $output= '' ) {
151
		// Displays a message on top of gallery if carousel has bailed
152
		$message = '<div class="jp-carousel-msg"><p>';
153
		$message .= __( 'Jetpack\'s Carousel has been disabled, because another plugin or your theme is overriding the [gallery] shortcode.', 'jetpack' );
154
		$message .= '</p></div>';
155
		// put before gallery output
156
		$output = $message . $output;
157
		return $output;
158
	}
159
160
	function check_if_shortcode_processed_and_enqueue_assets( $output ) {
161
		if (
162
			! empty( $output ) &&
163
			/**
164
			 * Allow third-party plugins or themes to force-enable Carousel.
165
			 *
166
			 * @module carousel
167
			 *
168
			 * @since 1.9.0
169
			 *
170
			 * @param bool false Should we force enable Carousel? Default to false.
171
			 */
172
			! apply_filters( 'jp_carousel_force_enable', false )
173
		) {
174
			// Bail because someone is overriding the [gallery] shortcode.
175
			remove_filter( 'gallery_style', array( $this, 'add_data_to_container' ) );
176
			remove_filter( 'wp_get_attachment_image_attributes', array( $this, 'add_data_to_images' ) );
177
			remove_filter( 'the_content', array( $this, 'add_data_img_tags_and_enqueue_assets' ) );
178
			// Display message that carousel has bailed, if user is super_admin, and if we're not on WordPress.com.
179
			if (
180
				is_super_admin() &&
181
				! ( defined( 'IS_WPCOM' ) && IS_WPCOM )
182
			) {
183
				add_filter( 'post_gallery', array( $this, 'display_bail_message' ) );
184
			}
185
			return $output;
186
		}
187
188
		/**
189
		 * Fires when thumbnails are shown in Carousel.
190
		 *
191
		 * @module carousel
192
		 *
193
		 * @since 1.6.0
194
		 **/
195
		do_action( 'jp_carousel_thumbnails_shown' );
196
197
		$this->enqueue_assets();
198
199
		return $output;
200
	}
201
202
	function enqueue_admin_assets() {
203
		wp_enqueue_script(
204
			'jetpack-carousel',
205
			plugins_url( 'modules/carousel/carousel-media-modal.js', JETPACK__PLUGIN_FILE ),
206
			array( 'media-views', 'jquery', 'media-widgets' )
207
		);
208
	}
209
210
	function print_carousel_media_template() {
211
		?>
212
		<script type="text/html" id="tmpl-jetpack-carousel-media-notice">
213
			<div style="background-color: white;">
214
				Clicking thumbnails will always open a <a href="#">Carousel</a>
215
			</div>
216
		</script>
217
		<?php
218
	}
219
220
	function enqueue_assets() {
221
		if ( $this->first_run ) {
222
			wp_enqueue_script(
223
				'jetpack-carousel',
224
				Jetpack::get_file_url_for_environment(
225
					'_inc/build/carousel/jetpack-carousel.min.js',
226
					'modules/carousel/jetpack-carousel.js'
227
				),
228
				array( 'jquery.spin' ),
229
				$this->asset_version( '20170209' ),
230
				true
231
			);
232
233
			// 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)
234
			// Also: not hardcoding path since there is no guarantee site is running on site root in self-hosted context.
235
			$is_logged_in = is_user_logged_in();
236
			$current_user = wp_get_current_user();
237
			$comment_registration = intval( get_option( 'comment_registration' ) );
238
			$require_name_email   = intval( get_option( 'require_name_email' ) );
239
			$localize_strings = array(
240
				'widths'               => $this->prebuilt_widths,
241
				'is_logged_in'         => $is_logged_in,
242
				'lang'                 => strtolower( substr( get_locale(), 0, 2 ) ),
243
				'ajaxurl'              => set_url_scheme( admin_url( 'admin-ajax.php' ) ),
244
				'nonce'                => wp_create_nonce( 'carousel_nonce' ),
245
				'display_exif'         => $this->test_1or0_option( Jetpack_Options::get_option_and_ensure_autoload( 'carousel_display_exif', true ) ),
246
				'display_geo'          => $this->test_1or0_option( Jetpack_Options::get_option_and_ensure_autoload( 'carousel_display_geo', true ) ),
247
				'single_image_gallery' => $this->single_image_gallery_enabled,
248
				'single_image_gallery_media_file' => $this->single_image_gallery_enabled_media_file,
249
				'background_color'     => $this->carousel_background_color_sanitize( Jetpack_Options::get_option_and_ensure_autoload( 'carousel_background_color', '' ) ),
250
				'comment'              => __( 'Comment', 'jetpack' ),
251
				'post_comment'         => __( 'Post Comment', 'jetpack' ),
252
				'write_comment'        => __( 'Write a Comment...', 'jetpack' ),
253
				'loading_comments'     => __( 'Loading Comments...', 'jetpack' ),
254
				'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}' ),
255
				'no_comment_text'      => __( 'Please be sure to submit some text with your comment.', 'jetpack' ),
256
				'no_comment_email'     => __( 'Please provide an email address to comment.', 'jetpack' ),
257
				'no_comment_author'    => __( 'Please provide your name to comment.', 'jetpack' ),
258
				'comment_post_error'   => __( 'Sorry, but there was an error posting your comment. Please try again later.', 'jetpack' ),
259
				'comment_approved'     => __( 'Your comment was approved.', 'jetpack' ),
260
				'comment_unapproved'   => __( 'Your comment is in moderation.', 'jetpack' ),
261
				'camera'               => __( 'Camera', 'jetpack' ),
262
				'aperture'             => __( 'Aperture', 'jetpack' ),
263
				'shutter_speed'        => __( 'Shutter Speed', 'jetpack' ),
264
				'focal_length'         => __( 'Focal Length', 'jetpack' ),
265
				'copyright'            => __( 'Copyright', 'jetpack' ),
266
				'comment_registration' => $comment_registration,
267
				'require_name_email'   => $require_name_email,
268
				/** This action is documented in core/src/wp-includes/link-template.php */
269
				'login_url'            => wp_login_url( apply_filters( 'the_permalink', get_permalink() ) ),
270
				'blog_id'              => (int) get_current_blog_id(),
271
				'meta_data'            => array( 'camera', 'aperture', 'shutter_speed', 'focal_length', 'copyright' )
272
			);
273
274
			if ( ! isset( $localize_strings['jetpack_comments_iframe_src'] ) || empty( $localize_strings['jetpack_comments_iframe_src'] ) ) {
275
				// We're not using Comments after all, so fallback to standard local comments.
276
277
				if ( $is_logged_in ) {
278
					$localize_strings['local_comments_commenting_as'] = '<p id="jp-carousel-commenting-as">' . sprintf( __( 'Commenting as %s', 'jetpack' ), $current_user->data->display_name ) . '</p>';
279
				} else {
280
					if ( $comment_registration ) {
281
						$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>';
282
					} else {
283
						$required = ( $require_name_email ) ? __( '%s (Required)', 'jetpack' ) : '%s';
284
						$localize_strings['local_comments_commenting_as'] = ''
285
							. '<fieldset><label for="email">' . sprintf( $required, __( 'Email', 'jetpack' ) ) . '</label> '
286
							. '<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>'
287
							. '<fieldset><label for="author">' . sprintf( $required, __( 'Name', 'jetpack' ) ) . '</label> '
288
							. '<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>'
289
							. '<fieldset><label for="url">' . __( 'Website', 'jetpack' ) . '</label> '
290
							. '<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>';
291
						}
292
				}
293
			}
294
295
			/**
296
			 * Handle WP stats for images in full-screen.
297
			 * Build string with tracking info.
298
			 */
299
300
			/**
301
			 * Filter if Jetpack should enable stats collection on carousel views
302
			 *
303
			 * @module carousel
304
			 *
305
			 * @since 4.3.2
306
			 *
307
			 * @param bool Enable Jetpack Carousel stat collection. Default false.
308
			 */
309
			if ( apply_filters( 'jetpack_enable_carousel_stats', false ) && in_array( 'stats', Jetpack::get_active_modules() ) && ! Jetpack::is_development_mode() ) {
310
				$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;
311
312
				// Set the stats as empty if user is logged in but logged-in users shouldn't be tracked.
313 View Code Duplication
				if ( is_user_logged_in() && function_exists( 'stats_get_options' ) ) {
314
					$stats_options = stats_get_options();
315
					$track_loggedin_users = isset( $stats_options['reg_users'] ) ? (bool) $stats_options['reg_users'] : false;
316
317
					if ( ! $track_loggedin_users ) {
318
						$localize_strings['stats'] = '';
319
					}
320
				}
321
			}
322
323
			/**
324
			 * Filter the strings passed to the Carousel's js file.
325
			 *
326
			 * @module carousel
327
			 *
328
			 * @since 1.6.0
329
			 *
330
			 * @param array $localize_strings Array of strings passed to the Jetpack js file.
331
			 */
332
			$localize_strings = apply_filters( 'jp_carousel_localize_strings', $localize_strings );
333
			wp_localize_script( 'jetpack-carousel', 'jetpackCarouselStrings', $localize_strings );
334
			wp_enqueue_style( 'jetpack-carousel', plugins_url( 'jetpack-carousel.css', __FILE__ ), array(), $this->asset_version( '20120629' ) );
335
			wp_style_add_data( 'jetpack-carousel', 'rtl', 'replace' );
336
337
			wp_register_style( 'jetpack-carousel-ie8fix', plugins_url( 'jetpack-carousel-ie8fix.css', __FILE__ ), array(), $this->asset_version( '20121024' ) );
338
			$GLOBALS['wp_styles']->add_data( 'jetpack-carousel-ie8fix', 'conditional', 'lte IE 8' );
339
			wp_enqueue_style( 'jetpack-carousel-ie8fix' );
340
341
			/**
342
			 * Fires after carousel assets are enqueued for the first time.
343
			 * Allows for adding additional assets to the carousel page.
344
			 *
345
			 * @module carousel
346
			 *
347
			 * @since 1.6.0
348
			 *
349
			 * @param bool $first_run First load if Carousel on the page.
350
			 * @param array $localized_strings Array of strings passed to the Jetpack js file.
351
			 */
352
			do_action( 'jp_carousel_enqueue_assets', $this->first_run, $localize_strings );
353
354
			$this->first_run = false;
355
		}
356
	}
357
358
	function set_in_gallery( $output ) {
359
		$this->in_gallery = true;
360
		return $output;
361
	}
362
363
	/**
364
	 * Adds data-* attributes required by carousel to img tags in post HTML
365
	 * content. To be used by 'the_content' filter.
366
	 *
367
	 * @see add_data_to_images()
368
	 * @see wp_make_content_images_responsive() in wp-includes/media.php
369
	 *
370
	 * @param string $content HTML content of the post
371
	 * @return string Modified HTML content of the post
372
	 */
373
	function add_data_img_tags_and_enqueue_assets( $content ) {
374
		if ( ! preg_match_all( '/<img [^>]+>/', $content, $matches ) ) {
375
			return $content;
376
		}
377
		$selected_images = array();
378
379
		foreach( $matches[0] as $image_html ) {
380
			if ( preg_match( '/wp-image-([0-9]+)/i', $image_html, $class_id ) &&
381
				( $attachment_id = absint( $class_id[1] ) ) ) {
382
				/*
383
				 * If exactly the same image tag is used more than once, overwrite it.
384
				 * All identical tags will be replaced later with 'str_replace()'.
385
				 */
386
				$selected_images[ $attachment_id  ] = $image_html;
387
			}
388
		}
389
390
		$find        = array();
391
		$replace     = array();
392
		if ( empty( $selected_images ) ) {
393
			return $content;
394
		}
395
396
		$attachments = get_posts( array(
397
			'include' => array_keys( $selected_images ),
398
			'post_type' => 'any',
399
			'post_status' => 'any'
400
		) );
401
402
		foreach ( $attachments as $attachment ) {
403
			$image_html = $selected_images[ $attachment->ID ];
404
405
			$attributes = $this->add_data_to_images( array(), $attachment );
406
			$attributes_html = '';
407
			foreach( $attributes as $k => $v ) {
408
				$attributes_html .= esc_attr( $k ) . '="' . esc_attr( $v ) . '" ';
409
			}
410
411
			$find[]    = $image_html;
412
			$replace[] = str_replace( '<img ', "<img $attributes_html", $image_html );
413
		}
414
415
		$content = str_replace( $find, $replace, $content );
416
		$this->enqueue_assets();
417
		return $content;
418
	}
419
420
	function add_data_to_images( $attr, $attachment = null ) {
421
		$attachment_id   = intval( $attachment->ID );
422
		$orig_file       = wp_get_attachment_image_src( $attachment_id, 'full' );
423
		$orig_file       = isset( $orig_file[0] ) ? $orig_file[0] : wp_get_attachment_url( $attachment_id );
424
		$meta            = wp_get_attachment_metadata( $attachment_id );
425
		$size            = isset( $meta['width'] ) ? intval( $meta['width'] ) . ',' . intval( $meta['height'] ) : '';
426
		$img_meta        = ( ! empty( $meta['image_meta'] ) ) ? (array) $meta['image_meta'] : array();
427
		$comments_opened = intval( comments_open( $attachment_id ) );
428
429
		 /*
430
		 * Note: Cannot generate a filename from the width and height wp_get_attachment_image_src() returns because
431
		 * it takes the $content_width global variable themes can set in consideration, therefore returning sizes
432
		 * which when used to generate a filename will likely result in a 404 on the image.
433
		 * $content_width has no filter we could temporarily de-register, run wp_get_attachment_image_src(), then
434
		 * re-register. So using returned file URL instead, which we can define the sizes from through filename
435
		 * parsing in the JS, as this is a failsafe file reference.
436
		 *
437
		 * EG with Twenty Eleven activated:
438
		 * 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) }
439
		 *
440
		 * EG with Twenty Ten activated:
441
		 * 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) }
442
		 */
443
444
		$medium_file_info = wp_get_attachment_image_src( $attachment_id, 'medium' );
445
		$medium_file      = isset( $medium_file_info[0] ) ? $medium_file_info[0] : '';
446
447
		$large_file_info  = wp_get_attachment_image_src( $attachment_id, 'large' );
448
		$large_file       = isset( $large_file_info[0] ) ? $large_file_info[0] : '';
449
450
		$attachment       = get_post( $attachment_id );
451
		$attachment_title = wptexturize( $attachment->post_title );
452
		$attachment_desc  = wpautop( wptexturize( $attachment->post_content ) );
453
		// Not yet providing geo-data, need to "fuzzify" for privacy
454 View Code Duplication
		if ( ! empty( $img_meta ) ) {
455
			foreach ( $img_meta as $k => $v ) {
456
				if ( 'latitude' == $k || 'longitude' == $k )
457
					unset( $img_meta[$k] );
458
			}
459
		}
460
461
		// See https://github.com/Automattic/jetpack/issues/2765
462
		if ( isset( $img_meta['keywords'] ) ) {
463
			unset( $img_meta['keywords'] );
464
		}
465
466
		$img_meta = json_encode( array_map( 'strval', $img_meta ) );
467
468
		$attr['data-attachment-id']     = $attachment_id;
469
		$attr['data-permalink']         = esc_attr( get_permalink( $attachment->ID ) );
470
		$attr['data-orig-file']         = esc_attr( $orig_file );
471
		$attr['data-orig-size']         = $size;
472
		$attr['data-comments-opened']   = $comments_opened;
473
		$attr['data-image-meta']        = esc_attr( $img_meta );
474
		$attr['data-image-title']       = esc_attr( htmlspecialchars( $attachment_title ) );
475
		$attr['data-image-description'] = esc_attr( htmlspecialchars( $attachment_desc ) );
476
		$attr['data-medium-file']       = esc_attr( $medium_file );
477
		$attr['data-large-file']        = esc_attr( $large_file );
478
479
		return $attr;
480
	}
481
482
	function add_data_to_container( $html ) {
483
		global $post;
484
485
		if ( isset( $post ) ) {
486
			$blog_id = (int) get_current_blog_id();
487
488
			$extra_data = array(
489
				'data-carousel-extra' => array(
490
					'blog_id' => $blog_id,
491
					'permalink' => get_permalink( $post->ID ),
492
					)
493
				);
494
495
			/**
496
			 * Filter the data added to the Gallery container.
497
			 *
498
			 * @module carousel
499
			 *
500
			 * @since 1.6.0
501
			 *
502
			 * @param array $extra_data Array of data about the site and the post.
503
			 */
504
			$extra_data = apply_filters( 'jp_carousel_add_data_to_container', $extra_data );
505
			foreach ( (array) $extra_data as $data_key => $data_values ) {
506
				$html = str_replace( '<div ', '<div ' . esc_attr( $data_key ) . "='" . json_encode( $data_values ) . "' ", $html );
507
			}
508
		}
509
510
		return $html;
511
	}
512
513
	function get_attachment_comments() {
514
		if ( ! headers_sent() )
515
			header('Content-type: text/javascript');
516
517
		/**
518
		 * Allows for the checking of privileges of the blog user before comments
519
		 * are packaged as JSON and sent back from the get_attachment_comments
520
		 * AJAX endpoint
521
		 *
522
		 * @module carousel
523
		 *
524
		 * @since 1.6.0
525
		 */
526
		do_action('jp_carousel_check_blog_user_privileges');
527
528
		$attachment_id = ( isset( $_REQUEST['id'] ) ) ? (int) $_REQUEST['id'] : 0;
529
		$offset        = ( isset( $_REQUEST['offset'] ) ) ? (int) $_REQUEST['offset'] : 0;
530
531
		if ( ! $attachment_id ) {
532
			echo json_encode( __( 'Missing attachment ID.', 'jetpack' ) );
533
			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...
534
		}
535
536
		if ( $offset < 1 )
537
			$offset = 0;
538
539
		$comments = get_comments( array(
540
			'status'  => 'approve',
541
			'order'   => ( 'asc' == get_option('comment_order') ) ? 'ASC' : 'DESC',
542
			'number'  => 10,
543
			'offset'  => $offset,
544
			'post_id' => $attachment_id,
545
		) );
546
547
		$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...
548
549
		// Can't just send the results, they contain the commenter's email address.
550
		foreach ( $comments as $comment ) {
551
			$avatar = get_avatar( $comment->comment_author_email, 64 );
552
			if( ! $avatar )
553
				$avatar = '';
554
			$out[] = array(
555
				'id'              => $comment->comment_ID,
556
				'parent_id'       => $comment->comment_parent,
557
				'author_markup'   => get_comment_author_link( $comment->comment_ID ),
558
				'gravatar_markup' => $avatar,
559
				'date_gmt'        => $comment->comment_date_gmt,
560
				'content'         => wpautop($comment->comment_content),
561
			);
562
		}
563
564
		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...
565
	}
566
567
	function post_attachment_comment() {
568
		if ( ! headers_sent() )
569
			header('Content-type: text/javascript');
570
571
		if ( empty( $_POST['nonce'] ) || ! wp_verify_nonce($_POST['nonce'], 'carousel_nonce') )
572
			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...
573
574
		$_blog_id = (int) $_POST['blog_id'];
575
		$_post_id = (int) $_POST['id'];
576
		$comment = $_POST['comment'];
577
578
		if ( empty( $_blog_id ) )
579
			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...
580
581
		if ( empty( $_post_id ) )
582
			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...
583
584
		if ( empty( $comment ) )
585
			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...
586
587
		// Used in context like NewDash
588
		$switched = false;
589
		if ( is_multisite() && $_blog_id != get_current_blog_id() ) {
590
			switch_to_blog( $_blog_id );
591
			$switched = true;
592
		}
593
594
		/** This action is documented in modules/carousel/jetpack-carousel.php */
595
		do_action('jp_carousel_check_blog_user_privileges');
596
597
		if ( ! comments_open( $_post_id ) )
598
			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...
599
600
		if ( is_user_logged_in() ) {
601
			$user         = wp_get_current_user();
602
			$user_id      = $user->ID;
603
			$display_name = $user->display_name;
604
			$email        = $user->user_email;
605
			$url          = $user->user_url;
606
607
			if ( empty( $user_id ) )
608
				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...
609
		} else {
610
			$user_id      = 0;
611
			$display_name = $_POST['author'];
612
			$email        = $_POST['email'];
613
			$url          = $_POST['url'];
614
615
			if ( get_option( 'require_name_email' ) ) {
616
				if ( empty( $display_name ) )
617
					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...
618
619
				if ( empty( $email ) )
620
					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...
621
622
				if ( ! is_email( $email ) )
623
					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...
624
			}
625
		}
626
627
		$comment_data =  array(
628
			'comment_content'      => $comment,
629
			'comment_post_ID'      => $_post_id,
630
			'comment_author'       => $display_name,
631
			'comment_author_email' => $email,
632
			'comment_author_url'   => $url,
633
			'comment_approved'     => 0,
634
			'comment_type'         => '',
635
		);
636
637
		if ( ! empty( $user_id ) )
638
			$comment_data['user_id'] = $user_id;
639
640
		// Note: wp_new_comment() sanitizes and validates the values (too).
641
		$comment_id = wp_new_comment( $comment_data );
642
643
		/**
644
		 * Fires before adding a new comment to the database via the get_attachment_comments ajax endpoint.
645
		 *
646
		 * @module carousel
647
		 *
648
		 * @since 1.6.0
649
		 */
650
		do_action( 'jp_carousel_post_attachment_comment' );
651
		$comment_status = wp_get_comment_status( $comment_id );
652
653
		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...
654
			restore_current_blog();
655
656
		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...
657
	}
658
659
	function register_settings() {
660
		add_settings_section('carousel_section', __( 'Image Gallery Carousel', 'jetpack' ), array( $this, 'carousel_section_callback' ), 'media');
661
662
		if ( ! $this->in_jetpack ) {
663
			add_settings_field('carousel_enable_it', __( 'Enable carousel', 'jetpack' ), array( $this, 'carousel_enable_it_callback' ), 'media', 'carousel_section' );
664
			register_setting( 'media', 'carousel_enable_it', array( $this, 'carousel_enable_it_sanitize' ) );
665
		}
666
667
		add_settings_field('carousel_background_color', __( 'Background color', 'jetpack' ), array( $this, 'carousel_background_color_callback' ), 'media', 'carousel_section' );
668
		register_setting( 'media', 'carousel_background_color', array( $this, 'carousel_background_color_sanitize' ) );
669
670
		add_settings_field('carousel_display_exif', __( 'Metadata', 'jetpack'), array( $this, 'carousel_display_exif_callback' ), 'media', 'carousel_section' );
671
		register_setting( 'media', 'carousel_display_exif', array( $this, 'carousel_display_exif_sanitize' ) );
672
673
		// No geo setting yet, need to "fuzzify" data first, for privacy
674
		// add_settings_field('carousel_display_geo', __( 'Geolocation', 'jetpack' ), array( $this, 'carousel_display_geo_callback' ), 'media', 'carousel_section' );
675
		// register_setting( 'media', 'carousel_display_geo', array( $this, 'carousel_display_geo_sanitize' ) );
676
	}
677
678
	// Fulfill the settings section callback requirement by returning nothing
679
	function carousel_section_callback() {
680
		return;
681
	}
682
683
	function test_1or0_option( $value, $default_to_1 = true ) {
684
		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...
685
			// Binary false (===) of $value means it has not yet been set, in which case we do want to default sites to 1
686
			if ( false === $value )
687
				$value = 1;
688
		}
689
		return ( 1 == $value ) ? 1 : 0;
690
	}
691
692
	function sanitize_1or0_option( $value ) {
693
		return ( 1 == $value ) ? 1 : 0;
694
	}
695
696
	function settings_checkbox($name, $label_text, $extra_text = '', $default_to_checked = true) {
697
		if ( empty( $name ) )
698
			return;
699
		$option = $this->test_1or0_option( get_option( $name ), $default_to_checked );
700
		echo '<fieldset>';
701
		echo '<input type="checkbox" name="'.esc_attr($name).'" id="'.esc_attr($name).'" value="1" ';
702
		checked( '1', $option );
703
		echo '/> <label for="'.esc_attr($name).'">'.$label_text.'</label>';
704
		if ( ! empty( $extra_text ) )
705
			echo '<p class="description">'.$extra_text.'</p>';
706
		echo '</fieldset>';
707
	}
708
709
	function settings_select($name, $values, $extra_text = '') {
710
		if ( empty( $name ) || ! is_array( $values ) || empty( $values ) )
711
			return;
712
		$option = get_option( $name );
713
		echo '<fieldset>';
714
		echo '<select name="'.esc_attr($name).'" id="'.esc_attr($name).'">';
715
		foreach( $values as $key => $value ) {
716
			echo '<option value="'.esc_attr($key).'" ';
717
			selected( $key, $option );
718
			echo '>'.esc_html($value).'</option>';
719
		}
720
		echo '</select>';
721
		if ( ! empty( $extra_text ) )
722
			echo '<p class="description">'.$extra_text.'</p>';
723
		echo '</fieldset>';
724
	}
725
726
	function carousel_display_exif_callback() {
727
		$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' ) );
728
	}
729
730
	function carousel_display_exif_sanitize( $value ) {
731
		return $this->sanitize_1or0_option( $value );
732
	}
733
734
	function carousel_display_geo_callback() {
735
		$this->settings_checkbox( 'carousel_display_geo', __( 'Show map of photo location in carousel, when available.', 'jetpack' ) );
736
	}
737
738
	function carousel_display_geo_sanitize( $value ) {
739
		return $this->sanitize_1or0_option( $value );
740
	}
741
742
	function carousel_background_color_callback() {
743
		$this->settings_select( 'carousel_background_color', array( 'black' => __( 'Black', 'jetpack' ), 'white' => __( 'White', 'jetpack', 'jetpack' ) ) );
744
	}
745
746
	function carousel_background_color_sanitize( $value ) {
747
		return ( 'white' == $value ) ? 'white' : 'black';
748
	}
749
750
	function carousel_enable_it_callback() {
751
		$this->settings_checkbox( 'carousel_enable_it', __( 'Display images in full-size carousel slideshow.', 'jetpack' ) );
752
	}
753
754
	function carousel_enable_it_sanitize( $value ) {
755
		return $this->sanitize_1or0_option( $value );
756
	}
757
}
758
759
new Jetpack_Carousel;
760