Completed
Push — update/add-csstidy-config-sett... ( 5d5261...a816cd )
by
unknown
548:09 queued 537:58
created

Jetpack_Carousel::get_attachment_comments()   D

Complexity

Conditions 15
Paths 136

Size

Total Lines 119

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 15
nc 136
nop 0
dl 0
loc 119
rs 4.4932
c 0
b 0
f 0

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
use Automattic\Jetpack\Assets;
3
use Automattic\Jetpack\Status;
4
/*
5
Plugin Name: Jetpack Carousel
6
Plugin URL: https://wordpress.com/
7
Description: Transform your standard image galleries into an immersive full-screen experience.
8
Version: 0.1
9
Author: Automattic
10
11
Released under the GPL v.2 license.
12
13
This program is distributed in the hope that it will be useful,
14
but WITHOUT ANY WARRANTY; without even the implied warranty of
15
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16
GNU General Public License for more details.
17
*/
18
class Jetpack_Carousel {
19
20
	public $prebuilt_widths = array( 370, 700, 1000, 1200, 1400, 2000 );
21
22
	public $first_run = true;
23
24
	public $in_gallery = false;
25
26
	public $in_jetpack = true;
27
28
	public $single_image_gallery_enabled = false;
29
30
	public $single_image_gallery_enabled_media_file = false;
31
32
	function __construct() {
33
		add_action( 'init', array( $this, 'init' ) );
34
	}
35
36
	function init() {
37
		if ( $this->maybe_disable_jp_carousel() ) {
38
			return;
39
		}
40
41
		$this->in_jetpack = ( class_exists( 'Jetpack' ) && method_exists( 'Jetpack', 'enable_module_configurable' ) ) ? true : false;
42
43
		$this->single_image_gallery_enabled            = ! $this->maybe_disable_jp_carousel_single_images();
44
		$this->single_image_gallery_enabled_media_file = $this->maybe_enable_jp_carousel_single_images_media_file();
45
46
		if ( is_admin() ) {
47
			// Register the Carousel-related related settings
48
			add_action( 'admin_init', array( $this, 'register_settings' ), 5 );
49
			if ( ! $this->in_jetpack ) {
50
				if ( 0 == $this->test_1or0_option( get_option( 'carousel_enable_it' ), true ) ) {
51
					return; // Carousel disabled, abort early, but still register setting so user can switch it back on
52
				}
53
			}
54
			// If in admin, register the ajax endpoints.
55
			add_action( 'wp_ajax_get_attachment_comments', array( $this, 'get_attachment_comments' ) );
56
			add_action( 'wp_ajax_nopriv_get_attachment_comments', array( $this, 'get_attachment_comments' ) );
57
			add_action( 'wp_ajax_post_attachment_comment', array( $this, 'post_attachment_comment' ) );
58
			add_action( 'wp_ajax_nopriv_post_attachment_comment', array( $this, 'post_attachment_comment' ) );
59
		} else {
60
			if ( ! $this->in_jetpack ) {
61
				if ( 0 == $this->test_1or0_option( get_option( 'carousel_enable_it' ), true ) ) {
62
					return; // Carousel disabled, abort early
63
				}
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
			add_filter( 'the_content', array( $this, 'check_content_for_blocks' ), 1 );
82
			add_filter( 'jetpack_tiled_galleries_block_content', array( $this, 'add_data_img_tags_and_enqueue_assets' ) );
83
			if ( $this->single_image_gallery_enabled ) {
84
				add_filter( 'the_content', array( $this, 'add_data_img_tags_and_enqueue_assets' ) );
85
			}
86
		}
87
88
		if ( $this->in_jetpack ) {
89
			Jetpack::enable_module_configurable( dirname( dirname( __FILE__ ) ) . '/carousel.php' );
90
		}
91
	}
92
93
	function maybe_disable_jp_carousel() {
94
		/**
95
		 * Allow third-party plugins or themes to disable Carousel.
96
		 *
97
		 * @module carousel
98
		 *
99
		 * @since 1.6.0
100
		 *
101
		 * @param bool false Should Carousel be disabled? Default to false.
102
		 */
103
		return apply_filters( 'jp_carousel_maybe_disable', false );
104
	}
105
106
	function maybe_disable_jp_carousel_single_images() {
107
		/**
108
		 * Allow third-party plugins or themes to disable Carousel for single images.
109
		 *
110
		 * @module carousel
111
		 *
112
		 * @since 4.5.0
113
		 *
114
		 * @param bool false Should Carousel be disabled for single images? Default to false.
115
		 */
116
		return apply_filters( 'jp_carousel_maybe_disable_single_images', false );
117
	}
118
119
	function maybe_enable_jp_carousel_single_images_media_file() {
120
		/**
121
		 * Allow third-party plugins or themes to enable Carousel
122
		 * for single images linking to 'Media File' (full size image).
123
		 *
124
		 * @module carousel
125
		 *
126
		 * @since 4.5.0
127
		 *
128
		 * @param bool false Should Carousel be enabled for single images linking to 'Media File'? Default to false.
129
		 */
130
		return apply_filters( 'jp_carousel_load_for_images_linked_to_file', false );
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
			class_exists( 'Jetpack_AMP_Support' )
159
			&& Jetpack_AMP_Support::is_amp_request()
160
		) {
161
			return $output;
162
		}
163
164
		if (
165
			! empty( $output ) &&
166
			/**
167
			 * Allow third-party plugins or themes to force-enable Carousel.
168
			 *
169
			 * @module carousel
170
			 *
171
			 * @since 1.9.0
172
			 *
173
			 * @param bool false Should we force enable Carousel? Default to false.
174
			 */
175
			! apply_filters( 'jp_carousel_force_enable', false )
176
		) {
177
			// Bail because someone is overriding the [gallery] shortcode.
178
			remove_filter( 'gallery_style', array( $this, 'add_data_to_container' ) );
179
			remove_filter( 'wp_get_attachment_image_attributes', array( $this, 'add_data_to_images' ) );
180
			remove_filter( 'the_content', array( $this, 'add_data_img_tags_and_enqueue_assets' ) );
181
			// Display message that carousel has bailed, if user is super_admin, and if we're not on WordPress.com.
182
			if (
183
				is_super_admin() &&
184
				! ( defined( 'IS_WPCOM' ) && IS_WPCOM )
185
			) {
186
				add_filter( 'post_gallery', array( $this, 'display_bail_message' ) );
187
			}
188
			return $output;
189
		}
190
191
		/**
192
		 * Fires when thumbnails are shown in Carousel.
193
		 *
194
		 * @module carousel
195
		 *
196
		 * @since 1.6.0
197
		 **/
198
		do_action( 'jp_carousel_thumbnails_shown' );
199
200
		$this->enqueue_assets();
201
202
		return $output;
203
	}
204
205
	/**
206
	 * Check if the content of a post uses gallery blocks. To be used by 'the_content' filter.
207
	 *
208
	 * @since 6.8.0
209
	 *
210
	 * @param string $content Post content.
211
	 *
212
	 * @return string $content Post content.
213
	 */
214
	function check_content_for_blocks( $content ) {
215
		if (
216
			class_exists( 'Jetpack_AMP_Support' )
217
			&& Jetpack_AMP_Support::is_amp_request()
218
		) {
219
			return $content;
220
		}
221
222
		if ( has_block( 'gallery', $content ) || has_block( 'jetpack/tiled-gallery', $content ) ) {
223
			$this->enqueue_assets();
224
			$content = $this->add_data_to_container( $content );
225
		}
226
		return $content;
227
	}
228
229
	function enqueue_assets() {
230
		if ( $this->first_run ) {
231
			wp_enqueue_script(
232
				'jetpack-carousel',
233
				Assets::get_file_url_for_environment(
234
					'_inc/build/carousel/jetpack-carousel.min.js',
235
					'modules/carousel/jetpack-carousel.js'
236
				),
237
				array( 'jquery' ),
238
				$this->asset_version( JETPACK__VERSION ),
239
				true
240
			);
241
242
			// 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)
243
			// Also: not hardcoding path since there is no guarantee site is running on site root in self-hosted context.
244
			$is_logged_in         = is_user_logged_in();
245
			$comment_registration = (int) get_option( 'comment_registration' );
246
			$require_name_email   = (int) get_option( 'require_name_email' );
247
			$localize_strings     = array(
248
				'widths'                          => $this->prebuilt_widths,
249
				'is_logged_in'                    => $is_logged_in,
250
				'lang'                            => strtolower( substr( get_locale(), 0, 2 ) ),
251
				'ajaxurl'                         => set_url_scheme( admin_url( 'admin-ajax.php' ) ),
252
				'nonce'                           => wp_create_nonce( 'carousel_nonce' ),
253
				'display_exif'                    => $this->test_1or0_option( Jetpack_Options::get_option_and_ensure_autoload( 'carousel_display_exif', true ) ),
254
				'display_comments'                => $this->test_1or0_option( Jetpack_Options::get_option_and_ensure_autoload( 'carousel_display_comments', true ) ),
255
				'display_geo'                     => $this->test_1or0_option( Jetpack_Options::get_option_and_ensure_autoload( 'carousel_display_geo', true ) ),
256
				'single_image_gallery'            => $this->single_image_gallery_enabled,
257
				'single_image_gallery_media_file' => $this->single_image_gallery_enabled_media_file,
258
				'background_color'                => $this->carousel_background_color_sanitize( Jetpack_Options::get_option_and_ensure_autoload( 'carousel_background_color', '' ) ),
259
				'comment'                         => __( 'Comment', 'jetpack' ),
260
				'post_comment'                    => __( 'Post Comment', 'jetpack' ),
261
				'write_comment'                   => __( 'Write a Comment...', 'jetpack' ),
262
				'loading_comments'                => __( 'Loading Comments...', 'jetpack' ),
263
				'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}' ),
264
				'no_comment_text'                 => __( 'Please be sure to submit some text with your comment.', 'jetpack' ),
265
				'no_comment_email'                => __( 'Please provide an email address to comment.', 'jetpack' ),
266
				'no_comment_author'               => __( 'Please provide your name to comment.', 'jetpack' ),
267
				'comment_post_error'              => __( 'Sorry, but there was an error posting your comment. Please try again later.', 'jetpack' ),
268
				'comment_approved'                => __( 'Your comment was approved.', 'jetpack' ),
269
				'comment_unapproved'              => __( 'Your comment is in moderation.', 'jetpack' ),
270
				'camera'                          => __( 'Camera', 'jetpack' ),
271
				'aperture'                        => __( 'Aperture', 'jetpack' ),
272
				'shutter_speed'                   => __( 'Shutter Speed', 'jetpack' ),
273
				'focal_length'                    => __( 'Focal Length', 'jetpack' ),
274
				'copyright'                       => __( 'Copyright', 'jetpack' ),
275
				'comment_registration'            => $comment_registration,
276
				'require_name_email'              => $require_name_email,
277
				/** This action is documented in core/src/wp-includes/link-template.php */
278
				'login_url'                       => wp_login_url( apply_filters( 'the_permalink', get_permalink() ) ),
279
				'blog_id'                         => (int) get_current_blog_id(),
280
				'meta_data'                       => array( 'camera', 'aperture', 'shutter_speed', 'focal_length', 'copyright' ),
281
			);
282
283
			/**
284
			 * Handle WP stats for images in full-screen.
285
			 * Build string with tracking info.
286
			 */
287
288
			/**
289
			 * Filter if Jetpack should enable stats collection on carousel views
290
			 *
291
			 * @module carousel
292
			 *
293
			 * @since 4.3.2
294
			 *
295
			 * @param bool Enable Jetpack Carousel stat collection. Default false.
296
			 */
297
			if ( apply_filters( 'jetpack_enable_carousel_stats', false ) && in_array( 'stats', Jetpack::get_active_modules(), true ) && ! ( new Status() )->is_offline_mode() ) {
298
				$localize_strings['stats'] = 'blog=' . Jetpack_Options::get_option( 'id' ) . '&host=' . wp_parse_url( get_option( 'home' ), PHP_URL_HOST ) . '&v=ext&j=' . JETPACK__API_VERSION . ':' . JETPACK__VERSION;
299
300
				// Set the stats as empty if user is logged in but logged-in users shouldn't be tracked.
301 View Code Duplication
				if ( is_user_logged_in() && function_exists( 'stats_get_options' ) ) {
302
					$stats_options        = stats_get_options();
303
					$track_loggedin_users = isset( $stats_options['reg_users'] ) ? (bool) $stats_options['reg_users'] : false;
304
305
					if ( ! $track_loggedin_users ) {
306
						$localize_strings['stats'] = '';
307
					}
308
				}
309
			}
310
311
			/**
312
			 * Filter the strings passed to the Carousel's js file.
313
			 *
314
			 * @module carousel
315
			 *
316
			 * @since 1.6.0
317
			 *
318
			 * @param array $localize_strings Array of strings passed to the Jetpack js file.
319
			 */
320
			$localize_strings = apply_filters( 'jp_carousel_localize_strings', $localize_strings );
321
			wp_localize_script( 'jetpack-carousel', 'jetpackCarouselStrings', $localize_strings );
322
			wp_enqueue_style( 'jetpack-carousel', plugins_url( 'jetpack-carousel.css', __FILE__ ), array(), $this->asset_version( JETPACK__VERSION ) );
323
			wp_style_add_data( 'jetpack-carousel', 'rtl', 'replace' );
324
325
			/**
326
			 * Fires after carousel assets are enqueued for the first time.
327
			 * Allows for adding additional assets to the carousel page.
328
			 *
329
			 * @module carousel
330
			 *
331
			 * @since 1.6.0
332
			 *
333
			 * @param bool $first_run First load if Carousel on the page.
334
			 * @param array $localized_strings Array of strings passed to the Jetpack js file.
335
			 */
336
			do_action( 'jp_carousel_enqueue_assets', $this->first_run, $localize_strings );
337
338
			// Add the carousel skeleton to the page.
339
			$this->localize_strings = $localize_strings;
0 ignored issues
show
Bug introduced by
The property localize_strings does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
340
			add_action( 'wp_footer', array( $this, 'add_carousel_skeleton' ) );
341
342
			$this->first_run = false;
343
		}
344
	}
