Completed
Push — add/photon-thumbnail-disabled-... ( ef6228 )
by
unknown
07:38
created

Jetpack_Photon::strip_image_dimensions_maybe()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 17

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 3
nc 3
nop 1
dl 0
loc 17
rs 9.7
c 0
b 0
f 0
1
<?php
2
3
class Jetpack_Photon {
4
	/**
5
	 * Class variables
6
	 */
7
	// Oh look, a singleton
8
	private static $__instance = null;
9
10
	// Allowed extensions must match http://code.trac.wordpress.org/browser/photon/index.php#L31
11
	protected static $extensions = array(
12
		'gif',
13
		'jpg',
14
		'jpeg',
15
		'png'
16
	);
17
18
	// Don't access this directly. Instead, use self::image_sizes() so it's actually populated with something.
19
	protected static $image_sizes = null;
20
21
	/**
22
	 * Singleton implementation
23
	 *
24
	 * @return object
25
	 */
26
	public static function instance() {
27
		if ( ! is_a( self::$__instance, 'Jetpack_Photon' ) ) {
28
			self::$__instance = new Jetpack_Photon;
29
			self::$__instance->setup();
30
		}
31
32
		return self::$__instance;
33
	}
34
35
	/**
36
	 * Silence is golden.
37
	 */
38
	private function __construct() {}
39
40
	/**
41
	 * Register actions and filters, but only if basic Photon functions are available.
42
	 * The basic functions are found in ./functions.photon.php.
43
	 *
44
	 * @uses add_action, add_filter
45
	 * @return null
46
	 */
47
	private function setup() {
48
		if ( ! function_exists( 'jetpack_photon_url' ) ) {
49
			return;
50
		}
51
52
		// Images in post content and galleries
53
		add_filter( 'the_content', array( __CLASS__, 'filter_the_content' ), 999999 );
54
		add_filter( 'get_post_galleries', array( __CLASS__, 'filter_the_galleries' ), 999999 );
55
		add_filter( 'widget_media_image_instance', array( __CLASS__, 'filter_the_image_widget' ), 999999 );
56
57
		// Core image retrieval
58
		add_filter( 'image_downsize', array( $this, 'filter_image_downsize' ), 10, 3 );
59
		add_filter( 'rest_request_before_callbacks', array( $this, 'should_rest_photon_image_downsize' ), 10, 3 );
60
		add_filter( 'rest_request_after_callbacks', array( $this, 'cleanup_rest_photon_image_downsize' ) );
61
62
		// Responsive image srcset substitution
63
		add_filter( 'wp_calculate_image_srcset', array( $this, 'filter_srcset_array' ), 10, 5 );
64
		add_filter( 'wp_calculate_image_sizes', array( $this, 'filter_sizes' ), 1, 2 ); // Early so themes can still easily filter.
65
66
		// Helpers for maniuplated images
67
		add_action( 'wp_enqueue_scripts', array( $this, 'action_wp_enqueue_scripts' ), 9 );
68
69
		/**
70
		 * Allow Photon to disable uploaded images resizing and use its own resize capabilities instead.
71
		 *
72
		 * @module photon
73
		 *
74
		 * @since 7.1.0
75
		 *
76
		 * @param bool false Should Photon enable noresize mode. Default to false.
77
		 */
78
		if ( apply_filters( 'jetpack_photon_noresize_mode', false ) ) {
79
			$this->enable_noresize_mode();
80
		}
81
	}
82
83
	/**
84
	 * Enables the noresize mode for Photon, allowing to avoid intermediate size files generation.
85
	 */
86
	private function enable_noresize_mode() {
87
		// The main objective of noresize mode is to disable additional resized image versions creation.
88
		// This filter handles removal of additional sizes.
89
		add_filter( 'intermediate_image_sizes_advanced', 'wpcom_intermediate_sizes' );
90
91
		// This allows to assign the Photon domain to images that normally use the home URL as base.
92
		add_filter( 'jetpack_photon_domain', array( __CLASS__, 'filter_photon_norezise_mode_domain' ), 10, 2 );
93
94
		add_filter( 'the_content', array( __CLASS__, 'filter_content_add' ), 0 );
95
96
		// Jetpack hooks in at six nines (999999) so this filter does at seven.
97
		add_filter( 'the_content', array( __CLASS__, 'filter_content_remove' ), 9999999 );
98
99
		// Regular Photon operation mode filter doesn't run when is_admin(), so we need an additional filter.
100
		// This is temporary until Jetpack allows more easily running these filters for is_admin().
101
		if ( is_admin() ) {
102
			add_filter( 'image_downsize', array( $this, 'filter_image_downsize' ), 5, 3 );
103
			add_filter( 'jetpack_photon_admin_allow_image_downsize', array( __CLASS__, 'filter_photon_noresize_allow_downsize' ), 10, 2 );
104
		}
105
	}
106
107
	/**
108
	 * This is our catch-all to strip dimensions from intermediate images in content.
109
	 * Since this primarily only impacts post_content we do a little dance to add the filter early
110
	 * to `the_content` and then remove it later on in the same hook.
111
	 *
112
	 * @param String $content the post content.
113
	 * @return String the post content unchanged.
114
	 */
115
	public static function filter_content_add( $content ) {
116
		add_filter( 'jetpack_photon_pre_image_url', array( __CLASS__, 'strip_image_dimensions_maybe' ) );
117
		return $content;
118
	}
119
120
	/**
121
	 * Removing the content filter that was set previously.
122
	 *
123
	 * @param String $content the post content.
124
	 * @return String the post content unchanged.
125
	 */
126
	public static function filter_content_remove( $content ) {
127
		remove_filter( 'jetpack_photon_pre_image_url', array( __CLASS__, 'strip_image_dimensions_maybe' ) );
128
		return $content;
129
	}
130
131
	/**
132
	 * Short circuits the Photon filter to enable Photon processing for any URL.
133
	 *
134
	 * @param String $photon_url a proposed Photon URL for the media file.
135
	 * @param String $image_url the original media URL.
136
	 * @return String an URL to be used for the media file.
137
	 */
138
	public static function filter_photon_norezise_mode_domain( $photon_url, $image_url ) {
139
		return $photon_url;
140
	}
141
142
	/**
143
	 * Allows any image that gets passed to Photon to be resized via Photon.
144
	 *
145
	 * @param Boolean $allow whether to allow the image to get resized with Photon.
146
	 * @param Array   $params an array containing image data, attachment ID and size variant.
147
	 * @return Boolean
148
	 */
149
	public static function filter_photon_noresize_allow_downsize( $allow, $params ) {
150
		return true;
151
	}
152
153
	/**
154
	 ** IN-CONTENT IMAGE MANIPULATION FUNCTIONS
155
	 **/
156
157
	/**
158
	 * Match all images and any relevant <a> tags in a block of HTML.
159
	 *
160
	 * @param string $content Some HTML.
161
	 * @return array An array of $images matches, where $images[0] is
162
	 *         an array of full matches, and the link_url, img_tag,
163
	 *         and img_url keys are arrays of those matches.
164
	 */
165
	public static function parse_images_from_html( $content ) {
166
		$images = array();
167
168
		if ( preg_match_all( '#(?:<a[^>]+?href=["|\'](?P<link_url>[^\s]+?)["|\'][^>]*?>\s*)?(?P<img_tag><img[^>]*?\s+?src=["|\'](?P<img_url>[^\s]+?)["|\'].*?>){1}(?:\s*</a>)?#is', $content, $images ) ) {
169
			foreach ( $images as $key => $unused ) {
170
				// Simplify the output as much as possible, mostly for confirming test results.
171
				if ( is_numeric( $key ) && $key > 0 )
172
					unset( $images[$key] );
173
			}
174
175
			return $images;
176
		}
177
178
		return array();
179
	}
180
181
	/**
182
	 * Try to determine height and width from strings WP appends to resized image filenames.
183
	 *
184
	 * @param string $src The image URL.
185
	 * @return array An array consisting of width and height.
186
	 */
187
	public static function parse_dimensions_from_filename( $src ) {
188
		$width_height_string = array();
189
190
		if ( preg_match( '#-(\d+)x(\d+)\.(?:' . implode('|', self::$extensions ) . '){1}$#i', $src, $width_height_string ) ) {
191
			$width = (int) $width_height_string[1];
192
			$height = (int) $width_height_string[2];
193
194
			if ( $width && $height )
195
				return array( $width, $height );
196
		}
197
198
		return array( false, false );
199
	}
200
201
	/**
202
	 * Identify images in post content, and if images are local (uploaded to the current site), pass through Photon.
203
	 *
204
	 * @param string $content
205
	 * @uses self::validate_image_url, apply_filters, jetpack_photon_url, esc_url
206
	 * @filter the_content
207
	 * @return string
208
	 */
209
	public static function filter_the_content( $content ) {
210
		$images = Jetpack_Photon::parse_images_from_html( $content );
211
212
		if ( ! empty( $images ) ) {
213
			$content_width = Jetpack::get_content_width();
214
215
			$image_sizes = self::image_sizes();
216
			$upload_dir = wp_get_upload_dir();
217
218
			foreach ( $images[0] as $index => $tag ) {
219
				// Default to resize, though fit may be used in certain cases where a dimension cannot be ascertained
220
				$transform = 'resize';
221
222
				// Start with a clean attachment ID each time
223
				$attachment_id = false;
224
225
				// Flag if we need to munge a fullsize URL
226
				$fullsize_url = false;
227
228
				// Identify image source
229
				$src = $src_orig = $images['img_url'][ $index ];
230
231
				/**
232
				 * Allow specific images to be skipped by Photon.
233
				 *
234
				 * @module photon
235
				 *
236
				 * @since 2.0.3
237
				 *
238
				 * @param bool false Should Photon ignore this image. Default to false.
239
				 * @param string $src Image URL.
240
				 * @param string $tag Image Tag (Image HTML output).
241
				 */
242
				if ( apply_filters( 'jetpack_photon_skip_image', false, $src, $tag ) )
243
					continue;
244
245
				// Support Automattic's Lazy Load plugin
246
				// Can't modify $tag yet as we need unadulterated version later
247
				if ( preg_match( '#data-lazy-src=["|\'](.+?)["|\']#i', $images['img_tag'][ $index ], $lazy_load_src ) ) {
248
					$placeholder_src = $placeholder_src_orig = $src;
249
					$src = $src_orig = $lazy_load_src[1];
250
				} elseif ( preg_match( '#data-lazy-original=["|\'](.+?)["|\']#i', $images['img_tag'][ $index ], $lazy_load_src ) ) {
251
					$placeholder_src = $placeholder_src_orig = $src;
252
					$src = $src_orig = $lazy_load_src[1];
253
				}
254
255
				// Check if image URL should be used with Photon
256
				if ( self::validate_image_url( $src ) ) {
257
					// Find the width and height attributes
258
					$width = $height = false;
259
260
					// First, check the image tag
261
					if ( preg_match( '#width=["|\']?([\d%]+)["|\']?#i', $images['img_tag'][ $index ], $width_string ) )
262
						$width = $width_string[1];
263
264
					if ( preg_match( '#height=["|\']?([\d%]+)["|\']?#i', $images['img_tag'][ $index ], $height_string ) )
265
						$height = $height_string[1];
266
267
					// Can't pass both a relative width and height, so unset the height in favor of not breaking the horizontal layout.
268
					if ( false !== strpos( $width, '%' ) && false !== strpos( $height, '%' ) )
269
						$width = $height = false;
270
271
					// Detect WP registered image size from HTML class
272
					if ( preg_match( '#class=["|\']?[^"\']*size-([^"\'\s]+)[^"\']*["|\']?#i', $images['img_tag'][ $index ], $size ) ) {
273
						$size = array_pop( $size );
274
275
						if ( false === $width && false === $height && 'full' != $size && array_key_exists( $size, $image_sizes ) ) {
276
							$width = (int) $image_sizes[ $size ]['width'];
277
							$height = (int) $image_sizes[ $size ]['height'];
278
							$transform = $image_sizes[ $size ]['crop'] ? 'resize' : 'fit';
279
						}
280
					} else {
281
						unset( $size );
282
					}
283
284
					// WP Attachment ID, if uploaded to this site
285
					if (
286
						preg_match( '#class=["|\']?[^"\']*wp-image-([\d]+)[^"\']*["|\']?#i', $images['img_tag'][ $index ], $attachment_id ) &&
287
						0 === strpos( $src, $upload_dir['baseurl'] ) &&
288
						/**
289
						 * Filter whether an image using an attachment ID in its class has to be uploaded to the local site to go through Photon.
290
						 *
291
						 * @module photon
292
						 *
293
						 * @since 2.0.3
294
						 *
295
						 * @param bool false Was the image uploaded to the local site. Default to false.
296
						 * @param array $args {
297
						 * 	 Array of image details.
298
						 *
299
						 * 	 @type $src Image URL.
300
						 * 	 @type tag Image tag (Image HTML output).
301
						 * 	 @type $images Array of information about the image.
302
						 * 	 @type $index Image index.
303
						 * }
304
						 */
305
						apply_filters( 'jetpack_photon_image_is_local', false, compact( 'src', 'tag', 'images', 'index' ) )
306
					) {
307
						$attachment_id = intval( array_pop( $attachment_id ) );
308
309
						if ( $attachment_id ) {
310
							$attachment = get_post( $attachment_id );
311
312
							// Basic check on returned post object
313
							if ( is_object( $attachment ) && ! is_wp_error( $attachment ) && 'attachment' == $attachment->post_type ) {
314
								$src_per_wp = wp_get_attachment_image_src( $attachment_id, isset( $size ) ? $size : 'full' );
315
316
								if ( self::validate_image_url( $src_per_wp[0] ) ) {
317
									$src = $src_per_wp[0];
318
									$fullsize_url = true;
319
320
									// Prevent image distortion if a detected dimension exceeds the image's natural dimensions
321
									if ( ( false !== $width && $width > $src_per_wp[1] ) || ( false !== $height && $height > $src_per_wp[2] ) ) {
322
										$width = false === $width ? false : min( $width, $src_per_wp[1] );
323
										$height = false === $height ? false : min( $height, $src_per_wp[2] );
324
									}
325
326
									// If no width and height are found, max out at source image's natural dimensions
327
									// Otherwise, respect registered image sizes' cropping setting
328
									if ( false === $width && false === $height ) {
329
										$width = $src_per_wp[1];
330
										$height = $src_per_wp[2];
331
										$transform = 'fit';
332
									} elseif ( isset( $size ) && array_key_exists( $size, $image_sizes ) && isset( $image_sizes[ $size ]['crop'] ) ) {
333
										$transform = (bool) $image_sizes[ $size ]['crop'] ? 'resize' : 'fit';
334
									}
335
								}
336
							} else {
337
								unset( $attachment_id );
338
								unset( $attachment );
339
							}
340
						}
341
					}
342
343
					// If image tag lacks width and height arguments, try to determine from strings WP appends to resized image filenames.
344
					if ( false === $width && false === $height ) {
345
						list( $width, $height ) = Jetpack_Photon::parse_dimensions_from_filename( $src );
346
					}
347
348
					// If width is available, constrain to $content_width
349
					if ( false !== $width && false === strpos( $width, '%' ) && is_numeric( $content_width ) ) {
350
						if ( $width > $content_width && false !== $height && false === strpos( $height, '%' ) ) {
351
							$height = round( ( $content_width * $height ) / $width );
352
							$width = $content_width;
353
						} elseif ( $width > $content_width ) {
354
							$width = $content_width;
355
						}
356
					}
357
358
					// Set a width if none is found and $content_width is available
359
					// If width is set in this manner and height is available, use `fit` instead of `resize` to prevent skewing
360
					if ( false === $width && is_numeric( $content_width ) ) {
361
						$width = (int) $content_width;
362
363
						if ( false !== $height )
364
							$transform = 'fit';
365
					}
366
367
					// Detect if image source is for a custom-cropped thumbnail and prevent further URL manipulation.
368
					if ( ! $fullsize_url && preg_match_all( '#-e[a-z0-9]+(-\d+x\d+)?\.(' . implode('|', self::$extensions ) . '){1}$#i', basename( $src ), $filename ) )
369
						$fullsize_url = true;
370
371
					// Build URL, first maybe removing WP's resized string so we pass the original image to Photon
372
					if ( ! $fullsize_url ) {
373
						$src = self::strip_image_dimensions_maybe( $src );
374
					}
375
376
					// Build array of Photon args and expose to filter before passing to Photon URL function
377
					$args = array();
378
379
					if ( false !== $width && false !== $height && false === strpos( $width, '%' ) && false === strpos( $height, '%' ) )
380
						$args[ $transform ] = $width . ',' . $height;
381
					elseif ( false !== $width )
382
						$args['w'] = $width;
383
					elseif ( false !== $height )
384
						$args['h'] = $height;
385
386
					/**
387
					 * Filter the array of Photon arguments added to an image when it goes through Photon.
388
					 * By default, only includes width and height values.
389
					 * @see https://developer.wordpress.com/docs/photon/api/
390
					 *
391
					 * @module photon
392
					 *
393
					 * @since 2.0.0
394
					 *
395
					 * @param array $args Array of Photon Arguments.
396
					 * @param array $args {
397
					 * 	 Array of image details.
398
					 *
399
					 * 	 @type $tag Image tag (Image HTML output).
400
					 * 	 @type $src Image URL.
401
					 * 	 @type $src_orig Original Image URL.
402
					 * 	 @type $width Image width.
403
					 * 	 @type $height Image height.
404
					 * }
405
					 */
406
					$args = apply_filters( 'jetpack_photon_post_image_args', $args, compact( 'tag', 'src', 'src_orig', 'width', 'height' ) );
407
408
					$photon_url = jetpack_photon_url( $src, $args );
409
410
					// Modify image tag if Photon function provides a URL
411
					// Ensure changes are only applied to the current image by copying and modifying the matched tag, then replacing the entire tag with our modified version.
412
					if ( $src != $photon_url ) {
413
						$new_tag = $tag;
414
415
						// If present, replace the link href with a Photoned URL for the full-size image.
416
						if ( ! empty( $images['link_url'][ $index ] ) && self::validate_image_url( $images['link_url'][ $index ] ) )
417
							$new_tag = preg_replace( '#(href=["|\'])' . $images['link_url'][ $index ] . '(["|\'])#i', '\1' . jetpack_photon_url( $images['link_url'][ $index ] ) . '\2', $new_tag, 1 );
418
419
						// Supplant the original source value with our Photon URL
420
						$photon_url = esc_url( $photon_url );
421
						$new_tag = str_replace( $src_orig, $photon_url, $new_tag );
422
423
						// If Lazy Load is in use, pass placeholder image through Photon
424
						if ( isset( $placeholder_src ) && self::validate_image_url( $placeholder_src ) ) {
425
							$placeholder_src = jetpack_photon_url( $placeholder_src );
426
427
							if ( $placeholder_src != $placeholder_src_orig )
428
								$new_tag = str_replace( $placeholder_src_orig, esc_url( $placeholder_src ), $new_tag );
0 ignored issues
show
Bug introduced by
The variable $placeholder_src_orig does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
429
430
							unset( $placeholder_src );
431
						}
432
433
						// If we are not transforming the image with resize, fit, or letterbox (lb), then we should remove
434
						// the width and height arguments from the image to prevent distortion. Even if $args['w'] and $args['h']
435
						// are present, Photon does not crop to those dimensions. Instead, it appears to favor height.
436
						//
437
						// If we are transforming the image via one of those methods, let's update the width and height attributes.
438
						if ( empty( $args['resize'] ) && empty( $args['fit'] ) && empty( $args['lb'] ) ) {
439
							$new_tag = preg_replace( '#(?<=\s)(width|height)=["|\']?[\d%]+["|\']?\s?#i', '', $new_tag );
440
						} else {
441
							$resize_args = isset( $args['resize'] ) ? $args['resize'] : false;
442 View Code Duplication
							if ( false == $resize_args ) {
443
								$resize_args = ( ! $resize_args && isset( $args['fit'] ) )
444
									? $args['fit']
445
									: false;
446
							}
447 View Code Duplication
							if ( false == $resize_args ) {
448
								$resize_args = ( ! $resize_args && isset( $args['lb'] ) )
449
									? $args['lb']
450
									: false;
451
							}
452
453
							$resize_args = array_map( 'trim', explode( ',', $resize_args ) );
454
455
							// (?<=\s)         - Ensure width or height attribute is preceded by a space
456
							// (width=["|\']?) - Matches, and captures, width=, width=", or width='
457
							// [\d%]+          - Matches 1 or more digits
458
							// (["|\']?)       - Matches, and captures, ", ', or empty string
459
							// \s              - Ensures there's a space after the attribute
460
							$new_tag = preg_replace( '#(?<=\s)(width=["|\']?)[\d%]+(["|\']?)\s?#i', sprintf( '${1}%d${2} ', $resize_args[0] ), $new_tag );
461
							$new_tag = preg_replace( '#(?<=\s)(height=["|\']?)[\d%]+(["|\']?)\s?#i', sprintf( '${1}%d${2} ', $resize_args[1] ), $new_tag );
462
						}
463
464
						// Tag an image for dimension checking
465
						$new_tag = preg_replace( '#(\s?/)?>(\s*</a>)?$#i', ' data-recalc-dims="1"\1>\2', $new_tag );
466
467
						// Replace original tag with modified version
468
						$content = str_replace( $tag, $new_tag, $content );
469
					}
470
				} elseif ( preg_match( '#^http(s)?://i[\d]{1}.wp.com#', $src ) && ! empty( $images['link_url'][ $index ] ) && self::validate_image_url( $images['link_url'][ $index ] ) ) {
471
					$new_tag = preg_replace( '#(href=["|\'])' . $images['link_url'][ $index ] . '(["|\'])#i', '\1' . jetpack_photon_url( $images['link_url'][ $index ] ) . '\2', $tag, 1 );
472
473
					$content = str_replace( $tag, $new_tag, $content );
474
				}
475
			}
476
		}
477
478
		return $content;
479
	}
480
481
	public static function filter_the_galleries( $galleries ) {
482
		if ( empty( $galleries ) || ! is_array( $galleries ) ) {
483
			return $galleries;
484
		}
485
486
		// Pass by reference, so we can modify them in place.
487
		foreach ( $galleries as &$this_gallery ) {
488
			if ( is_string( $this_gallery ) ) {
489
				$this_gallery = self::filter_the_content( $this_gallery );
490
		// LEAVING COMMENTED OUT as for the moment it doesn't seem
491
		// necessary and I'm not sure how it would propagate through.
492
		//	} elseif ( is_array( $this_gallery )
493
		//	           && ! empty( $this_gallery['src'] )
494
		//	           && ! empty( $this_gallery['type'] )
495
		//	           && in_array( $this_gallery['type'], array( 'rectangle', 'square', 'circle' ) ) ) {
496
		//		$this_gallery['src'] = array_map( 'jetpack_photon_url', $this_gallery['src'] );
497
			}
498
		}
499
		unset( $this_gallery ); // break the reference.
500
501
		return $galleries;
502
	}
503
504
505
	/**
506
	 * Runs the image widget through photon.
507
	 *
508
	 * @param array $instance Image widget instance data.
509
	 * @return array
510
	 */
511
	public static function filter_the_image_widget( $instance ) {
512
		if ( Jetpack::is_module_active( 'photon' ) && ! $instance['attachment_id'] && $instance['url'] ) {
513
			jetpack_photon_url( $instance['url'], array(
514
				'w' => $instance['width'],
515
				'h' => $instance['height'],
516
			) );
517
		}
518
519
		return $instance;
520
	}
521
522
	/**
523
	 ** CORE IMAGE RETRIEVAL
524
	 **/
525
526
	/**
527
	 * Filter post thumbnail image retrieval, passing images through Photon
528
	 *
529
	 * @param string|bool $image
530
	 * @param int $attachment_id
531
	 * @param string|array $size
532
	 * @uses is_admin, apply_filters, wp_get_attachment_url, self::validate_image_url, this::image_sizes, jetpack_photon_url
533
	 * @filter image_downsize
534
	 * @return string|bool
535
	 */
536
	public function filter_image_downsize( $image, $attachment_id, $size ) {
537
		// Don't foul up the admin side of things, unless a plugin wants to.
538
		if ( is_admin() &&
539
			/**
540
			 * Provide plugins a way of running Photon for images in the WordPress Dashboard (wp-admin).
541
			 *
542
			 * Note: enabling this will result in Photon URLs added to your post content, which could make migrations across domains (and off Photon) a bit more challenging.
543
			 *
544
			 * @module photon
545
			 *
546
			 * @since 4.8.0
547
			 *
548
			 * @param bool false Stop Photon from being run on the Dashboard. Default to false.
549
			 * @param array $args {
550
			 * 	 Array of image details.
551
			 *
552
			 * 	 @type $image Image URL.
553
			 * 	 @type $attachment_id Attachment ID of the image.
554
			 * 	 @type $size Image size. Can be a string (name of the image size, e.g. full) or an array of width and height.
555
			 * }
556
			 */
557
			false === apply_filters( 'jetpack_photon_admin_allow_image_downsize', false, compact( 'image', 'attachment_id', 'size' ) )
558
		) {
559
			return $image;
560
		}
561
562
		/**
563
		 * Provide plugins a way of preventing Photon from being applied to images retrieved from WordPress Core.
564
		 *
565
		 * @module photon
566
		 *
567
		 * @since 2.0.0
568
		 *
569
		 * @param bool false Stop Photon from being applied to the image. Default to false.
570
		 * @param array $args {
571
		 * 	 Array of image details.
572
		 *
573
		 * 	 @type $image Image URL.
574
		 * 	 @type $attachment_id Attachment ID of the image.
575
		 * 	 @type $size Image size. Can be a string (name of the image size, e.g. full) or an array of width and height.
576
		 * }
577
		 */
578
		if ( apply_filters( 'jetpack_photon_override_image_downsize', false, compact( 'image', 'attachment_id', 'size' ) ) ) {
579
			return $image;
580
		}
581
582
		// Get the image URL and proceed with Photon-ification if successful
583
		$image_url = wp_get_attachment_url( $attachment_id );
584
585
		// Set this to true later when we know we have size meta.
586
		$has_size_meta = false;
587
588
		if ( $image_url ) {
589
			// Check if image URL should be used with Photon
590
			if ( ! self::validate_image_url( $image_url ) ) {
591
				return $image;
592
			}
593
594
			$intermediate = true; // For the fourth array item returned by the image_downsize filter.
595
596
			// If an image is requested with a size known to WordPress, use that size's settings with Photon.
597
			// WP states that `add_image_size()` should use a string for the name, but doesn't enforce that.
598
			// Due to differences in how Core and Photon check for the registered image size, we check both types.
599
			if ( ( is_string( $size ) || is_int( $size ) ) && array_key_exists( $size, self::image_sizes() ) ) {
600
				$image_args = self::image_sizes();
601
				$image_args = $image_args[ $size ];
602
603
				$photon_args = array();
604
605
				$image_meta = image_get_intermediate_size( $attachment_id, $size );
606
607
				// 'full' is a special case: We need consistent data regardless of the requested size.
608
				if ( 'full' == $size ) {
609
					$image_meta = wp_get_attachment_metadata( $attachment_id );
610
					$intermediate = false;
611
				} elseif ( ! $image_meta ) {
612
					// If we still don't have any image meta at this point, it's probably from a custom thumbnail size
613
					// for an image that was uploaded before the custom image was added to the theme.  Try to determine the size manually.
614
					$image_meta = wp_get_attachment_metadata( $attachment_id );
615
616
					if ( isset( $image_meta['width'], $image_meta['height'] ) ) {
617
						$image_resized = image_resize_dimensions( $image_meta['width'], $image_meta['height'], $image_args['width'], $image_args['height'], $image_args['crop'] );
618
						if ( $image_resized ) { // This could be false when the requested image size is larger than the full-size image.
619
							$image_meta['width'] = $image_resized[6];
620
							$image_meta['height'] = $image_resized[7];
621
						}
622
					}
623
				}
624
625
				if ( isset( $image_meta['width'], $image_meta['height'] ) ) {
626
					$image_args['width']  = $image_meta['width'];
627
					$image_args['height'] = $image_meta['height'];
628
629
					list( $image_args['width'], $image_args['height'] ) = image_constrain_size_for_editor( $image_args['width'], $image_args['height'], $size, 'display' );
630
					$has_size_meta = true;
631
				}
632
633
				// Expose determined arguments to a filter before passing to Photon
634
				$transform = $image_args['crop'] ? 'resize' : 'fit';
635
636
				// Check specified image dimensions and account for possible zero values; photon fails to resize if a dimension is zero.
637
				if ( 0 == $image_args['width'] || 0 == $image_args['height'] ) {
638
					if ( 0 == $image_args['width'] && 0 < $image_args['height'] ) {
639
						$photon_args['h'] = $image_args['height'];
640
					} elseif ( 0 == $image_args['height'] && 0 < $image_args['width'] ) {
641
						$photon_args['w'] = $image_args['width'];
642
					}
643
				} else {
644
					if ( ( 'resize' === $transform ) && $image_meta = wp_get_attachment_metadata( $attachment_id ) ) {
645
						if ( isset( $image_meta['width'], $image_meta['height'] ) ) {
646
							// Lets make sure that we don't upscale images since wp never upscales them as well
647
							$smaller_width  = ( ( $image_meta['width']  < $image_args['width']  ) ? $image_meta['width']  : $image_args['width']  );
648
							$smaller_height = ( ( $image_meta['height'] < $image_args['height'] ) ? $image_meta['height'] : $image_args['height'] );
649
650
							$photon_args[ $transform ] = $smaller_width . ',' . $smaller_height;
651
						}
652
					} else {
653
						$photon_args[ $transform ] = $image_args['width'] . ',' . $image_args['height'];
654
					}
655
656
				}
657
658
659
				/**
660
				 * Filter the Photon Arguments added to an image when going through Photon, when that image size is a string.
661
				 * Image size will be a string (e.g. "full", "medium") when it is known to WordPress.
662
				 *
663
				 * @module photon
664
				 *
665
				 * @since 2.0.0
666
				 *
667
				 * @param array $photon_args Array of Photon arguments.
668
				 * @param array $args {
669
				 * 	 Array of image details.
670
				 *
671
				 * 	 @type $image_args Array of Image arguments (width, height, crop).
672
				 * 	 @type $image_url Image URL.
673
				 * 	 @type $attachment_id Attachment ID of the image.
674
				 * 	 @type $size Image size. Can be a string (name of the image size, e.g. full) or an integer.
675
				 * 	 @type $transform Value can be resize or fit.
676
				 *                    @see https://developer.wordpress.com/docs/photon/api
677
				 * }
678
				 */
679
				$photon_args = apply_filters( 'jetpack_photon_image_downsize_string', $photon_args, compact( 'image_args', 'image_url', 'attachment_id', 'size', 'transform' ) );
680
681
				// Generate Photon URL
682
				$image = array(
683
					jetpack_photon_url( $image_url, $photon_args ),
684
					$has_size_meta ? $image_args['width'] : false,
685
					$has_size_meta ? $image_args['height'] : false,
686
					$intermediate
687
				);
688
			} elseif ( is_array( $size ) ) {
689
				// Pull width and height values from the provided array, if possible
690
				$width = isset( $size[0] ) ? (int) $size[0] : false;
691
				$height = isset( $size[1] ) ? (int) $size[1] : false;
692
693
				// Don't bother if necessary parameters aren't passed.
694
				if ( ! $width || ! $height ) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $width of type integer|false is loosely compared to false; this is ambiguous if the integer can be zero. You might want to explicitly use === null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For integer values, zero is a special case, in particular the following results might be unexpected:

0   == false // true
0   == null  // true
123 == false // false
123 == null  // false

// It is often better to use strict comparison
0 === false // false
0 === null  // false
Loading history...
Bug Best Practice introduced by
The expression $height of type integer|false is loosely compared to false; this is ambiguous if the integer can be zero. You might want to explicitly use === null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For integer values, zero is a special case, in particular the following results might be unexpected:

0   == false // true
0   == null  // true
123 == false // false
123 == null  // false

// It is often better to use strict comparison
0 === false // false
0 === null  // false
Loading history...
695
					return $image;
696
				}
697
698
				$image_meta = wp_get_attachment_metadata( $attachment_id );
699
				if ( isset( $image_meta['width'], $image_meta['height'] ) ) {
700
					$image_resized = image_resize_dimensions( $image_meta['width'], $image_meta['height'], $width, $height );
701
702
					if ( $image_resized ) { // This could be false when the requested image size is larger than the full-size image.
703
						$width = $image_resized[6];
704
						$height = $image_resized[7];
705
					} else {
706
						$width = $image_meta['width'];
707
						$height = $image_meta['height'];
708
					}
709
710
					$has_size_meta = true;
711
				}
712
713
				list( $width, $height ) = image_constrain_size_for_editor( $width, $height, $size );
714
715
				// Expose arguments to a filter before passing to Photon
716
				$photon_args = array(
717
					'fit' => $width . ',' . $height
718
				);
719
720
				/**
721
				 * Filter the Photon Arguments added to an image when going through Photon,
722
				 * when the image size is an array of height and width values.
723
				 *
724
				 * @module photon
725
				 *
726
				 * @since 2.0.0
727
				 *
728
				 * @param array $photon_args Array of Photon arguments.
729
				 * @param array $args {
730
				 * 	 Array of image details.
731
				 *
732
				 * 	 @type $width Image width.
733
				 * 	 @type height Image height.
734
				 * 	 @type $image_url Image URL.
735
				 * 	 @type $attachment_id Attachment ID of the image.
736
				 * }
737
				 */
738
				$photon_args = apply_filters( 'jetpack_photon_image_downsize_array', $photon_args, compact( 'width', 'height', 'image_url', 'attachment_id' ) );
739
740
				// Generate Photon URL
741
				$image = array(
742
					jetpack_photon_url( $image_url, $photon_args ),
743
					$has_size_meta ? $width : false,
744
					$has_size_meta ? $height : false,
745
					$intermediate
746
				);
747
			}
748
		}
749
750
		return $image;
751
	}
