Completed
Push — feature/replace-yarn-1-with-pn... ( ca863a...eb625d )
by
unknown
85:44 queued 75:23
created

Jetpack_AMP_Support::is_amp_available()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
nc 2
nop 0
dl 0
loc 3
rs 10
c 0
b 0
f 0
1
<?php //phpcs:ignore WordPress.Files.FileName.InvalidClassFileName
2
3
use Automattic\Jetpack\Assets;
4
use Automattic\Jetpack\Sync\Functions;
5
6
/**
7
 * Manages compatibility with the amp-wp plugin
8
 *
9
 * @see https://github.com/Automattic/amp-wp
10
 */
11
class Jetpack_AMP_Support {
12
13
	/**
14
	 * Apply custom AMP changes on the front-end.
15
	 */
16
	public static function init() {
17
18
		// Add Stats tracking pixel on Jetpack sites when the Stats module is active.
19
		if (
20
			Jetpack::is_module_active( 'stats' )
21
			&& ! ( defined( 'IS_WPCOM' ) && IS_WPCOM )
22
		) {
23
			add_action( 'amp_post_template_footer', array( 'Jetpack_AMP_Support', 'add_stats_pixel' ) );
24
		}
25
26
		/**
27
		 * Remove this during the init hook in case users have enabled it during
28
		 * the after_setup_theme hook, which triggers before init.
29
		 */
30
		remove_theme_support( 'jetpack-devicepx' );
31
32
		// Sharing.
33
		add_filter( 'jetpack_sharing_display_markup', array( 'Jetpack_AMP_Support', 'render_sharing_html' ), 10, 2 );
34
		add_filter( 'sharing_enqueue_scripts', array( 'Jetpack_AMP_Support', 'amp_disable_sharedaddy_css' ) );
35
		add_action( 'wp_enqueue_scripts', array( 'Jetpack_AMP_Support', 'amp_enqueue_sharing_css' ) );
36
37
		// Sharing for Reader mode.
38
		if ( function_exists( 'jetpack_social_menu_include_svg_icons' ) ) {
39
			add_action( 'amp_post_template_footer', 'jetpack_social_menu_include_svg_icons' );
40
		}
41
		add_action( 'amp_post_template_css', array( 'Jetpack_AMP_Support', 'amp_reader_sharing_css' ), 10, 0 );
42
43
		// enforce freedom mode for videopress.
44
		add_filter( 'videopress_shortcode_options', array( 'Jetpack_AMP_Support', 'videopress_enable_freedom_mode' ) );
45
46
		// include Jetpack og tags when rendering native AMP head.
47
		add_action( 'amp_post_template_head', array( 'Jetpack_AMP_Support', 'amp_post_jetpack_og_tags' ) );
48
49
		// Post rendering changes for legacy AMP.
50
		add_action( 'pre_amp_render_post', array( 'Jetpack_AMP_Support', 'amp_disable_the_content_filters' ) );
51
52
		// Disable Comment Likes.
53
		add_filter( 'jetpack_comment_likes_enabled', array( 'Jetpack_AMP_Support', 'comment_likes_enabled' ) );
54
55
		// Transitional mode AMP should not have comment likes.
56
		add_filter( 'the_content', array( 'Jetpack_AMP_Support', 'disable_comment_likes_before_the_content' ) );
57
58
		// Remove the Likes button from the admin bar.
59
		add_filter( 'jetpack_admin_bar_likes_enabled', array( 'Jetpack_AMP_Support', 'disable_likes_admin_bar' ) );
60
61
		// Add post template metadata for legacy AMP.
62
		add_filter( 'amp_post_template_metadata', array( 'Jetpack_AMP_Support', 'amp_post_template_metadata' ), 10, 2 );
63
64
		// Filter photon image args for AMP Stories.
65
		add_filter( 'jetpack_photon_post_image_args', array( 'Jetpack_AMP_Support', 'filter_photon_post_image_args_for_stories' ), 10, 2 );
66
67
		// Sync the amp-options.
68
		add_filter( 'jetpack_options_whitelist', array( 'Jetpack_AMP_Support', 'filter_jetpack_options_safelist' ) );
69
	}
70
71
	/**
72
	 * Disable the Comment Likes feature on AMP views.
73
	 *
74
	 * @param bool $enabled Should comment likes be enabled.
75
	 */
76
	public static function comment_likes_enabled( $enabled ) {
77
		return $enabled && ! self::is_amp_request();
78
	}
79
80
	/**
81
	 * Apply custom AMP changes in wp-admin.
82
	 */
83
	public static function admin_init() {
84
		// disable Likes metabox for post editor if AMP canonical disabled.
85
		add_filter( 'post_flair_disable', array( 'Jetpack_AMP_Support', 'is_amp_canonical' ), 99 );
86
	}
87
88
	/**
89
	 * Is the page in AMP 'canonical mode'.
90
	 * Used when themes register support for AMP with `add_theme_support( 'amp' )`.
91
	 *
92
	 * @return bool is_amp_canonical
93
	 */
94
	public static function is_amp_canonical() {
95
		return function_exists( 'amp_is_canonical' ) && amp_is_canonical();
96
	}
97
98
	/**
99
	 * Is AMP available for this request
100
	 * This returns false for admin, CLI requests etc.
101
	 *
102
	 * @return bool is_amp_available
103
	 */
104
	public static function is_amp_available() {
105
		return ( function_exists( 'amp_is_available' ) && amp_is_available() );
106
	}
107
108
	/**
109
	 * Does the page return AMP content.
110
	 *
111
	 * @return bool $is_amp_request Are we on am AMP view.
112
	 */
113
	public static function is_amp_request() {
114
		$is_amp_request = ( function_exists( 'is_amp_endpoint' ) && is_amp_endpoint() );
115
116
		/**
117
		 * Returns true if the current request should return valid AMP content.
118
		 *
119
		 * @since 6.2.0
120
		 *
121
		 * @param boolean $is_amp_request Is this request supposed to return valid AMP content?
122
		 */
123
		return apply_filters( 'jetpack_is_amp_request', $is_amp_request );
124
	}
125
126
	/**
127
	 * Remove content filters added by Jetpack.
128
	 */
129
	public static function amp_disable_the_content_filters() {
130
		if ( defined( 'IS_WPCOM' ) && IS_WPCOM ) {
131
			add_filter( 'videopress_show_2015_player', '__return_true' );
132
			add_filter( 'protected_embeds_use_form_post', '__return_false' );
133
			remove_filter( 'the_title', 'widont' );
134
		}
135
136
		remove_filter( 'pre_kses', array( 'Filter_Embedded_HTML_Objects', 'filter' ), 11 );
137
		remove_filter( 'pre_kses', array( 'Filter_Embedded_HTML_Objects', 'maybe_create_links' ), 100 );
138
	}
139
140
	/**
141
	 * Do not add comment likes on AMP requests.
142
	 *
143
	 * @param string $content Post content.
144
	 */
145
	public static function disable_comment_likes_before_the_content( $content ) {
146
		if ( self::is_amp_request() ) {
147
			remove_filter( 'comment_text', 'comment_like_button', 12, 2 );
0 ignored issues
show
Unused Code introduced by
The call to remove_filter() has too many arguments starting with 2.

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.

In this case you can add the @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
148
		}
149
		return $content;
150
	}
151
152
	/**
153
	 * Do not display the Likes' Admin bar on AMP requests.
154
	 *
155
	 * @param bool $is_admin_bar_button_visible Should the Like button be visible in the Admin bar. Default to true.
156
	 */
157
	public static function disable_likes_admin_bar( $is_admin_bar_button_visible ) {
158
		if ( self::is_amp_request() ) {
159
			return false;
160
		}
161
		return $is_admin_bar_button_visible;
162
	}
163
164
	/**
165
	 * Add Jetpack stats pixel.
166
	 *
167
	 * @since 6.2.1
168
	 */
169
	public static function add_stats_pixel() {
170
		if ( ! has_action( 'wp_footer', 'stats_footer' ) ) {
171
			return;
172
		}
173
		stats_render_amp_footer( stats_build_view_data() );
174
	}
175
176
	/**
177
	 * Add publisher and image metadata to legacy AMP post.
178
	 *
179
	 * @since 6.2.0
180
	 *
181
	 * @param array   $metadata Metadata array.
182
	 * @param WP_Post $post     Post.
183
	 * @return array Modified metadata array.
184
	 */
185
	public static function amp_post_template_metadata( $metadata, $post ) {
186
		if ( isset( $metadata['publisher'] ) && ! isset( $metadata['publisher']['logo'] ) ) {
187
			$metadata = self::add_site_icon_to_metadata( $metadata );
188
		}
189
190
		if ( ! isset( $metadata['image'] ) && ! empty( $post ) ) {
191
			$metadata = self::add_image_to_metadata( $metadata, $post );
192
		}
193
194
		return $metadata;
195
	}
196
197
	/**
198
	 * Add blavatar to legacy AMP post metadata.
199
	 *
200
	 * @since 6.2.0
201
	 *
202
	 * @param array $metadata Metadata.
203
	 *
204
	 * @return array Metadata.
205
	 */
206
	private static function add_site_icon_to_metadata( $metadata ) {
207
		$size          = 60;
208
		$site_icon_url = class_exists( 'Automattic\\Jetpack\\Sync\\Functions' ) ? Functions::site_icon_url( $size ) : '';
209
210
		if ( function_exists( 'blavatar_domain' ) ) {
211
			$metadata['publisher']['logo'] = array(
212
				'@type'  => 'ImageObject',
213
				'url'    => blavatar_url( blavatar_domain( site_url() ), 'img', $size, self::staticize_subdomain( 'https://wordpress.com/i/favicons/apple-touch-icon-60x60.png' ) ),
214
				'width'  => $size,
215
				'height' => $size,
216
			);
217
		} elseif ( $site_icon_url ) {
218
			$metadata['publisher']['logo'] = array(
219
				'@type'  => 'ImageObject',
220
				'url'    => $site_icon_url,
221
				'width'  => $size,
222
				'height' => $size,
223
			);
224
		}
225
226
		return $metadata;
227
	}
228
229
	/**
230
	 * Add image to legacy AMP post metadata.
231
	 *
232
	 * @since 6.2.0
233
	 *
234
	 * @param array   $metadata Metadata.
235
	 * @param WP_Post $post     Post.
236
	 * @return array Metadata.
237
	 */
238
	private static function add_image_to_metadata( $metadata, $post ) {
239
		$image = Jetpack_PostImages::get_image(
240
			$post->ID,
241
			array(
242
				'fallback_to_avatars' => true,
243
				'avatar_size'         => 200,
244
				// AMP already attempts these.
245
				'from_thumbnail'      => false,
246
				'from_attachment'     => false,
247
			)
248
		);
249
250
		if ( empty( $image ) ) {
251
			return self::add_fallback_image_to_metadata( $metadata );
252
		}
253
254
		if ( ! isset( $image['src_width'] ) ) {
255
			$dimensions = self::extract_image_dimensions_from_getimagesize(
256
				array(
257
					$image['src'] => false,
258
				)
259
			);
260
261
			if ( false !== $dimensions[ $image['src'] ] ) {
262
				$image['src_width']  = $dimensions['width'];
263
				$image['src_height'] = $dimensions['height'];
264
			}
265
		}
266
267
		$metadata['image'] = array(
268
			'@type' => 'ImageObject',
269
			'url'   => $image['src'],
270
		);
271
		if ( isset( $image['src_width'] ) ) {
272
			$metadata['image']['width'] = $image['src_width'];
273
		}
274
		if ( isset( $image['src_width'] ) ) {
275
			$metadata['image']['height'] = $image['src_height'];
276
		}
277
278
		return $metadata;
279
	}
280
281
	/**
282
	 * Add fallback image to legacy AMP post metadata.
283
	 *
284
	 * @since 6.2.0
285
	 *
286
	 * @param array $metadata Metadata.
287
	 * @return array Metadata.
288
	 */
289
	private static function add_fallback_image_to_metadata( $metadata ) {
290
		/** This filter is documented in functions.opengraph.php */
291
		$default_image = apply_filters( 'jetpack_open_graph_image_default', 'https://wordpress.com/i/blank.jpg' );
292
293
		$metadata['image'] = array(
294
			'@type'  => 'ImageObject',
295
			'url'    => self::staticize_subdomain( $default_image ),
296
			'width'  => 200,
297
			'height' => 200,
298
		);
299
300
		return $metadata;
301
	}
302
303
	/**
304
	 * Return static WordPress.com domain to use to load resources from WordPress.com.
305
	 *
306
	 * @param string $domain Asset URL.
307
	 */
308
	private static function staticize_subdomain( $domain ) {
309
		// deal with WPCOM vs Jetpack.
310
		if ( function_exists( 'staticize_subdomain' ) ) {
311
			return staticize_subdomain( $domain );
312
		} else {
313
			return Assets::staticize_subdomain( $domain );
314
		}
315
	}
316
317
	/**
318
	 * Extract image dimensions via wpcom/imagesize, only on WPCOM
319
	 *
320
	 * @since 6.2.0
321
	 *
322
	 * @param array $dimensions Dimensions.
323
	 * @return array Dimensions.
324
	 */
325
	private static function extract_image_dimensions_from_getimagesize( $dimensions ) {
326
		if ( ! ( defined( 'IS_WPCOM' ) && IS_WPCOM && function_exists( 'jetpack_require_lib' ) ) ) {
327
			return $dimensions;
328
		}
329
		jetpack_require_lib( 'wpcom/imagesize' );
330
331
		foreach ( $dimensions as $url => $value ) {
332
			if ( is_array( $value ) ) {
333
				continue;
334
			}
335
			$result = wpcom_getimagesize( $url );
336
			if ( is_array( $result ) ) {
337
				$dimensions[ $url ] = array(
338
					'width'  => $result[0],
339
					'height' => $result[1],
340
				);
341
			}
342
		}
343
344
		return $dimensions;
345
	}
346
347
	/**
348
	 * Display Open Graph Meta tags in AMP views.
349
	 */
350
	public static function amp_post_jetpack_og_tags() {
351
		if ( ! ( defined( 'IS_WPCOM' ) && IS_WPCOM ) ) {
352
			Jetpack::init()->check_open_graph();
353
		}
354
355
		if ( function_exists( 'jetpack_og_tags' ) ) {
356
			jetpack_og_tags();
357
		}
358
	}
359
360
	/**
361
	 * Force Freedom mode in VideoPress.
362
	 *
363
	 * @param array $options Array of VideoPress shortcode options.
364
	 */
365
	public static function videopress_enable_freedom_mode( $options ) {
366
		if ( self::is_amp_request() ) {
367
			$options['freedom'] = true;
368
		}
369
		return $options;
370
	}
371
372
	/**
373
	 * Display custom markup for the sharing buttons when in an AMP view.
374
	 *
375
	 * @param string $markup          Content markup of the Jetpack sharing links.
376
	 * @param array  $sharing_enabled Array of Sharing Services currently enabled.
377
	 */
378
	public static function render_sharing_html( $markup, $sharing_enabled ) {
379
		global $post;
380
381
		if ( empty( $post ) ) {
382
			return '';
383
		}
384
385
		if ( ! self::is_amp_request() ) {
386
			return $markup;
387
		}
388
389
		remove_action( 'wp_footer', 'sharing_add_footer' );
390
		if ( empty( $sharing_enabled ) ) {
391
			return $markup;
392
		}
393
394
		$sharing_links = array();
395
		foreach ( $sharing_enabled['visible'] as $service ) {
396
			$sharing_link = $service->get_amp_display( $post );
397
			if ( ! empty( $sharing_link ) ) {
398
				$sharing_links[] = $sharing_link;
399
			}
400
		}
401
402
		// Replace the existing unordered list with AMP sharing buttons.
403
		$markup = preg_replace( '#<ul>(.+)</ul>#', implode( '', $sharing_links ), $markup );
404
405
		// Remove any lingering share-end list items.
406
		$markup = str_replace( '<li class="share-end"></li>', '', $markup );
407
408
		return $markup;
409
	}
410
411
	/**
412
	 * Tells Jetpack not to enqueue CSS for share buttons.
413
	 *
414
	 * @param  bool $enqueue Whether or not to enqueue.
415
	 * @return bool          Whether or not to enqueue.
416
	 */
417
	public static function amp_disable_sharedaddy_css( $enqueue ) {
418
		if ( self::is_amp_request() ) {
419
			$enqueue = false;
420
		}
421
422
		return $enqueue;
423
	}
424
425
	/**
426
	 * Enqueues the AMP specific sharing styles for the sharing icons.
427
	 */
428
	public static function amp_enqueue_sharing_css() {
429
		if ( self::is_amp_request() ) {
430
			wp_enqueue_style( 'sharedaddy-amp', plugin_dir_url( __DIR__ ) . 'modules/sharedaddy/amp-sharing.css', array( 'social-logos' ), JETPACK__VERSION );
431
		}
432
	}
433
434
	/**
435
	 * For the AMP Reader mode template, include styles that we need.
436
	 */
437
	public static function amp_reader_sharing_css() {
438
		// If sharing is not enabled, we should not proceed to render the CSS.
439
		if ( ! defined( 'JETPACK_SOCIAL_LOGOS_DIR' ) | ! defined( 'JETPACK_SOCIAL_LOGOS_URL' ) || ! defined( 'WP_SHARING_PLUGIN_DIR' ) ) {
440
			return;
441
		}
442
443
		/*
444
		 * We'll need to output the full contents of the 2 files
445
		 * in the head on AMP views. We can't rely on regular enqueues here.
446
		 * @todo As of AMP plugin v1.5, you can actually rely on regular enqueues thanks to https://github.com/ampproject/amp-wp/pull/4299. Once WPCOM upgrades AMP, then this method can be eliminated.
447
		 *
448
		 * phpcs:disable WordPress.WP.AlternativeFunctions.file_get_contents_file_get_contents
449
		 * phpcs:disable WordPress.Security.EscapeOutput.OutputNotEscaped
450
		 */
451
		$css = file_get_contents( JETPACK_SOCIAL_LOGOS_DIR . 'social-logos.css' );
452
		$css = preg_replace( '#(?<=url\(")(?=social-logos\.)#', JETPACK_SOCIAL_LOGOS_URL, $css ); // Make sure font files get their absolute paths.
453
		echo $css;
454
		echo file_get_contents( WP_SHARING_PLUGIN_DIR . 'amp-sharing.css' );
455
456
		/*
457
		 * phpcs:enable WordPress.WP.AlternativeFunctions.file_get_contents_file_get_contents
458
		 * phpcs:enable WordPress.Security.EscapeOutput.OutputNotEscaped
459
		 */
460
	}
461
462
	/**
463
	 * Ensure proper Photon image dimensions for AMP Stories.
464
	 *
465
	 * @param array $args Array of Photon Arguments.
466
	 * @param array $details {
467
	 *     Array of image details.
468
	 *
469
	 *     @type string    $tag            Image tag (Image HTML output).
470
	 *     @type string    $src            Image URL.
471
	 *     @type string    $src_orig       Original Image URL.
472
	 *     @type int|false $width          Image width.
473
	 *     @type int|false $height         Image height.
474
	 *     @type int|false $width_orig     Original image width before constrained by content_width.
475
	 *     @type int|false $height_orig    Original Image height before constrained by content_width.
476
	 *     @type string    $transform_orig Original transform before constrained by content_width.
477
	 * }
478
	 * @return array Args.
479
	 */
480
	public static function filter_photon_post_image_args_for_stories( $args, $details ) {
481
		if ( ! is_singular( 'amp_story' ) ) {
482
			return $args;
483
		}
484
485
		// Percentage-based dimensions are not allowed in AMP, so this shouldn't happen, but short-circuit just in case.
486
		if ( false !== strpos( $details['width_orig'], '%' ) || false !== strpos( $details['height_orig'], '%' ) ) {
487
			return $args;
488
		}
489
490
		$max_height = 1280; // See image size with the slug \AMP_Story_Post_Type::MAX_IMAGE_SIZE_SLUG.
491
		$transform  = $details['transform_orig'];
492
		$width      = $details['width_orig'];
493
		$height     = $details['height_orig'];
494
495
		// If height is available, constrain to $max_height.
496
		if ( false !== $height ) {
497
			if ( $height > $max_height && false !== $height ) {
498
				$width  = ( $max_height * $width ) / $height;
499
				$height = $max_height;
500
			} elseif ( $height > $max_height ) {
501
				$height = $max_height;
502
			}
503
		}
504
505
		/*
506
		 * Set a height if none is found.
507
		 * If height is set in this manner and height is available, use `fit` instead of `resize` to prevent skewing.
508
		 */
509
		if ( false === $height ) {
510
			$height = $max_height;
511
			if ( false !== $width ) {
512
				$transform = 'fit';
513
			}
514
		}
515
516
		// Build array of Photon args and expose to filter before passing to Photon URL function.
517
		$args = array();
518
519 View Code Duplication
		if ( false !== $width && false !== $height ) {
520
			$args[ $transform ] = $width . ',' . $height;
521
		} elseif ( false !== $width ) {
522
			$args['w'] = $width;
523
		} elseif ( false !== $height ) {
524
			$args['h'] = $height;
525
		}
526
527
		return $args;
528
	}
529
530
	/**
531
	 *  Adds amp-options to the list of options to sync, if AMP is available
532
	 *
533
	 * @param array $options_safelist Safelist of options to sync.
534
	 *
535
	 * @return array Updated options safelist
536
	 */
537
	public static function filter_jetpack_options_safelist( $options_safelist ) {
538
		if ( function_exists( 'is_amp_endpoint' ) ) {
539
			$options_safelist[] = 'amp-options';
540
		}
541
		return $options_safelist;
542
	}
543
}
544
545
add_action( 'init', array( 'Jetpack_AMP_Support', 'init' ), 1 );
546
547
add_action( 'admin_init', array( 'Jetpack_AMP_Support', 'admin_init' ), 1 );
548