345
346
	/**
347
	 * Generate the HTML skeleton that will be picked up by the Carousel JS and used for showing the carousel.
348
	 */
349
	public function add_carousel_skeleton() {
350
		$localize_strings = $this->localize_strings;
351
		$is_light         = ( 'white' === $localize_strings['background_color'] );
352
		// Determine whether to fall back to standard local comments.
353
		$use_local_comments = ! isset( $localize_strings['jetpack_comments_iframe_src'] ) || empty( $localize_strings['jetpack_comments_iframe_src'] );
354
		$current_user       = wp_get_current_user();
355
		$require_name_email = (int) get_option( 'require_name_email' );
356
		/* translators: %s is replaced with a field name in the form, e.g. "Email" */
357
		$required = ( $require_name_email ) ? __( '%s (Required)', 'jetpack' ) : '%s';
358
		?>
359
360
		<div
361
			class="jp-carousel-wrap jp-carousel-transitions<?php echo( $is_light ? ' jp-carousel-light' : '' ); ?>"
362
			itemscope
363
			itemtype="https://schema.org/ImageGallery"
364
			style="display: none;">
365
			<div class="jp-carousel-overlay"></div>
366
			<div class="jp-carousel"></div>
367
			<div class="jp-carousel-fadeaway"></div>
368
			<div class="jp-carousel-info">
369
				<div class="jp-carousel-photo-info">
370
					<h2 class="jp-carousel-caption" itemprop="caption description"></h2>
371
				</div>
372
				<div class="jp-carousel-info-columns">
373
					<div class="jp-carousel-left-column-wrapper">
374
						<div class="jp-carousel-titleanddesc"></div>
375
						<!-- Intentional duplicate -->
376
						<div class="jp-carousel-photo-info">
377
							<h2 class="jp-carousel-caption" itemprop="caption description"></h2>
378
						</div>
379
						<?php if ( $localize_strings['display_comments'] ) : ?>
380
							<div id="jp-carousel-comment-form-container">
381
								<?php if ( $use_local_comments ) : ?>
382
									<?php if ( ! $localize_strings['is_logged_in'] && $localize_strings['comment_registration'] ) : ?>
383
										<div id="jp-carousel-comment-form-commenting-as">
384
											<p id="jp-carousel-commenting-as">
385
												<?php
386
													echo wp_kses(
387
														__( 'You must be <a href="#" class="jp-carousel-comment-login">logged in</a> to post a comment.', 'jetpack' ),
388
														array(
389
															'a' => array(
390
																'href'  => array(),
391
																'class' => array(),
392
															),
393
														)
394
													);
395
												?>
396
											</p>
397
										</div>
398
									<?php else : ?>
399
										<form id="jp-carousel-comment-form">
400
											<label for="jp-carousel-comment-form-comment-field" class="screen-reader-text"><?php echo esc_attr( $localize_strings['write_comment'] ); ?></label>
401
											<textarea
402
												name="comment"
403
												class="jp-carousel-comment-form-field jp-carousel-comment-form-textarea"
404
												id="jp-carousel-comment-form-comment-field"
405
												placeholder="<?php echo esc_attr( $localize_strings['write_comment'] ); ?>"
406
											></textarea>
407
											<div id="jp-carousel-comment-form-submit-and-info-wrapper">
408
												<div id="jp-carousel-comment-form-commenting-as">
409
													<?php if ( $localize_strings['is_logged_in'] ) : ?>
410
														<p id="jp-carousel-commenting-as">
411
															<?php
412
																printf(
413
																	/* translators: %s is replaced with the user's display name */
414
																	esc_html__( 'Commenting as %s', 'jetpack' ),
415
																	esc_html( $current_user->data->display_name )
416
																);
417
															?>
418
														</p>
419
													<?php else : ?>
420
														<fieldset>
421
															<label for="jp-carousel-comment-form-email-field"><?php echo esc_html( sprintf( $required, __( 'Email', 'jetpack' ) ) ); ?></label>
422
															<input type="text" name="email" class="jp-carousel-comment-form-field jp-carousel-comment-form-text-field" id="jp-carousel-comment-form-email-field" />
423
														</fieldset>
424
														<fieldset>
425
															<label for="jp-carousel-comment-form-author-field"><?php echo esc_html( sprintf( $required, __( 'Name', 'jetpack' ) ) ); ?></label>
426
															<input type="text" name="author" class="jp-carousel-comment-form-field jp-carousel-comment-form-text-field" id="jp-carousel-comment-form-author-field" />
427
														</fieldset>
428
														<fieldset>
429
															<label for="jp-carousel-comment-form-url-field"><?php esc_html_e( 'Website', 'jetpack' ); ?></label>
430
															<input type="text" name="url" class="jp-carousel-comment-form-field jp-carousel-comment-form-text-field" id="jp-carousel-comment-form-url-field" />
431
														</fieldset>
432
													<?php endif ?>
433
												</div>
434
												<input
435
													type="submit"
436
													name="submit"
437
													class="jp-carousel-comment-form-button"
438
													id="jp-carousel-comment-form-button-submit"
439
													value="<?php echo esc_attr( $localize_strings['post_comment'] ); ?>" />
440
												<span id="jp-carousel-comment-form-spinner">&nbsp;</span>
441
												<div id="jp-carousel-comment-post-results"></div>
442
											</div>
443
										</form>
444
									<?php endif ?>
445
								<?php endif ?>
446
							</div>
447
							<div class="jp-carousel-comments"></div>
448
							<div id="jp-carousel-comments-loading">
449
								<span><?php echo esc_html( $localize_strings['loading_comments'] ); ?></span>
450
							</div>
451
						<?php endif ?>
452
					</div>
453
					<div class="jp-carousel-image-meta">
454
						<div class="jp-carousel-buttons">
455
							<?php if ( $localize_strings['display_comments'] ) : ?>
456
							<a class="jp-carousel-commentlink" href="#"><?php echo esc_html( $localize_strings['comment'] ); ?></a>
457
							<?php endif ?>
458
						</div>
459
						<ul class="jp-carousel-image-exif" style="display: none;"></ul>
460
						<a class="jp-carousel-image-download" style="display: none;"></a>
461
						<div class="jp-carousel-image-map" style="display: none;"></div>
462
					</div>
463
				</div>
464
			</div>
465
			<div class="jp-carousel-next-button" style="display: none;">
466
				<span></span>
467
			</div>
468
			<div class="jp-carousel-previous-button" style="display: none;">
469
				<span></span>
470
			</div>
471
			<div class="jp-carousel-close-hint"><span>&times;</span></div>
472
		</div>
473
474
		<?php
475
	}