752
753
	/**
754
	 * Filters an array of image `srcset` values, replacing each URL with its Photon equivalent.
755
	 *
756
	 * @since 3.8.0
757
	 * @since 4.0.4 Added automatically additional sizes beyond declared image sizes.
758
	 * @param array $sources An array of image urls and widths.
759
	 * @uses self::validate_image_url, jetpack_photon_url, Jetpack_Photon::parse_from_filename
760
	 * @uses Jetpack_Photon::strip_image_dimensions_maybe, Jetpack::get_content_width
761
	 * @return array An array of Photon image urls and widths.
762
	 */
763
	public function filter_srcset_array( $sources = array(), $size_array = array(), $image_src = array(), $image_meta = array(), $attachment_id = 0 ) {
764
		if ( ! is_array( $sources ) ) {
765
			return $sources;
766
		}
767
		$upload_dir = wp_get_upload_dir();
768
769
		foreach ( $sources as $i => $source ) {
770
			if ( ! self::validate_image_url( $source['url'] ) ) {
771
				continue;
772
			}
773
774
			/** This filter is already documented in class.photon.php */
775
			if ( apply_filters( 'jetpack_photon_skip_image', false, $source['url'], $source ) ) {
776
				continue;
777
			}
778
779
			$url = $source['url'];
780
			list( $width, $height ) = Jetpack_Photon::parse_dimensions_from_filename( $url );
781
782
			// It's quicker to get the full size with the data we have already, if available
783
			if ( ! empty( $attachment_id ) ) {
784
				$url = wp_get_attachment_url( $attachment_id );
785
			} else {
786
				$url = Jetpack_Photon::strip_image_dimensions_maybe( $url );
787
			}
788
789
			$args = array();
790
			if ( 'w' === $source['descriptor'] ) {
791
				if ( $height && ( $source['value'] == $width ) ) {
792
					$args['resize'] = $width . ',' . $height;
793
				} else {
794
					$args['w'] = $source['value'];
795
				}
796
797
			}
798
799
			$sources[ $i ]['url'] = jetpack_photon_url( $url, $args );
800
		}
801
802
		/**
803
		 * At this point, $sources is the original srcset with Photonized URLs.
804
		 * Now, we're going to construct additional sizes based on multiples of the content_width.
805
		 * This will reduce the gap between the largest defined size and the original image.
806
		 */
807
808
		/**
809
		 * Filter the multiplier Photon uses to create new srcset items.
810
		 * Return false to short-circuit and bypass auto-generation.
811
		 *
812
		 * @module photon
813
		 *
814
		 * @since 4.0.4
815
		 *
816
		 * @param array|bool $multipliers Array of multipliers to use or false to bypass.
817
		 */
818
		$multipliers = apply_filters( 'jetpack_photon_srcset_multipliers', array( 2, 3 ) );
819
		$url         = trailingslashit( $upload_dir['baseurl'] ) . $image_meta['file'];
820
821
		if (
822
			/** Short-circuit via jetpack_photon_srcset_multipliers filter. */
823
			is_array( $multipliers )
824
			/** This filter is already documented in class.photon.php */
825
			&& ! apply_filters( 'jetpack_photon_skip_image', false, $url, null )
826
			/** Verify basic meta is intact. */
827
			&& isset( $image_meta['width'] ) && isset( $image_meta['height'] ) && isset( $image_meta['file'] )
828
			/** Verify we have the requested width/height. */
829
			&& isset( $size_array[0] ) && isset( $size_array[1] )
830
			) {
831
832
			$fullwidth  = $image_meta['width'];
833
			$fullheight = $image_meta['height'];
834
			$reqwidth   = $size_array[0];
835
			$reqheight  = $size_array[1];
836
837
			$constrained_size = wp_constrain_dimensions( $fullwidth, $fullheight, $reqwidth );
838
			$expected_size = array( $reqwidth, $reqheight );
839
840
			if ( abs( $constrained_size[0] - $expected_size[0] ) <= 1 && abs( $constrained_size[1] - $expected_size[1] ) <= 1 ) {
841
				$crop = 'soft';
842
				$base = Jetpack::get_content_width() ? Jetpack::get_content_width() : 1000; // Provide a default width if none set by the theme.
843
			} else {
844
				$crop = 'hard';
845
				$base = $reqwidth;
846
			}
847
848
849
			$currentwidths = array_keys( $sources );
850
			$newsources = null;
851
852
			foreach ( $multipliers as $multiplier ) {
853
854
				$newwidth = $base * $multiplier;
855
				foreach ( $currentwidths as $currentwidth ){
856
					// If a new width would be within 100 pixes of an existing one or larger than the full size image, skip.
857
					if ( abs( $currentwidth - $newwidth ) < 50 || ( $newwidth > $fullwidth ) ) {
858
						continue 2; // Back to the foreach ( $multipliers as $multiplier )
859
					}
860
				} // foreach ( $currentwidths as $currentwidth ){
861
862
				if ( 'soft' == $crop ) {
863
					$args = array(
864
						'w' => $newwidth,
865
					);
866
				} else { // hard crop, e.g. add_image_size( 'example', 200, 200, true );
867
					$args = array(
868
						'zoom'   => $multiplier,
869
						'resize' => $reqwidth . ',' . $reqheight,
870
					);
871
				}
872
873
				$newsources[ $newwidth ] = array(
874
					'url'         => jetpack_photon_url( $url, $args ),
875
					'descriptor'  => 'w',
876
					'value'       => $newwidth,
877
					);
878
			} // foreach ( $multipliers as $multiplier )
879
			if ( is_array( $newsources ) ) {
880
				if ( function_exists( 'array_replace' ) ) { // PHP 5.3+, preferred
881
					// phpcs:disable
882
					$sources = array_replace( $sources, $newsources );
883
					// phpcs:enable
884
				} else { // For PHP 5.2 using WP shim function
885
					$sources = array_replace_recursive( $sources, $newsources );
886
				}
887
			}
888
		} // if ( isset( $image_meta['width'] ) && isset( $image_meta['file'] ) )
889
890
		return $sources;
891
	}
