Completed
Push — jetpack-fusion-mock-files ( e51750...3b1561 )
by
unknown
13:31
created

modules/carousel/jetpack-carousel.php (8 issues)

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

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