476
477
	function set_in_gallery( $output ) {
478
		if (
479
			class_exists( 'Jetpack_AMP_Support' )
480
			&& Jetpack_AMP_Support::is_amp_request()
481
		) {
482
			return $output;
483
		}
484
		$this->in_gallery = true;
485
		return $output;
486
	}
487
488
	/**
489
	 * Adds data-* attributes required by carousel to img tags in post HTML
490
	 * content. To be used by 'the_content' filter.
491
	 *
492
	 * @see add_data_to_images()
493
	 * @see wp_make_content_images_responsive() in wp-includes/media.php
494
	 *
495
	 * @param string $content HTML content of the post
496
	 * @return string Modified HTML content of the post
497
	 */
498
	function add_data_img_tags_and_enqueue_assets( $content ) {
499
		if (
500
			class_exists( 'Jetpack_AMP_Support' )
501
			&& Jetpack_AMP_Support::is_amp_request()
502
		) {
503
			return $this->maybe_add_amp_lightbox( $content );
504
		}
505
506
		if ( ! preg_match_all( '/<img [^>]+>/', $content, $matches ) ) {
507
			return $content;
508
		}
509
		$selected_images = array();
510
		foreach ( $matches[0] as $image_html ) {
511
			if ( preg_match( '/(wp-image-|data-id=)\"?([0-9]+)\"?/i', $image_html, $class_id ) &&
512
				! preg_match( '/wp-block-jetpack-slideshow_image/', $image_html ) ) {
513
				$attachment_id = absint( $class_id[2] );
514
				/**
515
				 * If exactly the same image tag is used more than once, overwrite it.
516
				 * All identical tags will be replaced later with 'str_replace()'.
517
				 */
518
				$selected_images[ $attachment_id  ] = $image_html;
519
			}
520
		}
521
522
		$find    = array();
523
		$replace = array();
524
		if ( empty( $selected_images ) ) {
525
			return $content;
526
		}
527
528
		$attachments = get_posts(
529
			array(
530
				'include'          => array_keys( $selected_images ),
531
				'post_type'        => 'any',
532
				'post_status'      => 'any',
533
				'suppress_filters' => false,
534
			)
535
		);
536
537
		foreach ( $attachments as $attachment ) {
538
			$image_html = $selected_images[ $attachment->ID ];
539
540
			$attributes      = $this->add_data_to_images( array(), $attachment );
541
			$attributes_html = '';
542
			foreach ( $attributes as $k => $v ) {
543
				$attributes_html .= esc_attr( $k ) . '="' . esc_attr( $v ) . '" ';
544
			}
545
546
			$find[]    = $image_html;
547
			$replace[] = str_replace( '<img ', "<img $attributes_html", $image_html );
548
		}
549
550
		$content = str_replace( $find, $replace, $content );
551
		$this->enqueue_assets();
552
		return $content;
553
	}