892
893
	/**
894
	 * Filters an array of image `sizes` values, using $content_width instead of image's full size.
895
	 *
896
	 * @since 4.0.4
897
	 * @since 4.1.0 Returns early for images not within the_content.
898
	 * @param array $sizes An array of media query breakpoints.
899
	 * @param array $size  Width and height of the image
900
	 * @uses Jetpack::get_content_width
901
	 * @return array An array of media query breakpoints.
902
	 */
903
	public function filter_sizes( $sizes, $size ) {
904
		if ( ! doing_filter( 'the_content' ) ){
905
			return $sizes;
906
		}
907
		$content_width = Jetpack::get_content_width();
908
		if ( ! $content_width ) {
909
			$content_width = 1000;
910
		}
911
912
		if ( ( is_array( $size ) && $size[0] < $content_width ) ) {
913
			return $sizes;
914
		}
915
916
		return sprintf( '(max-width: %1$dpx) 100vw, %1$dpx', $content_width );
917
	}
918
919
	/**
920
	 ** GENERAL FUNCTIONS
921
	 **/
922
923
	/**
924
	 * Ensure image URL is valid for Photon.
925
	 * Though Photon functions address some of the URL issues, we should avoid unnecessary processing if we know early on that the image isn't supported.
926
	 *
927
	 * @param string $url
928
	 * @uses wp_parse_args
929
	 * @return bool
930
	 */
