These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more
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 | // Display warning if site is private |
||
49 | add_action( 'jetpack_activate_module_photon', array( $this, 'action_jetpack_activate_module_photon' ) ); |
||
50 | |||
51 | if ( ! function_exists( 'jetpack_photon_url' ) ) |
||
52 | return; |
||
53 | |||
54 | // Images in post content and galleries |
||
55 | add_filter( 'the_content', array( __CLASS__, 'filter_the_content' ), 999999 ); |
||
56 | add_filter( 'get_post_galleries', array( __CLASS__, 'filter_the_galleries' ), 999999 ); |
||
57 | |||
58 | // Core image retrieval |
||
59 | add_filter( 'image_downsize', array( $this, 'filter_image_downsize' ), 10, 3 ); |
||
60 | |||
61 | // Responsive image srcset substitution |
||
62 | add_filter( 'wp_calculate_image_srcset', array( $this, 'filter_srcset_array' ), 10, 4 ); |
||
63 | |||
64 | // Helpers for maniuplated images |
||
65 | add_action( 'wp_enqueue_scripts', array( $this, 'action_wp_enqueue_scripts' ), 9 ); |
||
66 | } |
||
67 | |||
68 | /** |
||
69 | * Check if site is private and warn user if it is |
||
70 | * |
||
71 | * @uses Jetpack::check_privacy |
||
72 | * @action jetpack_activate_module_photon |
||
73 | * @return null |
||
74 | */ |
||
75 | public function action_jetpack_activate_module_photon() { |
||
76 | Jetpack::check_privacy( __FILE__ ); |
||
77 | } |
||
78 | |||
79 | /** |
||
80 | ** IN-CONTENT IMAGE MANIPULATION FUNCTIONS |
||
81 | **/ |
||
82 | |||
83 | /** |
||
84 | * Match all images and any relevant <a> tags in a block of HTML. |
||
85 | * |
||
86 | * @param string $content Some HTML. |
||
87 | * @return array An array of $images matches, where $images[0] is |
||
88 | * an array of full matches, and the link_url, img_tag, |
||
89 | * and img_url keys are arrays of those matches. |
||
90 | */ |
||
91 | public static function parse_images_from_html( $content ) { |
||
92 | $images = array(); |
||
93 | |||
94 | if ( preg_match_all( '#(?:<a[^>]+?href=["|\'](?P<link_url>[^\s]+?)["|\'][^>]*?>\s*)?(?P<img_tag><img[^>]+?src=["|\'](?P<img_url>[^\s]+?)["|\'].*?>){1}(?:\s*</a>)?#is', $content, $images ) ) { |
||
95 | foreach ( $images as $key => $unused ) { |
||
96 | // Simplify the output as much as possible, mostly for confirming test results. |
||
97 | if ( is_numeric( $key ) && $key > 0 ) |
||
98 | unset( $images[$key] ); |
||
99 | } |
||
100 | |||
101 | return $images; |
||
102 | } |
||
103 | |||
104 | return array(); |
||
105 | } |
||
106 | |||
107 | /** |
||
108 | * Try to determine height and width from strings WP appends to resized image filenames. |
||
109 | * |
||
110 | * @param string $src The image URL. |
||
111 | * @return array An array consisting of width and height. |
||
112 | */ |
||
113 | public static function parse_dimensions_from_filename( $src ) { |
||
114 | $width_height_string = array(); |
||
115 | |||
116 | if ( preg_match( '#-(\d+)x(\d+)\.(?:' . implode('|', self::$extensions ) . '){1}$#i', $src, $width_height_string ) ) { |
||
117 | $width = (int) $width_height_string[1]; |
||
118 | $height = (int) $width_height_string[2]; |
||
119 | |||
120 | if ( $width && $height ) |
||
121 | return array( $width, $height ); |
||
122 | } |
||
123 | |||
124 | return array( false, false ); |
||
125 | } |
||
126 | |||
127 | /** |
||
128 | * Identify images in post content, and if images are local (uploaded to the current site), pass through Photon. |
||
129 | * |
||
130 | * @param string $content |
||
131 | * @uses self::validate_image_url, apply_filters, jetpack_photon_url, esc_url |
||
132 | * @filter the_content |
||
133 | * @return string |
||
134 | */ |
||
135 | public static function filter_the_content( $content ) { |
||
136 | $images = Jetpack_Photon::parse_images_from_html( $content ); |
||
137 | |||
138 | if ( ! empty( $images ) ) { |
||
139 | $content_width = Jetpack::get_content_width(); |
||
140 | |||
141 | $image_sizes = self::image_sizes(); |
||
142 | $upload_dir = wp_upload_dir(); |
||
143 | |||
144 | foreach ( $images[0] as $index => $tag ) { |
||
145 | // Default to resize, though fit may be used in certain cases where a dimension cannot be ascertained |
||
146 | $transform = 'resize'; |
||
147 | |||
148 | // Start with a clean attachment ID each time |
||
149 | $attachment_id = false; |
||
150 | |||
151 | // Flag if we need to munge a fullsize URL |
||
152 | $fullsize_url = false; |
||
153 | |||
154 | // Identify image source |
||
155 | $src = $src_orig = $images['img_url'][ $index ]; |
||
156 | |||
157 | /** |
||
158 | * Allow specific images to be skipped by Photon. |
||
159 | * |
||
160 | * @module photon |
||
161 | * |
||
162 | * @since 2.0.3 |
||
163 | * |
||
164 | * @param bool false Should Photon ignore this image. Default to false. |
||
165 | * @param string $src Image URL. |
||
166 | * @param string $tag Image Tag (Image HTML output). |
||
167 | */ |
||
168 | if ( apply_filters( 'jetpack_photon_skip_image', false, $src, $tag ) ) |
||
169 | continue; |
||
170 | |||
171 | // Support Automattic's Lazy Load plugin |
||
172 | // Can't modify $tag yet as we need unadulterated version later |
||
173 | if ( preg_match( '#data-lazy-src=["|\'](.+?)["|\']#i', $images['img_tag'][ $index ], $lazy_load_src ) ) { |
||
174 | $placeholder_src = $placeholder_src_orig = $src; |
||
175 | $src = $src_orig = $lazy_load_src[1]; |
||
176 | } elseif ( preg_match( '#data-lazy-original=["|\'](.+?)["|\']#i', $images['img_tag'][ $index ], $lazy_load_src ) ) { |
||
177 | $placeholder_src = $placeholder_src_orig = $src; |
||
178 | $src = $src_orig = $lazy_load_src[1]; |
||
179 | } |
||
180 | |||
181 | // Check if image URL should be used with Photon |
||
182 | if ( self::validate_image_url( $src ) ) { |
||
183 | // Find the width and height attributes |
||
184 | $width = $height = false; |
||
185 | |||
186 | // First, check the image tag |
||
187 | if ( preg_match( '#width=["|\']?([\d%]+)["|\']?#i', $images['img_tag'][ $index ], $width_string ) ) |
||
188 | $width = $width_string[1]; |
||
189 | |||
190 | if ( preg_match( '#height=["|\']?([\d%]+)["|\']?#i', $images['img_tag'][ $index ], $height_string ) ) |
||
191 | $height = $height_string[1]; |
||
192 | |||
193 | // Can't pass both a relative width and height, so unset the height in favor of not breaking the horizontal layout. |
||
194 | if ( false !== strpos( $width, '%' ) && false !== strpos( $height, '%' ) ) |
||
195 | $width = $height = false; |
||
196 | |||
197 | // Detect WP registered image size from HTML class |
||
198 | if ( preg_match( '#class=["|\']?[^"\']*size-([^"\'\s]+)[^"\']*["|\']?#i', $images['img_tag'][ $index ], $size ) ) { |
||
199 | $size = array_pop( $size ); |
||
200 | |||
201 | if ( false === $width && false === $height && 'full' != $size && array_key_exists( $size, $image_sizes ) ) { |
||
202 | $width = (int) $image_sizes[ $size ]['width']; |
||
203 | $height = (int) $image_sizes[ $size ]['height']; |
||
204 | $transform = $image_sizes[ $size ]['crop'] ? 'resize' : 'fit'; |
||
205 | } |
||
206 | } else { |
||
207 | unset( $size ); |
||
208 | } |
||
209 | |||
210 | // WP Attachment ID, if uploaded to this site |
||
211 | if ( |
||
212 | preg_match( '#class=["|\']?[^"\']*wp-image-([\d]+)[^"\']*["|\']?#i', $images['img_tag'][ $index ], $attachment_id ) && |
||
213 | ( |
||
214 | 0 === strpos( $src, $upload_dir['baseurl'] ) || |
||
215 | /** |
||
216 | * Filter whether an image using an attachment ID in its class has to be uploaded to the local site to go through Photon. |
||
217 | * |
||
218 | * @module photon |
||
219 | * |
||
220 | * @since 2.0.3 |
||
221 | * |
||
222 | * @param bool false Was the image uploaded to the local site. Default to false. |
||
223 | * @param array $args { |
||
224 | * Array of image details. |
||
225 | * |
||
226 | * @type $src Image URL. |
||
227 | * @type tag Image tag (Image HTML output). |
||
228 | * @type $images Array of information about the image. |
||
229 | * @type $index Image index. |
||
230 | * } |
||
231 | */ |
||
232 | apply_filters( 'jetpack_photon_image_is_local', false, compact( 'src', 'tag', 'images', 'index' ) ) |
||
233 | ) |
||
234 | ) { |
||
235 | $attachment_id = intval( array_pop( $attachment_id ) ); |
||
236 | |||
237 | if ( $attachment_id ) { |
||
238 | $attachment = get_post( $attachment_id ); |
||
239 | |||
240 | // Basic check on returned post object |
||
241 | if ( is_object( $attachment ) && ! is_wp_error( $attachment ) && 'attachment' == $attachment->post_type ) { |
||
242 | $src_per_wp = wp_get_attachment_image_src( $attachment_id, isset( $size ) ? $size : 'full' ); |
||
243 | |||
244 | if ( self::validate_image_url( $src_per_wp[0] ) ) { |
||
245 | $src = $src_per_wp[0]; |
||
246 | $fullsize_url = true; |
||
247 | |||
248 | // Prevent image distortion if a detected dimension exceeds the image's natural dimensions |
||
249 | if ( ( false !== $width && $width > $src_per_wp[1] ) || ( false !== $height && $height > $src_per_wp[2] ) ) { |
||
250 | $width = false == $width ? false : min( $width, $src_per_wp[1] ); |
||
251 | $height = false == $height ? false : min( $height, $src_per_wp[2] ); |
||
252 | } |
||
253 | |||
254 | // If no width and height are found, max out at source image's natural dimensions |
||
255 | // Otherwise, respect registered image sizes' cropping setting |
||
256 | if ( false == $width && false == $height ) { |
||
257 | $width = $src_per_wp[1]; |
||
258 | $height = $src_per_wp[2]; |
||
259 | $transform = 'fit'; |
||
260 | } elseif ( isset( $size ) && array_key_exists( $size, $image_sizes ) && isset( $image_sizes[ $size ]['crop'] ) ) { |
||
261 | $transform = (bool) $image_sizes[ $size ]['crop'] ? 'resize' : 'fit'; |
||
262 | } |
||
263 | } |
||
264 | } else { |
||
265 | unset( $attachment_id ); |
||
266 | unset( $attachment ); |
||
267 | } |
||
268 | } |
||
269 | } |
||
270 | |||
271 | // If image tag lacks width and height arguments, try to determine from strings WP appends to resized image filenames. |
||
272 | if ( false === $width && false === $height ) { |
||
273 | list( $width, $height ) = Jetpack_Photon::parse_dimensions_from_filename( $src ); |
||
274 | } |
||
275 | |||
276 | // If width is available, constrain to $content_width |
||
277 | if ( false !== $width && false === strpos( $width, '%' ) && is_numeric( $content_width ) ) { |
||
278 | if ( $width > $content_width && false !== $height && false === strpos( $height, '%' ) ) { |
||
279 | $height = round( ( $content_width * $height ) / $width ); |
||
280 | $width = $content_width; |
||
281 | } elseif ( $width > $content_width ) { |
||
282 | $width = $content_width; |
||
283 | } |
||
284 | } |
||
285 | |||
286 | // Set a width if none is found and $content_width is available |
||
287 | // If width is set in this manner and height is available, use `fit` instead of `resize` to prevent skewing |
||
288 | if ( false === $width && is_numeric( $content_width ) ) { |
||
289 | $width = (int) $content_width; |
||
290 | |||
291 | if ( false !== $height ) |
||
292 | $transform = 'fit'; |
||
293 | } |
||
294 | |||
295 | // Detect if image source is for a custom-cropped thumbnail and prevent further URL manipulation. |
||
296 | if ( ! $fullsize_url && preg_match_all( '#-e[a-z0-9]+(-\d+x\d+)?\.(' . implode('|', self::$extensions ) . '){1}$#i', basename( $src ), $filename ) ) |
||
297 | $fullsize_url = true; |
||
298 | |||
299 | // Build URL, first maybe removing WP's resized string so we pass the original image to Photon |
||
300 | if ( ! $fullsize_url ) { |
||
301 | $src = self::strip_image_dimensions_maybe( $src ); |
||
302 | } |
||
303 | |||
304 | // Build array of Photon args and expose to filter before passing to Photon URL function |
||
305 | $args = array(); |
||
306 | |||
307 | if ( false !== $width && false !== $height && false === strpos( $width, '%' ) && false === strpos( $height, '%' ) ) |
||
308 | $args[ $transform ] = $width . ',' . $height; |
||
309 | elseif ( false !== $width ) |
||
310 | $args['w'] = $width; |
||
311 | elseif ( false !== $height ) |
||
312 | $args['h'] = $height; |
||
313 | |||
314 | /** |
||
315 | * Filter the array of Photon arguments added to an image when it goes through Photon. |
||
316 | * By default, only includes width and height values. |
||
317 | * @see https://developer.wordpress.com/docs/photon/api/ |
||
318 | * |
||
319 | * @module photon |
||
320 | * |
||
321 | * @since 2.0.0 |
||
322 | * |
||
323 | * @param array $args Array of Photon Arguments. |
||
324 | * @param array $args { |
||
325 | * Array of image details. |
||
326 | * |
||
327 | * @type $tag Image tag (Image HTML output). |
||
328 | * @type $src Image URL. |
||
329 | * @type $src_orig Original Image URL. |
||
330 | * @type $width Image width. |
||
331 | * @type $height Image height. |
||
332 | * } |
||
333 | */ |
||
334 | $args = apply_filters( 'jetpack_photon_post_image_args', $args, compact( 'tag', 'src', 'src_orig', 'width', 'height' ) ); |
||
335 | |||
336 | $photon_url = jetpack_photon_url( $src, $args ); |
||
337 | |||
338 | // Modify image tag if Photon function provides a URL |
||
339 | // 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. |
||
340 | if ( $src != $photon_url ) { |
||
341 | $new_tag = $tag; |
||
342 | |||
343 | // If present, replace the link href with a Photoned URL for the full-size image. |
||
344 | if ( ! empty( $images['link_url'][ $index ] ) && self::validate_image_url( $images['link_url'][ $index ] ) ) |
||
345 | $new_tag = preg_replace( '#(href=["|\'])' . $images['link_url'][ $index ] . '(["|\'])#i', '\1' . jetpack_photon_url( $images['link_url'][ $index ] ) . '\2', $new_tag, 1 ); |
||
346 | |||
347 | // Supplant the original source value with our Photon URL |
||
348 | $photon_url = esc_url( $photon_url ); |
||
349 | $new_tag = str_replace( $src_orig, $photon_url, $new_tag ); |
||
350 | |||
351 | // If Lazy Load is in use, pass placeholder image through Photon |
||
352 | if ( isset( $placeholder_src ) && self::validate_image_url( $placeholder_src ) ) { |
||
353 | $placeholder_src = jetpack_photon_url( $placeholder_src ); |
||
354 | |||
355 | if ( $placeholder_src != $placeholder_src_orig ) |
||
356 | $new_tag = str_replace( $placeholder_src_orig, esc_url( $placeholder_src ), $new_tag ); |
||
357 | |||
358 | unset( $placeholder_src ); |
||
359 | } |
||
360 | |||
361 | // Remove the width and height arguments from the tag to prevent distortion |
||
362 | $new_tag = preg_replace( '#(?<=\s)(width|height)=["|\']?[\d%]+["|\']?\s?#i', '', $new_tag ); |
||
363 | |||
364 | // Tag an image for dimension checking |
||
365 | $new_tag = preg_replace( '#(\s?/)?>(\s*</a>)?$#i', ' data-recalc-dims="1"\1>\2', $new_tag ); |
||
366 | |||
367 | // Replace original tag with modified version |
||
368 | $content = str_replace( $tag, $new_tag, $content ); |
||
369 | } |
||
370 | } elseif ( preg_match( '#^http(s)?://i[\d]{1}.wp.com#', $src ) && ! empty( $images['link_url'][ $index ] ) && self::validate_image_url( $images['link_url'][ $index ] ) ) { |
||
371 | $new_tag = preg_replace( '#(href=["|\'])' . $images['link_url'][ $index ] . '(["|\'])#i', '\1' . jetpack_photon_url( $images['link_url'][ $index ] ) . '\2', $tag, 1 ); |
||
372 | |||
373 | $content = str_replace( $tag, $new_tag, $content ); |
||
374 | } |
||
375 | } |
||
376 | } |
||
377 | |||
378 | return $content; |
||
379 | } |
||
380 | |||
381 | public static function filter_the_galleries( $galleries ) { |
||
382 | if ( empty( $galleries ) || ! is_array( $galleries ) ) { |
||
383 | return $galleries; |
||
384 | } |
||
385 | |||
386 | // Pass by reference, so we can modify them in place. |
||
387 | foreach ( $galleries as &$this_gallery ) { |
||
388 | if ( is_string( $this_gallery ) ) { |
||
389 | $this_gallery = self::filter_the_content( $this_gallery ); |
||
390 | // LEAVING COMMENTED OUT as for the moment it doesn't seem |
||
391 | // necessary and I'm not sure how it would propagate through. |
||
392 | // } elseif ( is_array( $this_gallery ) |
||
0 ignored issues
–
show
|
|||
393 | // && ! empty( $this_gallery['src'] ) |
||
0 ignored issues
–
show
Unused Code
Comprehensibility
introduced
by
65% of this comment could be valid code. Did you maybe forget this after debugging?
Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it. The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production. This check looks for comments that seem to be mostly valid code and reports them. ![]() |
|||
394 | // && ! empty( $this_gallery['type'] ) |
||
0 ignored issues
–
show
Unused Code
Comprehensibility
introduced
by
65% of this comment could be valid code. Did you maybe forget this after debugging?
Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it. The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production. This check looks for comments that seem to be mostly valid code and reports them. ![]() |
|||
395 | // && in_array( $this_gallery['type'], array( 'rectangle', 'square', 'circle' ) ) ) { |
||
0 ignored issues
–
show
Unused Code
Comprehensibility
introduced
by
60% of this comment could be valid code. Did you maybe forget this after debugging?
Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it. The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production. This check looks for comments that seem to be mostly valid code and reports them. ![]() |
|||
396 | // $this_gallery['src'] = array_map( 'jetpack_photon_url', $this_gallery['src'] ); |
||
0 ignored issues
–
show
Unused Code
Comprehensibility
introduced
by
62% of this comment could be valid code. Did you maybe forget this after debugging?
Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it. The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production. This check looks for comments that seem to be mostly valid code and reports them. ![]() |
|||
397 | } |
||
398 | } |
||
399 | unset( $this_gallery ); // break the reference. |
||
400 | |||
401 | return $galleries; |
||
402 | } |
||
403 | |||
404 | /** |
||
405 | ** CORE IMAGE RETRIEVAL |
||
406 | **/ |
||
407 | |||
408 | /** |
||
409 | * Filter post thumbnail image retrieval, passing images through Photon |
||
410 | * |
||
411 | * @param string|bool $image |
||
412 | * @param int $attachment_id |
||
413 | * @param string|array $size |
||
414 | * @uses is_admin, apply_filters, wp_get_attachment_url, self::validate_image_url, this::image_sizes, jetpack_photon_url |
||
415 | * @filter image_downsize |
||
416 | * @return string|bool |
||
417 | */ |
||
418 | public function filter_image_downsize( $image, $attachment_id, $size ) { |
||
419 | // Don't foul up the admin side of things, and provide plugins a way of preventing Photon from being applied to images. |
||
420 | if ( |
||
421 | is_admin() || |
||
422 | /** |
||
423 | * Provide plugins a way of preventing Photon from being applied to images retrieved from WordPress Core. |
||
424 | * |
||
425 | * @module photon |
||
426 | * |
||
427 | * @since 2.0.0 |
||
428 | * |
||
429 | * @param bool false Stop Photon from being applied to the image. Default to false. |
||
430 | * @param array $args { |
||
431 | * Array of image details. |
||
432 | * |
||
433 | * @type $image Image URL. |
||
434 | * @type $attachment_id Attachment ID of the image. |
||
435 | * @type $size Image size. Can be a string (name of the image size, e.g. full) or an integer. |
||
436 | * } |
||
437 | */ |
||
438 | apply_filters( 'jetpack_photon_override_image_downsize', false, compact( 'image', 'attachment_id', 'size' ) ) |
||
439 | ) |
||
440 | return $image; |
||
441 | |||
442 | // Get the image URL and proceed with Photon-ification if successful |
||
443 | $image_url = wp_get_attachment_url( $attachment_id ); |
||
444 | |||
445 | // Set this to true later when we know we have size meta. |
||
446 | $has_size_meta = false; |
||
447 | |||
448 | if ( $image_url ) { |
||
449 | // Check if image URL should be used with Photon |
||
450 | if ( ! self::validate_image_url( $image_url ) ) |
||
451 | return $image; |
||
452 | |||
453 | $intermediate = true; // For the fourth array item returned by the image_downsize filter. |
||
454 | |||
455 | // If an image is requested with a size known to WordPress, use that size's settings with Photon |
||
456 | if ( ( is_string( $size ) || is_int( $size ) ) && array_key_exists( $size, self::image_sizes() ) ) { |
||
457 | $image_args = self::image_sizes(); |
||
458 | $image_args = $image_args[ $size ]; |
||
459 | |||
460 | $photon_args = array(); |
||
461 | |||
462 | $image_meta = image_get_intermediate_size( $attachment_id, $size ); |
||
463 | |||
464 | // 'full' is a special case: We need consistent data regardless of the requested size. |
||
465 | if ( 'full' == $size ) { |
||
466 | $image_meta = wp_get_attachment_metadata( $attachment_id ); |
||
467 | $intermediate = false; |
||
468 | } elseif ( ! $image_meta ) { |
||
469 | // If we still don't have any image meta at this point, it's probably from a custom thumbnail size |
||
470 | // for an image that was uploaded before the custom image was added to the theme. Try to determine the size manually. |
||
471 | $image_meta = wp_get_attachment_metadata( $attachment_id ); |
||
472 | |||
473 | View Code Duplication | if ( isset( $image_meta['width'], $image_meta['height'] ) ) { |
|
474 | $image_resized = image_resize_dimensions( $image_meta['width'], $image_meta['height'], $image_args['width'], $image_args['height'], $image_args['crop'] ); |
||
475 | if ( $image_resized ) { // This could be false when the requested image size is larger than the full-size image. |
||
476 | $image_meta['width'] = $image_resized[6]; |
||
477 | $image_meta['height'] = $image_resized[7]; |
||
478 | } |
||
479 | } |
||
480 | } |
||
481 | |||
482 | View Code Duplication | if ( isset( $image_meta['width'], $image_meta['height'] ) ) { |
|
483 | $image_args['width'] = $image_meta['width']; |
||
484 | $image_args['height'] = $image_meta['height']; |
||
485 | |||
486 | list( $image_args['width'], $image_args['height'] ) = image_constrain_size_for_editor( $image_args['width'], $image_args['height'], $size, 'display' ); |
||
487 | $has_size_meta = true; |
||
488 | } |
||
489 | |||
490 | // Expose determined arguments to a filter before passing to Photon |
||
491 | $transform = $image_args['crop'] ? 'resize' : 'fit'; |
||
492 | |||
493 | // Check specified image dimensions and account for possible zero values; photon fails to resize if a dimension is zero. |
||
494 | if ( 0 == $image_args['width'] || 0 == $image_args['height'] ) { |
||
495 | if ( 0 == $image_args['width'] && 0 < $image_args['height'] ) { |
||
496 | $photon_args['h'] = $image_args['height']; |
||
497 | } elseif ( 0 == $image_args['height'] && 0 < $image_args['width'] ) { |
||
498 | $photon_args['w'] = $image_args['width']; |
||
499 | } |
||
500 | } else { |
||
501 | if ( ( 'resize' === $transform ) && $image_meta = wp_get_attachment_metadata( $attachment_id ) ) { |
||
502 | if ( isset( $image_meta['width'], $image_meta['height'] ) ) { |
||
503 | // Lets make sure that we don't upscale images since wp never upscales them as well |
||
504 | $smaller_width = ( ( $image_meta['width'] < $image_args['width'] ) ? $image_meta['width'] : $image_args['width'] ); |
||
505 | $smaller_height = ( ( $image_meta['height'] < $image_args['height'] ) ? $image_meta['height'] : $image_args['height'] ); |
||
506 | |||
507 | $photon_args[ $transform ] = $smaller_width . ',' . $smaller_height; |
||
508 | } |
||
509 | } else { |
||
510 | $photon_args[ $transform ] = $image_args['width'] . ',' . $image_args['height']; |
||
511 | } |
||
512 | |||
513 | } |
||
514 | |||
515 | |||
516 | /** |
||
517 | * Filter the Photon Arguments added to an image when going through Photon, when that image size is a string. |
||
518 | * Image size will be a string (e.g. "full", "medium") when it is known to WordPress. |
||
519 | * |
||
520 | * @module photon |
||
521 | * |
||
522 | * @since 2.0.0 |
||
523 | * |
||
524 | * @param array $photon_args Array of Photon arguments. |
||
525 | * @param array $args { |
||
526 | * Array of image details. |
||
527 | * |
||
528 | * @type $image_args Array of Image arguments (width, height, crop). |
||
529 | * @type $image_url Image URL. |
||
530 | * @type $attachment_id Attachment ID of the image. |
||
531 | * @type $size Image size. Can be a string (name of the image size, e.g. full) or an integer. |
||
532 | * @type $transform Value can be resize or fit. |
||
533 | * @see https://developer.wordpress.com/docs/photon/api |
||
534 | * } |
||
535 | */ |
||
536 | $photon_args = apply_filters( 'jetpack_photon_image_downsize_string', $photon_args, compact( 'image_args', 'image_url', 'attachment_id', 'size', 'transform' ) ); |
||
537 | |||
538 | // Generate Photon URL |
||
539 | $image = array( |
||
540 | jetpack_photon_url( $image_url, $photon_args ), |
||
541 | $has_size_meta ? $image_args['width'] : false, |
||
542 | $has_size_meta ? $image_args['height'] : false, |
||
543 | $intermediate |
||
544 | ); |
||
545 | } elseif ( is_array( $size ) ) { |
||
546 | // Pull width and height values from the provided array, if possible |
||
547 | $width = isset( $size[0] ) ? (int) $size[0] : false; |
||
548 | $height = isset( $size[1] ) ? (int) $size[1] : false; |
||
549 | |||
550 | // Don't bother if necessary parameters aren't passed. |
||
551 | if ( ! $width || ! $height ) { |
||
552 | return $image; |
||
553 | } |
||
554 | |||
555 | $image_meta = wp_get_attachment_metadata( $attachment_id ); |
||
556 | if ( isset( $image_meta['width'], $image_meta['height'] ) ) { |
||
557 | $image_resized = image_resize_dimensions( $image_meta['width'], $image_meta['height'], $width, $height ); |
||
558 | |||
559 | if ( $image_resized ) { // This could be false when the requested image size is larger than the full-size image. |
||
560 | $width = $image_resized[6]; |
||
561 | $height = $image_resized[7]; |
||
562 | } else { |
||
563 | $width = $image_meta['width']; |
||
564 | $height = $image_meta['height']; |
||
565 | } |
||
566 | |||
567 | $has_size_meta = true; |
||
568 | } |
||
569 | |||
570 | list( $width, $height ) = image_constrain_size_for_editor( $width, $height, $size ); |
||
571 | |||
572 | // Expose arguments to a filter before passing to Photon |
||
573 | $photon_args = array( |
||
574 | 'fit' => $width . ',' . $height |
||
575 | ); |
||
576 | |||
577 | /** |
||
578 | * Filter the Photon Arguments added to an image when going through Photon, |
||
579 | * when the image size is an array of height and width values. |
||
580 | * |
||
581 | * @module photon |
||
582 | * |
||
583 | * @since 2.0.0 |
||
584 | * |
||
585 | * @param array $photon_args Array of Photon arguments. |
||
586 | * @param array $args { |
||
587 | * Array of image details. |
||
588 | * |
||
589 | * @type $width Image width. |
||
590 | * @type height Image height. |
||
591 | * @type $image_url Image URL. |
||
592 | * @type $attachment_id Attachment ID of the image. |
||
593 | * } |
||
594 | */ |
||
595 | $photon_args = apply_filters( 'jetpack_photon_image_downsize_array', $photon_args, compact( 'width', 'height', 'image_url', 'attachment_id' ) ); |
||
596 | |||
597 | // Generate Photon URL |
||
598 | $image = array( |
||
599 | jetpack_photon_url( $image_url, $photon_args ), |
||
600 | $has_size_meta ? $width : false, |
||
601 | $has_size_meta ? $height : false, |
||
602 | $intermediate |
||
603 | ); |
||
604 | } |
||
605 | } |
||
606 | |||
607 | return $image; |
||
608 | } |
||
609 | |||
610 | /** |
||
611 | * Filters an array of image `srcset` values, replacing each URL with its Photon equivalent. |
||
612 | * |
||
613 | * @since 3.8.0 |
||
614 | * @param array $sources An array of image urls and widths. |
||
615 | * @uses self::validate_image_url, jetpack_photon_url |
||
616 | * @return array An array of Photon image urls and widths. |
||
617 | */ |
||
618 | public function filter_srcset_array( $sources, $size_array, $image_src, $image_meta ) { |
||
619 | $upload_dir = wp_upload_dir(); |
||
620 | |||
621 | foreach ( $sources as $i => $source ) { |
||
622 | if ( ! self::validate_image_url( $source['url'] ) ) { |
||
623 | continue; |
||
624 | } |
||
625 | |||
626 | $url = $source['url']; |
||
627 | list( $width, $height ) = Jetpack_Photon::parse_dimensions_from_filename( $url ); |
||
628 | |||
629 | // It's quicker to get the full size with the data we have already, if available |
||
630 | if ( isset( $image_meta['file'] ) ) { |
||
631 | $url = trailingslashit( $upload_dir['baseurl'] ) . $image_meta['file']; |
||
632 | } else { |
||
633 | $url = Jetpack_Photon::strip_image_dimensions_maybe( $url ); |
||
634 | } |
||
635 | |||
636 | $args = array(); |
||
637 | if ( 'w' === $source['descriptor'] ) { |
||
638 | if ( $height && ( $source['value'] == $width ) ) { |
||
639 | $args['resize'] = $width . ',' . $height; |
||
640 | } else { |
||
641 | $args['w'] = $source['value']; |
||
642 | } |
||
643 | |||
644 | } |
||
645 | |||
646 | $sources[ $i ]['url'] = jetpack_photon_url( $url, $args ); |
||
647 | } |
||
648 | |||
649 | return $sources; |
||
650 | } |
||
651 | |||
652 | /** |
||
653 | ** GENERAL FUNCTIONS |
||
654 | **/ |
||
655 | |||
656 | /** |
||
657 | * Ensure image URL is valid for Photon. |
||
658 | * 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. |
||
659 | * |
||
660 | * @param string $url |
||
661 | * @uses wp_parse_args |
||
662 | * @return bool |
||
663 | */ |
||
664 | protected static function validate_image_url( $url ) { |
||
665 | $parsed_url = @parse_url( $url ); |
||
666 | |||
667 | if ( ! $parsed_url ) |
||
668 | return false; |
||
669 | |||
670 | // Parse URL and ensure needed keys exist, since the array returned by `parse_url` only includes the URL components it finds. |
||
671 | $url_info = wp_parse_args( $parsed_url, array( |
||
672 | 'scheme' => null, |
||
673 | 'host' => null, |
||
674 | 'port' => null, |
||
675 | 'path' => null |
||
676 | ) ); |
||
677 | |||
678 | // Bail if scheme isn't http or port is set that isn't port 80 |
||
679 | if ( |
||
680 | ( 'http' != $url_info['scheme'] || ! in_array( $url_info['port'], array( 80, null ) ) ) && |
||
681 | /** |
||
682 | * Allow Photon to fetch images that are served via HTTPS. |
||
683 | * |
||
684 | * @module photon |
||
685 | * |
||
686 | * @since 2.4.0 |
||
687 | * @since 3.9.0 Default to false. |
||
688 | * |
||
689 | * @param bool $reject_https Should Photon ignore images using the HTTPS scheme. Default to false. |
||
690 | */ |
||
691 | apply_filters( 'jetpack_photon_reject_https', false ) |
||
692 | ) { |
||
693 | return false; |
||
694 | } |
||
695 | |||
696 | // Bail if no host is found |
||
697 | if ( is_null( $url_info['host'] ) ) |
||
698 | return false; |
||
699 | |||
700 | // Bail if the image alredy went through Photon |
||
701 | if ( preg_match( '#^i[\d]{1}.wp.com$#i', $url_info['host'] ) ) |
||
702 | return false; |
||
703 | |||
704 | // Bail if no path is found |
||
705 | if ( is_null( $url_info['path'] ) ) |
||
706 | return false; |
||
707 | |||
708 | // Ensure image extension is acceptable |
||
709 | if ( ! in_array( strtolower( pathinfo( $url_info['path'], PATHINFO_EXTENSION ) ), self::$extensions ) ) |
||
710 | return false; |
||
711 | |||
712 | // If we got this far, we should have an acceptable image URL |
||
713 | // But let folks filter to decline if they prefer. |
||
714 | /** |
||
715 | * Overwrite the results of the validation steps an image goes through before to be considered valid to be used by Photon. |
||
716 | * |
||
717 | * @module photon |
||
718 | * |
||
719 | * @since 3.0.0 |
||
720 | * |
||
721 | * @param bool true Is the image URL valid and can it be used by Photon. Default to true. |
||
722 | * @param string $url Image URL. |
||
723 | * @param array $parsed_url Array of information about the image. |
||
724 | */ |
||
725 | return apply_filters( 'photon_validate_image_url', true, $url, $parsed_url ); |
||
726 | } |
||
727 | |||
728 | /** |
||
729 | * Checks if the file exists before it passes the file to photon |
||
730 | * |
||
731 | * @param string $src The image URL |
||
732 | * @return string |
||
733 | **/ |
||
734 | protected static function strip_image_dimensions_maybe( $src ){ |
||
735 | $stripped_src = $src; |
||
736 | |||
737 | // Build URL, first removing WP's resized string so we pass the original image to Photon |
||
738 | if ( preg_match( '#(-\d+x\d+)\.(' . implode('|', self::$extensions ) . '){1}$#i', $src, $src_parts ) ) { |
||
739 | $stripped_src = str_replace( $src_parts[1], '', $src ); |
||
740 | $upload_dir = wp_upload_dir(); |
||
741 | |||
742 | // Extracts the file path to the image minus the base url |
||
743 | $file_path = substr( $stripped_src, strlen ( $upload_dir['baseurl'] ) ); |
||
744 | |||
745 | if( file_exists( $upload_dir["basedir"] . $file_path ) ) |
||
746 | $src = $stripped_src; |
||
747 | } |
||
748 | |||
749 | return $src; |
||
750 | } |
||
751 | |||
752 | /** |
||
753 | * Provide an array of available image sizes and corresponding dimensions. |
||
754 | * Similar to get_intermediate_image_sizes() except that it includes image sizes' dimensions, not just their names. |
||
755 | * |
||
756 | * @global $wp_additional_image_sizes |
||
757 | * @uses get_option |
||
758 | * @return array |
||
759 | */ |
||
760 | protected static function image_sizes() { |
||
761 | if ( null == self::$image_sizes ) { |
||
762 | global $_wp_additional_image_sizes; |
||
763 | |||
764 | // Populate an array matching the data structure of $_wp_additional_image_sizes so we have a consistent structure for image sizes |
||
765 | $images = array( |
||
766 | 'thumb' => array( |
||
767 | 'width' => intval( get_option( 'thumbnail_size_w' ) ), |
||
768 | 'height' => intval( get_option( 'thumbnail_size_h' ) ), |
||
769 | 'crop' => (bool) get_option( 'thumbnail_crop' ) |
||
770 | ), |
||
771 | 'medium' => array( |
||
772 | 'width' => intval( get_option( 'medium_size_w' ) ), |
||
773 | 'height' => intval( get_option( 'medium_size_h' ) ), |
||
774 | 'crop' => false |
||
775 | ), |
||
776 | 'large' => array( |
||
777 | 'width' => intval( get_option( 'large_size_w' ) ), |
||
778 | 'height' => intval( get_option( 'large_size_h' ) ), |
||
779 | 'crop' => false |
||
780 | ), |
||
781 | 'full' => array( |
||
782 | 'width' => null, |
||
783 | 'height' => null, |
||
784 | 'crop' => false |
||
785 | ) |
||
786 | ); |
||
787 | |||
788 | // Compatibility mapping as found in wp-includes/media.php |
||
789 | $images['thumbnail'] = $images['thumb']; |
||
790 | |||
791 | // Update class variable, merging in $_wp_additional_image_sizes if any are set |
||
792 | if ( is_array( $_wp_additional_image_sizes ) && ! empty( $_wp_additional_image_sizes ) ) |
||
793 | self::$image_sizes = array_merge( $images, $_wp_additional_image_sizes ); |
||
794 | else |
||
795 | self::$image_sizes = $images; |
||
796 | } |
||
797 | |||
798 | return is_array( self::$image_sizes ) ? self::$image_sizes : array(); |
||
799 | } |
||
800 | |||
801 | /** |
||
802 | * Pass og:image URLs through Photon |
||
803 | * |
||
804 | * @param array $tags |
||
805 | * @param array $parameters |
||
806 | * @uses jetpack_photon_url |
||
807 | * @return array |
||
808 | */ |
||
809 | function filter_open_graph_tags( $tags, $parameters ) { |
||
810 | if ( empty( $tags['og:image'] ) ) { |
||
811 | return $tags; |
||
812 | } |
||
813 | |||
814 | $photon_args = array( |
||
815 | 'fit' => sprintf( '%d,%d', 2 * $parameters['image_width'], 2 * $parameters['image_height'] ), |
||
816 | ); |
||
817 | |||
818 | if ( is_array( $tags['og:image'] ) ) { |
||
819 | $images = array(); |
||
820 | foreach ( $tags['og:image'] as $image ) { |
||
821 | $images[] = jetpack_photon_url( $image, $photon_args ); |
||
822 | } |
||
823 | $tags['og:image'] = $images; |
||
824 | } else { |
||
825 | $tags['og:image'] = jetpack_photon_url( $tags['og:image'], $photon_args ); |
||
826 | } |
||
827 | |||
828 | return $tags; |
||
829 | } |
||
830 | |||
831 | /** |
||
832 | * Enqueue Photon helper script |
||
833 | * |
||
834 | * @uses wp_enqueue_script, plugins_url |
||
835 | * @action wp_enqueue_script |
||
836 | * @return null |
||
837 | */ |
||
838 | public function action_wp_enqueue_scripts() { |
||
839 | wp_enqueue_script( 'jetpack-photon', plugins_url( 'modules/photon/photon.js', JETPACK__PLUGIN_FILE ), array( 'jquery' ), 20130122, true ); |
||
840 | } |
||
841 | } |
||
842 |
Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.
The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.
This check looks for comments that seem to be mostly valid code and reports them.