554
555
	function add_data_to_images( $attr, $attachment = null ) {
556
		if (
557
			class_exists( 'Jetpack_AMP_Support' )
558
			&& Jetpack_AMP_Support::is_amp_request()
559
		) {
560
			return $attr;
561
		}
562
563
		$attachment_id = (int) $attachment->ID;
564
		if ( ! wp_attachment_is_image( $attachment_id ) ) {
565
			return $attr;
566
		}
567
568
		$orig_file       = wp_get_attachment_image_src( $attachment_id, 'full' );
569
		$orig_file       = isset( $orig_file[0] ) ? $orig_file[0] : wp_get_attachment_url( $attachment_id );
570
		$meta            = wp_get_attachment_metadata( $attachment_id );
571
		$size            = isset( $meta['width'] ) ? (int) $meta['width'] . ',' . (int) $meta['height'] : '';
572
		$img_meta        = ( ! empty( $meta['image_meta'] ) ) ? (array) $meta['image_meta'] : array();
573
		$comments_opened = (int) comments_open( $attachment_id );
574
575
		/**
576
		 * Note: Cannot generate a filename from the width and height wp_get_attachment_image_src() returns because
577
		 * it takes the $content_width global variable themes can set in consideration, therefore returning sizes
578
		 * which when used to generate a filename will likely result in a 404 on the image.
579
		 * $content_width has no filter we could temporarily de-register, run wp_get_attachment_image_src(), then
580
		 * re-register. So using returned file URL instead, which we can define the sizes from through filename
581
		 * parsing in the JS, as this is a failsafe file reference.
582
		 *
583
		 * EG with Twenty Eleven activated:
584
		 * 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) }
585
		 *
586
		 * EG with Twenty Ten activated:
587
		 * 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) }
588
		 */
589
590
		$medium_file_info = wp_get_attachment_image_src( $attachment_id, 'medium' );
591
		$medium_file      = isset( $medium_file_info[0] ) ? $medium_file_info[0] : '';
592
593
		$large_file_info = wp_get_attachment_image_src( $attachment_id, 'large' );
594
		$large_file      = isset( $large_file_info[0] ) ? $large_file_info[0] : '';
595
596
		$attachment       = get_post( $attachment_id );
597
		$attachment_title = wptexturize( $attachment->post_title );
598
		$attachment_desc  = wpautop( wptexturize( $attachment->post_content ) );
599
		// Not yet providing geo-data, need to "fuzzify" for privacy
600 View Code Duplication
		if ( ! empty( $img_meta ) ) {
601
			foreach ( $img_meta as $k => $v ) {
602
				if ( 'latitude' == $k || 'longitude' == $k ) {
603
					unset( $img_meta[ $k ] );
604
				}
605
			}
606
		}
607
608
		// See https://github.com/Automattic/jetpack/issues/2765
609
		if ( isset( $img_meta['keywords'] ) ) {
610
			unset( $img_meta['keywords'] );
611
		}
612
613
		$img_meta = json_encode( array_map( 'strval', array_filter( $img_meta, 'is_scalar' ) ) );
614
615
		$attr['data-attachment-id']     = $attachment_id;
616
		$attr['data-permalink']         = esc_attr( get_permalink( $attachment->ID ) );
617
		$attr['data-orig-file']         = esc_attr( $orig_file );
618
		$attr['data-orig-size']         = $size;
619
		$attr['data-comments-opened']   = $comments_opened;
620
		$attr['data-image-meta']        = esc_attr( $img_meta );
621
		$attr['data-image-title']       = esc_attr( htmlspecialchars( $attachment_title ) );
622
		$attr['data-image-description'] = esc_attr( htmlspecialchars( $attachment_desc ) );
623
		$attr['data-medium-file']       = esc_attr( $medium_file );
624
		$attr['data-large-file']        = esc_attr( $large_file );
625
626
		return $attr;
627
	}