931
	protected static function validate_image_url( $url ) {
932
		$parsed_url = @parse_url( $url );
933
934
		if ( ! $parsed_url )
935
			return false;
936
937
		// Parse URL and ensure needed keys exist, since the array returned by `parse_url` only includes the URL components it finds.
938
		$url_info = wp_parse_args( $parsed_url, array(
939
			'scheme' => null,
940
			'host'   => null,
941
			'port'   => null,
942
			'path'   => null
943
		) );
944
945
		// Bail if scheme isn't http or port is set that isn't port 80
946
		if (
947
			( 'http' != $url_info['scheme'] || ! in_array( $url_info['port'], array( 80, null ) ) ) &&
948
			/**
949
			 * Allow Photon to fetch images that are served via HTTPS.
950
			 *
951
			 * @module photon
952
			 *
953
			 * @since 2.4.0
954
			 * @since 3.9.0 Default to false.
955
			 *
956
			 * @param bool $reject_https Should Photon ignore images using the HTTPS scheme. Default to false.
957
			 */
958
			apply_filters( 'jetpack_photon_reject_https', false )
959
		) {
960
			return false;
961
		}
962
963
		// Bail if no host is found
964
		if ( is_null( $url_info['host'] ) )
965
			return false;
966
967
		// Bail if the image alredy went through Photon
968
		if ( preg_match( '#^i[\d]{1}.wp.com$#i', $url_info['host'] ) )
969
			return false;
970
971
		// Bail if no path is found
972
		if ( is_null( $url_info['path'] ) )
973
			return false;
974
975
		// Ensure image extension is acceptable
976
		if ( ! in_array( strtolower( pathinfo( $url_info['path'], PATHINFO_EXTENSION ) ), self::$extensions ) )
977
			return false;
978
979
		// If we got this far, we should have an acceptable image URL
980
		// But let folks filter to decline if they prefer.
981
		/**
982
		 * Overwrite the results of the validation steps an image goes through before to be considered valid to be used by Photon.
983
		 *
984
		 * @module photon
985
		 *
986
		 * @since 3.0.0
987
		 *
988
		 * @param bool true Is the image URL valid and can it be used by Photon. Default to true.
989
		 * @param string $url Image URL.
990
		 * @param array $parsed_url Array of information about the image.
991
		 */
992
		return apply_filters( 'photon_validate_image_url', true, $url, $parsed_url );
993
	}
994
995
	/**
996
	 * Checks if the file exists before it passes the file to photon
997
	 *
998
	 * @param string $src The image URL
999
	 * @return string
1000
	 **/
1001
	public static function strip_image_dimensions_maybe( $src ){
1002
		$stripped_src = $src;
0 ignored issues
show
Unused Code introduced by
$stripped_src is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
1003
1004
		// Build URL, first removing WP's resized string so we pass the original image to Photon
1005
		if ( preg_match( '#(-\d+x\d+)\.(' . implode('|', self::$extensions ) . '){1}$#i', $src, $src_parts ) ) {
1006
			$stripped_src = str_replace( $src_parts[1], '', $src );
1007
			$upload_dir = wp_get_upload_dir();
1008
1009
			// Extracts the file path to the image minus the base url
1010
			$file_path = substr( $stripped_src, strlen ( $upload_dir['baseurl'] ) );
1011
1012
			if( file_exists( $upload_dir["basedir"] . $file_path ) )
1013
				$src = $stripped_src;
1014
		}
1015
1016
		return $src;
1017
	}
1018
1019
	/**
1020
	 * Provide an array of available image sizes and corresponding dimensions.
1021
	 * Similar to get_intermediate_image_sizes() except that it includes image sizes' dimensions, not just their names.
1022
	 *
1023
	 * @global $wp_additional_image_sizes
1024
	 * @uses get_option
1025
	 * @return array
1026
	 */