628
629
	function add_data_to_container( $html ) {
630
		global $post;
631
		if (
632
			class_exists( 'Jetpack_AMP_Support' )
633
			&& Jetpack_AMP_Support::is_amp_request()
634
		) {
635
			return $html;
636
		}
637
638
		if ( isset( $post ) ) {
639
			$blog_id = (int) get_current_blog_id();
640
641
			$extra_data = array(
642
				'data-carousel-extra' => array(
643
					'blog_id'   => $blog_id,
644
					'permalink' => get_permalink( $post->ID ),
645
				),
646
			);
647
648
			/**
649
			 * Filter the data added to the Gallery container.
650
			 *
651
			 * @module carousel
652
			 *
653
			 * @since 1.6.0
654
			 *
655
			 * @param array $extra_data Array of data about the site and the post.
656
			 */
657
			$extra_data = apply_filters( 'jp_carousel_add_data_to_container', $extra_data );
658
			foreach ( (array) $extra_data as $data_key => $data_values ) {
659
				$html = str_replace( '<div ', '<div ' . esc_attr( $data_key ) . "='" . wp_json_encode( $data_values ) . "' ", $html );
660
				$html = str_replace( '<ul class="wp-block-gallery', '<ul ' . esc_attr( $data_key ) . "='" . wp_json_encode( $data_values ) . "' class=\"wp-block-gallery", $html );
661
				$html = str_replace( '<ul class="blocks-gallery-grid', '<ul ' . esc_attr( $data_key ) . "='" . wp_json_encode( $data_values ) . "' class=\"blocks-gallery-grid", $html );
662
				$html = str_replace( '<figure class="wp-block-gallery blocks-gallery-grid', '<figure ' . esc_attr( $data_key ) . "='" . wp_json_encode( $data_values ) . "' class=\"wp-block-gallery  blocks-gallery-grid", $html );
663
			}
664
		}
665
666
		return $html;
667
	}
668
669
	/**
670
	 * Conditionally adds amp-lightbox to galleries and images.
671
	 *
672
	 * This applies to gallery blocks and shortcodes,
673
	 * in addition to images that are wrapped in a link to the page.
674
	 * Images wrapped in a link to the media file shouldn't get an amp-lightbox.
675
	 *
676
	 * @param string $content The content to possibly add amp-lightbox to.
677
	 * @return string The content, with amp-lightbox possibly added.
678
	 */
679
	public function maybe_add_amp_lightbox( $content ) {
680
		$content = preg_replace(
681
			array(
682
				'#(<figure)[^>]*(?=class=(["\']?)[^>]*wp-block-gallery[^>]*\2)#is', // Gallery block.
683
				'#(\[gallery)(?=\s+)#', // Gallery shortcode.
684
			),
685
			array(
686
				'\1 data-amp-lightbox="true" ', // https://github.com/ampproject/amp-wp/blob/1094ea03bd5dc92889405a47a8c41de1a88908de/includes/sanitizers/class-amp-gallery-block-sanitizer.php#L84.
687
				'\1 amp-lightbox="true"', // https://github.com/ampproject/amp-wp/blob/1094ea03bd5dc92889405a47a8c41de1a88908de/includes/embeds/class-amp-gallery-embed.php#L64.
688
			),
689
			$content
690
		);
691
692
		return preg_replace_callback(
693
			'#(<a[^>]* href=(["\']?)(\S+)\2>)\s*(<img[^>]*)(class=(["\']?)[^>]*wp-image-[0-9]+[^>]*\6.*>)\s*</a>#is',
694
			static function( $matches ) {
695 View Code Duplication
				if ( ! preg_match( '#\.\w+$#', $matches[3] ) ) {
696
					// The a[href] doesn't end in a file extension like .jpeg, so this is not a link to the media file, and should get a lightbox.
697
					return $matches[4] . ' data-amp-lightbox="true" lightbox="true" ' . $matches[5]; // https://github.com/ampproject/amp-wp/blob/1094ea03bd5dc92889405a47a8c41de1a88908de/includes/sanitizers/class-amp-img-sanitizer.php#L419.
698
				}
699
700
				return $matches[0];
701
			},
702
			$content
703
		);
704
	}
705
706
	function get_attachment_comments() {
707
		if ( ! headers_sent() ) {
708
			header( 'Content-type: text/javascript' );
709
		}
710
711
		/**
712
		 * Allows for the checking of privileges of the blog user before comments
713
		 * are packaged as JSON and sent back from the get_attachment_comments
714
		 * AJAX endpoint
715
		 *
716
		 * @module carousel
717
		 *
718
		 * @since 1.6.0
719
		 */
720
		do_action( 'jp_carousel_check_blog_user_privileges' );
721
722
		$attachment_id = ( isset( $_REQUEST['id'] ) ) ? (int) $_REQUEST['id'] : 0;
723
		$offset        = ( isset( $_REQUEST['offset'] ) ) ? (int) $_REQUEST['offset'] : 0;
724
725
		if ( ! $attachment_id ) {
726
			wp_send_json_error(
727
				__( 'Missing attachment ID.', 'jetpack' ),
728
				403
729
			);
730
			return;
731
		}
732
733
		$attachment_post = get_post( $attachment_id );
734
		// If we have no info about that attachment, bail.
735
		if ( ! ( $attachment_post instanceof WP_Post ) ) {
0 ignored issues
show
Bug introduced by
The class WP_Post does not exist. Did you forget a USE statement, or did you not list all dependencies?

This error could be the result of:

1. Missing dependencies

PHP Analyzer uses your composer.json file (if available) to determine the dependencies of your project and to determine all the available classes and functions. It expects the composer.json to be in the root folder of your repository.

Are you sure this class is defined by one of your dependencies, or did you maybe not list a dependency in either the require or require-dev section?

2. Missing use statement

PHP does not complain about undefined classes in ìnstanceof checks. For example, the following PHP code will work perfectly fine:

if ($x instanceof DoesNotExist) {
    // Do something.
}

If you have not tested against this specific condition, such errors might go unnoticed.

Loading history...
736
			wp_send_json_error(
737
				__( 'Missing attachment info.', 'jetpack' ),
738
				403
739
			);
740
			return;
741
		}
742
743
		// This AJAX call should only be used to fetch comments of attachments.
744
		if ( 'attachment' !== $attachment_post->post_type ) {
745
			wp_send_json_error(
746
				__( 'You aren’t authorized to do that.', 'jetpack' ),
747
				403
748
			);
749
			return;
750
		}
751
752
		$parent_post = get_post_parent( $attachment_id );
753
754
		/*
755
		 * If we have no info about that parent post, no extra checks.
756
		 * The attachment doesn't have a parent post, so is public.
757
		 * If we have a parent post, let's ensure the user has access to it.
758
		 */
759
		if ( $parent_post instanceof WP_Post ) {
0 ignored issues
show
Bug introduced by
The class WP_Post does not exist. Did you forget a USE statement, or did you not list all dependencies?

This error could be the result of:

1. Missing dependencies

PHP Analyzer uses your composer.json file (if available) to determine the dependencies of your project and to determine all the available classes and functions. It expects the composer.json to be in the root folder of your repository.

Are you sure this class is defined by one of your dependencies, or did you maybe not list a dependency in either the require or require-dev section?

2. Missing use statement

PHP does not complain about undefined classes in ìnstanceof checks. For example, the following PHP code will work perfectly fine:

if ($x instanceof DoesNotExist) {
    // Do something.
}

If you have not tested against this specific condition, such errors might go unnoticed.

Loading history...
760
			/*
761
			 * Fetch info about user making the request.
762
			 * If we have no info, bail.
763
			 * Even logged out users should get a WP_User user with id 0.
764
			 */
765
			$current_user = wp_get_current_user();
766
			if ( ! ( $current_user instanceof WP_User ) ) {
0 ignored issues
show
Bug introduced by
The class WP_User does not exist. Did you forget a USE statement, or did you not list all dependencies?

This error could be the result of:

1. Missing dependencies

PHP Analyzer uses your composer.json file (if available) to determine the dependencies of your project and to determine all the available classes and functions. It expects the composer.json to be in the root folder of your repository.

Are you sure this class is defined by one of your dependencies, or did you maybe not list a dependency in either the require or require-dev section?

2. Missing use statement

PHP does not complain about undefined classes in ìnstanceof checks. For example, the following PHP code will work perfectly fine:

if ($x instanceof DoesNotExist) {
    // Do something.
}

If you have not tested against this specific condition, such errors might go unnoticed.

Loading history...
767
				wp_send_json_error(
768
					__( 'Missing user info.', 'jetpack' ),
769
					403
770
				);
771
				return;
772
			}
773
774
			/*
775
			 * If a post is private / draft
776
			 * and the current user doesn't have access to it,
777
			 * bail.
778
			 */
779
			if (
780
				'publish' !== $parent_post->post_status
781
				&& ! current_user_can( 'read_post', $parent_post->ID )
782
			) {
783
				wp_send_json_error(
784
					__( 'You aren’t authorized to do that.', 'jetpack' ),
785
					403
786
				);
787
				return;
788
			}
789
		}
790
791
		if ( $offset < 1 ) {
792
			$offset = 0;
793
		}
794
795
		$comments = get_comments(
796
			array(
797
				'status'  => 'approve',
798
				'order'   => ( 'asc' == get_option( 'comment_order' ) ) ? 'ASC' : 'DESC',
799
				'number'  => 10,
800
				'offset'  => $offset,
801
				'post_id' => $attachment_id,
802
			)
803
		);
804
805
		$out = array();
806
807
		// Can't just send the results, they contain the commenter's email address.
808
		foreach ( $comments as $comment ) {
809
			$avatar = get_avatar( $comment->comment_author_email, 64 );
810
			if ( ! $avatar ) {
811
				$avatar = '';
812
			}
813
			$out[] = array(
814
				'id'              => $comment->comment_ID,
815
				'parent_id'       => $comment->comment_parent,
816
				'author_markup'   => get_comment_author_link( $comment->comment_ID ),
817
				'gravatar_markup' => $avatar,
818
				'date_gmt'        => $comment->comment_date_gmt,
819
				'content'         => wpautop( $comment->comment_content ),
820
			);
821
		}
822
823
		die( json_encode( $out ) );
824
	}