1027
	protected static function image_sizes() {
1028
		if ( null == self::$image_sizes ) {
1029
			global $_wp_additional_image_sizes;
1030
1031
			// Populate an array matching the data structure of $_wp_additional_image_sizes so we have a consistent structure for image sizes
1032
			$images = array(
1033
				'thumb'  => array(
1034
					'width'  => intval( get_option( 'thumbnail_size_w' ) ),
1035
					'height' => intval( get_option( 'thumbnail_size_h' ) ),
1036
					'crop'   => (bool) get_option( 'thumbnail_crop' )
1037
				),
1038
				'medium' => array(
1039
					'width'  => intval( get_option( 'medium_size_w' ) ),
1040
					'height' => intval( get_option( 'medium_size_h' ) ),
1041
					'crop'   => false
1042
				),
1043
				'large'  => array(
1044
					'width'  => intval( get_option( 'large_size_w' ) ),
1045
					'height' => intval( get_option( 'large_size_h' ) ),
1046
					'crop'   => false
1047
				),
1048
				'full'   => array(
1049
					'width'  => null,
1050
					'height' => null,
1051
					'crop'   => false
1052
				)
1053
			);
1054
1055
			// Compatibility mapping as found in wp-includes/media.php
1056
			$images['thumbnail'] = $images['thumb'];
1057
1058
			// Update class variable, merging in $_wp_additional_image_sizes if any are set
1059
			if ( is_array( $_wp_additional_image_sizes ) && ! empty( $_wp_additional_image_sizes ) )
1060
				self::$image_sizes = array_merge( $images, $_wp_additional_image_sizes );
1061
			else
1062
				self::$image_sizes = $images;
1063
		}
1064
1065
		return is_array( self::$image_sizes ) ? self::$image_sizes : array();
1066
	}