825
826
	function post_attachment_comment() {
827
		if ( ! headers_sent() ) {
828
			header( 'Content-type: text/javascript' );
829
		}
830
831
		if ( empty( $_POST['nonce'] ) || ! wp_verify_nonce( $_POST['nonce'], 'carousel_nonce' ) ) {
832
			die( json_encode( array( 'error' => __( 'Nonce verification failed.', 'jetpack' ) ) ) );
833
		}
834
835
		$_blog_id = (int) $_POST['blog_id'];
836
		$_post_id = (int) $_POST['id'];
837
		$comment  = $_POST['comment'];
838
839
		if ( empty( $_blog_id ) ) {
840
			die( json_encode( array( 'error' => __( 'Missing target blog ID.', 'jetpack' ) ) ) );
841
		}
842
843
		if ( empty( $_post_id ) ) {
844
			die( json_encode( array( 'error' => __( 'Missing target post ID.', 'jetpack' ) ) ) );
845
		}
846
847
		if ( empty( $comment ) ) {
848
			die( json_encode( array( 'error' => __( 'No comment text was submitted.', 'jetpack' ) ) ) );
849
		}
850
851
		// Used in context like NewDash
852
		$switched = false;
853
		if ( is_multisite() && $_blog_id != get_current_blog_id() ) {
854
			switch_to_blog( $_blog_id );
855
			$switched = true;
856
		}
857
858
		/** This action is documented in modules/carousel/jetpack-carousel.php */
859
		do_action( 'jp_carousel_check_blog_user_privileges' );
860
861 View Code Duplication
		if ( ! comments_open( $_post_id ) ) {
862
			if ( $switched ) {
863
				restore_current_blog();
864
			}
865
			die( json_encode( array( 'error' => __( 'Comments on this post are closed.', 'jetpack' ) ) ) );
866
		}
867
868
		if ( is_user_logged_in() ) {
869
			$user         = wp_get_current_user();
870
			$user_id      = $user->ID;
871
			$display_name = $user->display_name;
872
			$email        = $user->user_email;
873
			$url          = $user->user_url;
874
875 View Code Duplication
			if ( empty( $user_id ) ) {
876
				if ( $switched ) {
877
					restore_current_blog();
878
				}
879
				die( json_encode( array( 'error' => __( 'Sorry, but we could not authenticate your request.', 'jetpack' ) ) ) );
880
			}
881
		} else {
882
			$user_id      = 0;
883
			$display_name = $_POST['author'];
884
			$email        = $_POST['email'];
885
			$url          = $_POST['url'];
886
887
			if ( get_option( 'require_name_email' ) ) {
888 View Code Duplication
				if ( empty( $display_name ) ) {
889
					if ( $switched ) {
890
						restore_current_blog();
891
					}
892
					die( json_encode( array( 'error' => __( 'Please provide your name.', 'jetpack' ) ) ) );
893
				}
894
895 View Code Duplication
				if ( empty( $email ) ) {
896
					if ( $switched ) {
897
						restore_current_blog();
898
					}
899
					die( json_encode( array( 'error' => __( 'Please provide an email address.', 'jetpack' ) ) ) );
900
				}
901
902 View Code Duplication
				if ( ! is_email( $email ) ) {
903
					if ( $switched ) {
904
						restore_current_blog();
905
					}
906
					die( json_encode( array( 'error' => __( 'Please provide a valid email address.', 'jetpack' ) ) ) );
907
				}
908
			}
909
		}
910
911
		$comment_data = array(
912
			'comment_content'      => $comment,
913
			'comment_post_ID'      => $_post_id,
914
			'comment_author'       => $display_name,
915
			'comment_author_email' => $email,
916
			'comment_author_url'   => $url,
917
			'comment_approved'     => 0,
918
			'comment_type'         => 'comment',
919
		);
920
921
		if ( ! empty( $user_id ) ) {
922
			$comment_data['user_id'] = $user_id;
923
		}
924
925
		// Note: wp_new_comment() sanitizes and validates the values (too).
926
		$comment_id = wp_new_comment( $comment_data );
927
928
		/**
929
		 * Fires before adding a new comment to the database via the get_attachment_comments ajax endpoint.
930
		 *
931
		 * @module carousel
932
		 *
933
		 * @since 1.6.0
934
		 */
935
		do_action( 'jp_carousel_post_attachment_comment' );
936
		$comment_status = wp_get_comment_status( $comment_id );
937
938
		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...
939
			restore_current_blog();
940
		}
941
942
		die(
943
			json_encode(
944
				array(
945
					'comment_id'     => $comment_id,
946
					'comment_status' => $comment_status,
947
				)
948
			)
949
		);
950
	}