1067
1068
	/**
1069
	 * Pass og:image URLs through Photon
1070
	 *
1071
	 * @param array $tags
1072
	 * @param array $parameters
1073
	 * @uses jetpack_photon_url
1074
	 * @return array
1075
	 */
1076
	function filter_open_graph_tags( $tags, $parameters ) {
1077
		if ( empty( $tags['og:image'] ) ) {
1078
			return $tags;
1079
		}
1080
1081
		$photon_args = array(
1082
			'fit' => sprintf( '%d,%d', 2 * $parameters['image_width'], 2 * $parameters['image_height'] ),
1083
		);
1084
1085
		if ( is_array( $tags['og:image'] ) ) {
1086
			$images = array();
1087
			foreach ( $tags['og:image'] as $image ) {
1088
				$images[] = jetpack_photon_url( $image, $photon_args );
1089
			}
1090
			$tags['og:image'] = $images;
1091
		} else {
1092
			$tags['og:image'] = jetpack_photon_url( $tags['og:image'], $photon_args );
1093
		}
1094
1095
		return $tags;
1096
	}
1097
1098
	public function noresize_intermediate_sizes( $sizes ) {
1099
		return __return_empty_array();
1100
	}
1101
1102
	/**
1103
	 * Enqueue Photon helper script
1104
	 *
1105
	 * @uses wp_enqueue_script, plugins_url
1106
	 * @action wp_enqueue_script
1107
	 * @return null
1108
	 */