951
952
	function register_settings() {
953
		add_settings_section( 'carousel_section', __( 'Image Gallery Carousel', 'jetpack' ), array( $this, 'carousel_section_callback' ), 'media' );
954
955
		if ( ! $this->in_jetpack ) {
956
			add_settings_field( 'carousel_enable_it', __( 'Enable carousel', 'jetpack' ), array( $this, 'carousel_enable_it_callback' ), 'media', 'carousel_section' );
957
			register_setting( 'media', 'carousel_enable_it', array( $this, 'carousel_enable_it_sanitize' ) );
958
		}
959
960
		add_settings_field( 'carousel_background_color', __( 'Background color', 'jetpack' ), array( $this, 'carousel_background_color_callback' ), 'media', 'carousel_section' );
961
		register_setting( 'media', 'carousel_background_color', array( $this, 'carousel_background_color_sanitize' ) );
962
963
		add_settings_field( 'carousel_display_exif', __( 'Metadata', 'jetpack' ), array( $this, 'carousel_display_exif_callback' ), 'media', 'carousel_section' );
964
		register_setting( 'media', 'carousel_display_exif', array( $this, 'carousel_display_exif_sanitize' ) );
965
966
		add_settings_field( 'carousel_display_comments', __( 'Comments', 'jetpack' ), array( $this, 'carousel_display_comments_callback' ), 'media', 'carousel_section' );
967
		register_setting( 'media', 'carousel_display_comments', array( $this, 'carousel_display_comments_sanitize' ) );
968
969
		// No geo setting yet, need to "fuzzify" data first, for privacy
970
		// add_settings_field('carousel_display_geo', __( 'Geolocation', 'jetpack' ), array( $this, 'carousel_display_geo_callback' ), 'media', 'carousel_section' );
971
		// register_setting( 'media', 'carousel_display_geo', array( $this, 'carousel_display_geo_sanitize' ) );
972
	}
973
974
	// Fulfill the settings section callback requirement by returning nothing
975
	function carousel_section_callback() {
976
		return;
977
	}
978
979
	function test_1or0_option( $value, $default_to_1 = true ) {
980
		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...
981
			// Binary false (===) of $value means it has not yet been set, in which case we do want to default sites to 1
982
			if ( false === $value ) {
983
				$value = 1;
984
			}
985
		}
986
		return ( 1 == $value ) ? 1 : 0;
987
	}
988
989
	function sanitize_1or0_option( $value ) {
990
		return ( 1 == $value ) ? 1 : 0;
991
	}
992
993
	function settings_checkbox( $name, $label_text, $extra_text = '', $default_to_checked = true ) {
994
		if ( empty( $name ) ) {
995
			return;
996
		}
997
		$option = $this->test_1or0_option( get_option( $name ), $default_to_checked );
998
		echo '<fieldset>';
999
		echo '<input type="checkbox" name="' . esc_attr( $name ) . '" id="' . esc_attr( $name ) . '" value="1" ';
1000
		checked( '1', $option );
1001
		echo '/> <label for="' . esc_attr( $name ) . '">' . $label_text . '</label>';
1002
		if ( ! empty( $extra_text ) ) {
1003
			echo '<p class="description">' . $extra_text . '</p>';
1004
		}
1005
		echo '</fieldset>';
1006
	}
1007
1008
	function settings_select( $name, $values, $extra_text = '' ) {
1009
		if ( empty( $name ) || ! is_array( $values ) || empty( $values ) ) {
1010
			return;
1011
		}
1012
		$option = get_option( $name );
1013
		echo '<fieldset>';
1014
		echo '<select name="' . esc_attr( $name ) . '" id="' . esc_attr( $name ) . '">';
1015
		foreach ( $values as $key => $value ) {
1016
			echo '<option value="' . esc_attr( $key ) . '" ';
1017
			selected( $key, $option );
1018
			echo '>' . esc_html( $value ) . '</option>';
1019
		}
1020
		echo '</select>';
1021
		if ( ! empty( $extra_text ) ) {
1022
			echo '<p class="description">' . $extra_text . '</p>';
1023
		}
1024
		echo '</fieldset>';
1025
	}
1026
1027
	function carousel_display_exif_callback() {
1028
		$this->settings_checkbox( 'carousel_display_exif', __( 'Show photo metadata (<a href="https://en.wikipedia.org/wiki/Exchangeable_image_file_format" rel="noopener noreferrer" target="_blank">Exif</a>) in carousel, when available.', 'jetpack' ) );
1029
	}
1030
1031
	/**
1032
	 * Callback for checkbox and label of field that allows to toggle comments.
1033
	 */
1034
	public function carousel_display_comments_callback() {
1035
		$this->settings_checkbox( 'carousel_display_comments', esc_html__( 'Show comments area in carousel', 'jetpack' ) );
1036
	}
1037
1038
	function carousel_display_exif_sanitize( $value ) {
1039
		return $this->sanitize_1or0_option( $value );
1040
	}
1041
1042
	/**
1043
	 * Return sanitized option for value that controls whether comments will be hidden or not.
1044
	 *
1045
	 * @param number $value Value to sanitize.
1046
	 *
1047
	 * @return number Sanitized value, only 1 or 0.
1048
	 */
1049
	public function carousel_display_comments_sanitize( $value ) {
1050
		return $this->sanitize_1or0_option( $value );
1051
	}
1052
1053
	function carousel_display_geo_callback() {
1054
		$this->settings_checkbox( 'carousel_display_geo', __( 'Show map of photo location in carousel, when available.', 'jetpack' ) );
1055
	}
1056
1057
	function carousel_display_geo_sanitize( $value ) {
1058
		return $this->sanitize_1or0_option( $value );
1059
	}
1060
1061
	function carousel_background_color_callback() {
1062
		$this->settings_select(
1063
			'carousel_background_color', array(
1064
				'black' => __( 'Black', 'jetpack' ),
1065
				'white' => __( 'White', 'jetpack' ),
1066
			)
1067
		);
1068
	}
1069
1070
	function carousel_background_color_sanitize( $value ) {
1071
		return ( 'white' == $value ) ? 'white' : 'black';
1072
	}
1073
1074
	function carousel_enable_it_callback() {
1075
		$this->settings_checkbox( 'carousel_enable_it', __( 'Display images in full-size carousel slideshow.', 'jetpack' ) );
1076
	}
1077
1078
	function carousel_enable_it_sanitize( $value ) {
1079
		return $this->sanitize_1or0_option( $value );
1080
	}
1081
}
1082
1083
new Jetpack_Carousel;
1084