1109 View Code Duplication
	public function action_wp_enqueue_scripts() {
1110
		if ( Jetpack_AMP_Support::is_amp_request() ) {
1111
			return;
1112
		}
1113
		wp_enqueue_script(
1114
			'jetpack-photon',
1115
			Jetpack::get_file_url_for_environment(
1116
				'_inc/build/photon/photon.min.js',
1117
				'modules/photon/photon.js'
1118
			),
1119
			array( 'jquery' ),
1120
			20130122,
1121
			true
1122
		);
1123
	}
1124
1125
	/**
1126
	 * Determine if image_downsize should utilize Photon via REST API.
1127
	 *
1128
	 * The WordPress Block Editor (Gutenberg) and other REST API consumers using the wp/v2/media endpoint, especially in the "edit"
1129
	 * context is more akin to the is_admin usage of Photon (see filter_image_downsize). Since consumers are trying to edit content in posts,
1130
	 * Photon should not fire as it will fire later on display. By aborting an attempt to Photonize an image here, we
1131
	 * prevents issues like https://github.com/Automattic/jetpack/issues/10580 .
1132
	 *
1133
	 * To determine if we're using the wp/v2/media endpoint, we hook onto the `rest_request_before_callbacks` filter and
1134
	 * if determined we are using it in the edit context, we'll false out the `jetpack_photon_override_image_downsize` filter.
1135
	 *
1136
	 * @see Jetpack_Photon::filter_image_downsize()
1137
	 *
1138
	 * @param null|WP_Error   $response
1139
	 * @param array           $endpoint_data
1140
	 * @param WP_REST_Request $request  Request used to generate the response.
1141
	 *
1142
	 * @return null|WP_Error The original response object without modification.
1143
	 */
1144
	public function should_rest_photon_image_downsize( $response, $endpoint_data, $request ) {
1145
		if ( ! is_a( $request , 'WP_REST_Request' ) ) {
1146
			return $response; // Something odd is happening. Do nothing and return the response.
1147
		}
1148
1149
		if ( is_wp_error( $response ) ) {
1150
			// If we're going to return an error, we don't need to do anything with Photon.
1151
			return $response;
1152
		}
1153
1154
		$route = $request->get_route();
1155
1156
		if ( false !== strpos( $route, 'wp/v2/media' ) && 'edit' === $request['context'] ) {
1157
			// Don't use `__return_true()`: Use something unique. See ::_override_image_downsize_in_rest_edit_context()
1158
			// Late execution to avoid conflict with other plugins as we really don't want to run in this situation.
1159
			add_filter( 'jetpack_photon_override_image_downsize', array( $this, '_override_image_downsize_in_rest_edit_context' ), 999999 );
1160
		}
1161
1162
		return $response;
1163
1164
	}
1165
1166
	/**
1167
	 * Remove the override we may have added in ::should_rest_photon_image_downsize()
1168
	 * Since ::_override_image_downsize_in_rest_edit_context() is only
1169
	 * every used here, we can always remove it without ever worrying
1170
	 * about breaking any other configuration.
1171
	 *
1172
	 * @param mixed $response
1173
	 * @return mixed Unchanged $response
1174
	 */
1175
	public function cleanup_rest_photon_image_downsize( $response ) {
1176
		remove_filter( 'jetpack_photon_override_image_downsize', array( $this, '_override_image_downsize_in_rest_edit_context' ), 999999 );
1177
		return $response;
1178
	}
1179
1180
	/**
1181
	 * Used internally by ::should_rest_photon_image_downsize() to not photonize
1182
	 * image URLs in ?context=edit REST requests.
1183
	 * MUST NOT be used anywhere else.
1184
	 * We use a unique function instead of __return_true so that we can clean up
1185
	 * after ourselves without breaking anyone else's filters.
1186
	 *
1187
	 * @internal
1188
	 * @return true
1189
	 */
1190
	public function _override_image_downsize_in_rest_edit_context() {
1191
		return true;
1192
	}
1193
}
1194