PluginProbe ʕ •ᴥ•ʔ
Jetpack – WP Security, Backup, Speed, & Growth / 2.3.10
Jetpack – WP Security, Backup, Speed, & Growth v2.3.10
15.9-a.7 15.9-a.5 15.9-a.3 15.9-a.1 15.8 15.8-beta 15.8-a.7 15.8-a.5 5.2.5 5.3.4 5.4.4 5.5.5 5.6.5 5.7.5 5.8.4 5.9.4 6.0.4 6.1 6.1.1 6.1.2 6.1.3 6.1.4 6.1.5 6.2 6.2.1 6.2.2 6.2.3 6.2.4 6.2.5 6.3 6.3.1 6.3.2 6.3.3 6.3.4 6.3.5 6.3.6 6.3.7 6.4 6.4.1 6.4.2 6.4.3 6.4.4 6.4.5 6.4.6 6.5 6.5.1 6.5.2 6.5.3 6.5.4 6.6 6.6.1 6.6.2 6.6.3 6.6.4 6.6.5 6.7 6.7.1 6.7.2 6.7.3 6.7.4 6.8 6.8.1 6.8.2 6.8.3 6.8.4 6.8.5 6.9 6.9.1 6.9.2 6.9.3 6.9.4 7.0 7.0.1 7.0.2 7.0.3 7.0.4 7.0.5 7.1 7.1.1 7.1.2 7.1.3 7.1.4 7.1.5 7.2 7.2.1 7.2.1.1 7.2.2 7.2.3 7.2.4 7.2.5 7.3 7.3.0.1 7.3.1 7.3.1.1 7.3.2 7.3.3 7.3.4 7.3.5 7.4 7.4.1 7.4.2 7.4.3 7.4.4 7.4.5 7.5 7.5.0.1 7.5.1 7.5.2 7.5.3 7.5.4 7.5.5 7.5.6 7.5.7 7.6 7.6.1 7.6.2 7.6.3 7.6.4 7.7 7.7.1 7.7.2 7.7.3 7.7.4 7.7.5 7.7.6 7.8 7.8.1 7.8.2 7.8.3 7.8.4 7.9 7.9.1 7.9.2 7.9.3 7.9.4 8.0 8.0.1 8.0.2 8.0.3 8.1 8.1.1 8.1.2 8.1.3 8.1.4 8.2 8.2.0.1 8.2.1 8.2.2 8.2.3 8.2.4 8.2.5 8.2.6 8.3 8.3.1 8.3.2 8.3.3 8.4 8.4.1 8.4.2 8.4.3 8.4.4 8.4.5 8.5 8.5.1 8.5.2 8.5.3 8.6 8.6.1 8.6.2 8.6.3 8.6.4 8.7 8.7.0.1 8.7.1 8.7.2 8.7.3 8.7.4 8.8 8.8.1 8.8.2 8.8.3 8.8.4 8.8.5 8.9 8.9.1 8.9.2 8.9.3 8.9.4 9.0 9.0.1 9.0.2 9.0.3 9.0.4 9.0.5 9.1 9.1.1 9.1.2 9.1.3 9.2 9.2.1 9.2.2 9.2.3 9.2.4 9.3 9.3.1 9.3.2 9.3.3 9.3.4 9.3.5 9.4 9.4.1 9.4.2 9.4.3 9.4.4 9.5 9.5.1 9.5.2 9.5.3 9.5.4 9.5.5 9.6 9.6.1 9.6.2 9.6.3 9.6.4 9.7 9.7.1 9.7.2 15.7-beta.2 9.7.3 15.7.1 9.8 15.8-a.1 9.8.1 15.8-a.3 9.8.2 2.0.9 9.8.3 2.1.7 9.9 2.2.10 9.9.1 2.3.10 9.9.2 2.4.7 9.9.3 2.5.5 2.6.6 2.7.5 2.8.5 2.9.6 3.0.6 3.1.5 3.2.5 3.3.6 3.4.6 3.5.6 3.6.4 3.7.5 3.8.5 3.9.10 4.0.7 4.1.4 4.2.5 4.3.5 4.4.5 4.5.3 4.6.3 4.7.4 4.8.5 4.9.3 5.0.3 5.1.4 trunk 10.0 10.0.1 10.0.2 10.1 10.1.1 10.1.2 10.2 10.2.1 10.2.2 10.2.3 10.3 10.3.1 10.3.2 10.4 10.4.1 10.4.2 10.5 10.5.1 10.5.2 10.5.3 10.6 10.6.1 10.6.2 10.7 10.7.1 10.7.2 10.8 10.8.1 10.8.2 10.9 10.9.1 10.9.2 10.9.3 11.0 11.0.1 11.0.2 11.1 11.1.1 11.1.2 11.1.3 11.1.4 11.2 11.2.1 11.2.2 11.3 11.3.1 11.3.2 11.3.3 11.3.4 11.4 11.4.1 11.4.2 11.5 11.5.1 11.5.2 11.5.3 11.6 11.6.1 11.6.2 11.7 11.7.1 11.7.2 11.7.3 11.8 11.8.3 11.8.4 11.8.5 11.8.6 11.9 11.9.1 11.9.2 11.9.3 12.0 12.0.1 12.0.2 12.1 12.1.1 12.1.2 12.2 12.2.1 12.2.2 12.3 12.3.1 12.4 12.4.1 12.5 12.5.1 12.6 12.6.1 12.6.2 12.6.3 12.7 12.7.1 12.7.2 12.8 12.8.1 12.8.2 12.9 12.9.1 12.9.2 12.9.3 12.9.4 13.0 13.0.1 13.1 13.1.1 13.1.2 13.1.3 13.1.4 13.2 13.2.1 13.2.2 13.2.3 13.3 13.3.1 13.3.2 13.4 13.4.1 13.4.2 13.4.3 13.4.4 13.5 13.5.1 13.6 13.6.1 13.7 13.7.1 13.8 13.8.1 13.8.2 13.9 13.9.1 14.0 14.1 14.2 14.2.1 14.3 14.4 14.4.1 14.5 14.6 14.7 14.8 14.9 14.9.1 15.0 15.0.1 15.0.2 15.1 15.1.1 15.2 15.3 15.3.1 15.4 15.5 15.6 15.7 15.7-a.1 15.7-a.3 15.7-a.5 15.7-a.7 15.7-beta
jetpack / class.photon.php
jetpack Last commit date
_inc 10 years ago languages 10 years ago modules 5 years ago class.jetpack-bbpress-json-api-compat.php 10 years ago class.jetpack-client-server.php 10 years ago class.jetpack-client.php 10 years ago class.jetpack-data.php 10 years ago class.jetpack-debugger.php 10 years ago class.jetpack-error.php 10 years ago class.jetpack-heartbeat.php 10 years ago class.jetpack-ixr-client.php 10 years ago class.jetpack-options.php 10 years ago class.jetpack-post-images.php 10 years ago class.jetpack-signature.php 10 years ago class.jetpack-sync.php 10 years ago class.jetpack-user-agent.php 10 years ago class.jetpack-xmlrpc-server.php 10 years ago class.jetpack.php 10 years ago class.json-api-endpoints.php 3 years ago class.json-api.php 10 years ago class.photon.php 10 years ago functions.compat.php 10 years ago functions.gallery.php 10 years ago functions.opengraph.php 10 years ago functions.photon.php 10 years ago jetpack.php 3 years ago locales.php 10 years ago readme.txt 3 years ago uninstall.php 10 years ago
class.photon.php
560 lines
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_gallery', array( __CLASS__, 'filter_the_content' ), 999999 );
57
58 // Core image retrieval
59 add_filter( 'image_downsize', array( $this, 'filter_image_downsize' ), 10, 3 );
60
61 // og:image URL
62 add_filter( 'jetpack_open_graph_tags', array( $this, 'filter_open_graph_tags' ), 10, 2 );
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 // Allow specific images to be skipped
158 if ( apply_filters( 'jetpack_photon_skip_image', false, $src, $tag ) )
159 continue;
160
161 // Support Automattic's Lazy Load plugin
162 // Can't modify $tag yet as we need unadulterated version later
163 if ( preg_match( '#data-lazy-src=["|\'](.+?)["|\']#i', $images['img_tag'][ $index ], $lazy_load_src ) ) {
164 $placeholder_src = $placeholder_src_orig = $src;
165 $src = $src_orig = $lazy_load_src[1];
166 }
167
168 // Check if image URL should be used with Photon
169 if ( self::validate_image_url( $src ) ) {
170 // Find the width and height attributes
171 $width = $height = false;
172
173 // First, check the image tag
174 if ( preg_match( '#width=["|\']?([\d%]+)["|\']?#i', $images['img_tag'][ $index ], $width_string ) )
175 $width = $width_string[1];
176
177 if ( preg_match( '#height=["|\']?([\d%]+)["|\']?#i', $images['img_tag'][ $index ], $height_string ) )
178 $height = $height_string[1];
179
180 // Can't pass both a relative width and height, so unset the height in favor of not breaking the horizontal layout.
181 if ( false !== strpos( $width, '%' ) && false !== strpos( $height, '%' ) )
182 $width = $height = false;
183
184 // Detect WP registered image size from HTML class
185 if ( preg_match( '#class=["|\']?[^"\']*size-([^"\'\s]+)[^"\']*["|\']?#i', $images['img_tag'][ $index ], $size ) ) {
186 $size = array_pop( $size );
187
188 if ( false === $width && false === $height && 'full' != $size && array_key_exists( $size, $image_sizes ) ) {
189 $width = (int) $image_sizes[ $size ]['width'];
190 $height = (int) $image_sizes[ $size ]['height'];
191 $transform = $image_sizes[ $size ]['crop'] ? 'resize' : 'fit';
192 }
193 } else {
194 unset( $size );
195 }
196
197 // WP Attachment ID, if uploaded to this site
198 if ( preg_match( '#class=["|\']?[^"\']*wp-image-([\d]+)[^"\']*["|\']?#i', $images['img_tag'][ $index ], $attachment_id ) && ( 0 === strpos( $src, $upload_dir['baseurl'] ) || apply_filters( 'jetpack_photon_image_is_local', false, compact( 'src', 'tag', 'images', 'index' ) ) ) ) {
199 $attachment_id = intval( array_pop( $attachment_id ) );
200
201 if ( $attachment_id ) {
202 $attachment = get_post( $attachment_id );
203
204 // Basic check on returned post object
205 if ( is_object( $attachment ) && ! is_wp_error( $attachment ) && 'attachment' == $attachment->post_type ) {
206 $src_per_wp = wp_get_attachment_image_src( $attachment_id, isset( $size ) ? $size : 'full' );
207
208 if ( self::validate_image_url( $src_per_wp[0] ) ) {
209 $src = $src_per_wp[0];
210 $fullsize_url = true;
211
212 // Prevent image distortion if a detected dimension exceeds the image's natural dimensions
213 if ( ( false !== $width && $width > $src_per_wp[1] ) || ( false !== $height && $height > $src_per_wp[2] ) ) {
214 $width = false == $width ? false : min( $width, $src_per_wp[1] );
215 $height = false == $height ? false : min( $height, $src_per_wp[2] );
216 }
217
218 // If no width and height are found, max out at source image's natural dimensions
219 // Otherwise, respect registered image sizes' cropping setting
220 if ( false == $width && false == $height ) {
221 $width = $src_per_wp[1];
222 $height = $src_per_wp[2];
223 $transform = 'fit';
224 } elseif ( isset( $size ) && array_key_exists( $size, $image_sizes ) && isset( $image_sizes[ $size ]['crop'] ) ) {
225 $transform = (bool) $image_sizes[ $size ]['crop'] ? 'resize' : 'fit';
226 }
227 }
228 } else {
229 unset( $attachment_id );
230 unset( $attachment );
231 }
232 }
233 }
234
235 // If image tag lacks width and height arguments, try to determine from strings WP appends to resized image filenames.
236 if ( false === $width && false === $height ) {
237 list( $width, $height ) = Jetpack_Photon::parse_dimensions_from_filename( $src );
238 }
239
240 // If width is available, constrain to $content_width
241 if ( false !== $width && false === strpos( $width, '%' ) && is_numeric( $content_width ) ) {
242 if ( $width > $content_width && false !== $height && false === strpos( $height, '%' ) ) {
243 $height = round( ( $content_width * $height ) / $width );
244 $width = $content_width;
245 } elseif ( $width > $content_width ) {
246 $width = $content_width;
247 }
248 }
249
250 // Set a width if none is found and $content_width is available
251 // If width is set in this manner and height is available, use `fit` instead of `resize` to prevent skewing
252 if ( false === $width && is_numeric( $content_width ) ) {
253 $width = (int) $content_width;
254
255 if ( false !== $height )
256 $transform = 'fit';
257 }
258
259 // Detect if image source is for a custom-cropped thumbnail and prevent further URL manipulation.
260 if ( ! $fullsize_url && preg_match_all( '#-e[a-z0-9]+(-\d+x\d+)?\.(' . implode('|', self::$extensions ) . '){1}$#i', basename( $src ), $filename ) )
261 $fullsize_url = true;
262
263 // Build URL, first removing WP's resized string so we pass the original image to Photon
264 if ( ! $fullsize_url && preg_match( '#(-\d+x\d+)\.(' . implode('|', self::$extensions ) . '){1}$#i', $src, $src_parts ) )
265 $src = str_replace( $src_parts[1], '', $src );
266
267 // Build array of Photon args and expose to filter before passing to Photon URL function
268 $args = array();
269
270 if ( false !== $width && false !== $height && false === strpos( $width, '%' ) && false === strpos( $height, '%' ) )
271 $args[ $transform ] = $width . ',' . $height;
272 elseif ( false !== $width )
273 $args['w'] = $width;
274 elseif ( false !== $height )
275 $args['h'] = $height;
276
277 $args = apply_filters( 'jetpack_photon_post_image_args', $args, compact( 'tag', 'src', 'src_orig', 'width', 'height' ) );
278
279 $photon_url = jetpack_photon_url( $src, $args );
280
281 // Modify image tag if Photon function provides a URL
282 // 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.
283 if ( $src != $photon_url ) {
284 $new_tag = $tag;
285
286 // If present, replace the link href with a Photoned URL for the full-size image.
287 if ( ! empty( $images['link_url'][ $index ] ) && self::validate_image_url( $images['link_url'][ $index ] ) )
288 $new_tag = preg_replace( '#(href=["|\'])' . $images['link_url'][ $index ] . '(["|\'])#i', '\1' . jetpack_photon_url( $images['link_url'][ $index ] ) . '\2', $new_tag, 1 );
289
290 // Supplant the original source value with our Photon URL
291 $photon_url = esc_url( $photon_url );
292 $new_tag = str_replace( $src_orig, $photon_url, $new_tag );
293
294 // If Lazy Load is in use, pass placeholder image through Photon
295 if ( isset( $placeholder_src ) && self::validate_image_url( $placeholder_src ) ) {
296 $placeholder_src = jetpack_photon_url( $placeholder_src );
297
298 if ( $placeholder_src != $placeholder_src_orig )
299 $new_tag = str_replace( $placeholder_src_orig, esc_url( $placeholder_src ), $new_tag );
300
301 unset( $placeholder_src );
302 }
303
304 // Remove the width and height arguments from the tag to prevent distortion
305 $new_tag = preg_replace( '#(width|height)=["|\']?[\d%]+["|\']?\s?#i', '', $new_tag );
306
307 // Tag an image for dimension checking
308 $new_tag = preg_replace( '#(\s?/)?>(</a>)?$#i', ' data-recalc-dims="1"\1>\2', $new_tag );
309
310 // Replace original tag with modified version
311 $content = str_replace( $tag, $new_tag, $content );
312 }
313 } elseif ( preg_match( '#^http(s)?://i[\d]{1}.wp.com#', $src ) && ! empty( $images['link_url'][ $index ] ) && self::validate_image_url( $images['link_url'][ $index ] ) ) {
314 $new_tag = preg_replace( '#(href=["|\'])' . $images['link_url'][ $index ] . '(["|\'])#i', '\1' . jetpack_photon_url( $images['link_url'][ $index ] ) . '\2', $tag, 1 );
315
316 $content = str_replace( $tag, $new_tag, $content );
317 }
318 }
319 }
320
321 return $content;
322 }
323
324 /**
325 ** CORE IMAGE RETRIEVAL
326 **/
327
328 /**
329 * Filter post thumbnail image retrieval, passing images through Photon
330 *
331 * @param string|bool $image
332 * @param int $attachment_id
333 * @param string|array $size
334 * @uses is_admin, apply_filters, wp_get_attachment_url, self::validate_image_url, this::image_sizes, jetpack_photon_url
335 * @filter image_downsize
336 * @return string|bool
337 */
338 public function filter_image_downsize( $image, $attachment_id, $size ) {
339 // Don't foul up the admin side of things, and provide plugins a way of preventing Photon from being applied to images.
340 if ( is_admin() || apply_filters( 'jetpack_photon_override_image_downsize', false, compact( 'image', 'attachment_id', 'size' ) ) )
341 return $image;
342
343 // Get the image URL and proceed with Photon-ification if successful
344 $image_url = wp_get_attachment_url( $attachment_id );
345
346 if ( $image_url ) {
347 // Check if image URL should be used with Photon
348 if ( ! self::validate_image_url( $image_url ) )
349 return $image;
350
351 // If an image is requested with a size known to WordPress, use that size's settings with Photon
352 if ( ( is_string( $size ) || is_int( $size ) ) && array_key_exists( $size, self::image_sizes() ) ) {
353 $image_args = self::image_sizes();
354 $image_args = $image_args[ $size ];
355
356 $photon_args = array();
357
358 // `full` is a special case in WP
359 // To ensure filter receives consistent data regardless of requested size, `$image_args` is overridden with dimensions of original image.
360 if ( 'full' == $size ) {
361 $image_meta = wp_get_attachment_metadata( $attachment_id );
362
363 // 'crop' is true so Photon's `resize` method is used
364 $image_args = array(
365 'width' => $image_meta['width'],
366 'height' => $image_meta['height'],
367 'crop' => true
368 );
369 }
370
371 // Expose determined arguments to a filter before passing to Photon
372 $transform = $image_args['crop'] ? 'resize' : 'fit';
373
374 // Check specified image dimensions and account for possible zero values; photon fails to resize if a dimension is zero.
375 if ( 0 == $image_args['width'] || 0 == $image_args['height'] ) {
376 if ( 0 == $image_args['width'] && 0 < $image_args['height'] )
377 $photon_args['h'] = $image_args['height'];
378 elseif ( 0 == $image_args['height'] && 0 < $image_args['width'] )
379 $photon_args['w'] = $image_args['width'];
380 } else {
381 $photon_args[ $transform ] = $image_args['width'] . ',' . $image_args['height'];
382 }
383
384 $photon_args = apply_filters( 'jetpack_photon_image_downsize_string', $photon_args, compact( 'image_args', 'image_url', 'attachment_id', 'size', 'transform' ) );
385
386 // Generate Photon URL
387 $image = array(
388 jetpack_photon_url( $image_url, $photon_args ),
389 false,
390 false
391 );
392 } elseif ( is_array( $size ) ) {
393 // Pull width and height values from the provided array, if possible
394 $width = isset( $size[0] ) ? (int) $size[0] : false;
395 $height = isset( $size[1] ) ? (int) $size[1] : false;
396
397 // Don't bother if necessary parameters aren't passed.
398 if ( ! $width || ! $height )
399 return $image;
400
401 // Expose arguments to a filter before passing to Photon
402 $photon_args = array(
403 'fit' => $width . ',' . $height
404 );
405
406 $photon_args = apply_filters( 'jetpack_photon_image_downsize_array', $photon_args, compact( 'width', 'height', 'image_url', 'attachment_id' ) );
407
408 // Generate Photon URL
409 $image = array(
410 jetpack_photon_url( $image_url, $photon_args ),
411 false,
412 false
413 );
414 }
415 }
416
417 return $image;
418 }
419
420 /**
421 ** GENERAL FUNCTIONS
422 **/
423
424 /**
425 * Ensure image URL is valid for Photon.
426 * 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.
427 *
428 * @param string $url
429 * @uses wp_parse_args
430 * @return bool
431 */
432 protected static function validate_image_url( $url ) {
433 $parsed_url = @parse_url( $url );
434
435 if ( ! $parsed_url )
436 return false;
437
438 // Parse URL and ensure needed keys exist, since the array returned by `parse_url` only includes the URL components it finds.
439 $url_info = wp_parse_args( $parsed_url, array(
440 'scheme' => null,
441 'host' => null,
442 'port' => null,
443 'path' => null
444 ) );
445
446 // Bail if scheme isn't http or port is set that isn't port 80
447 if ( 'http' != $url_info['scheme'] || ! in_array( $url_info['port'], array( 80, null ) ) )
448 return false;
449
450 // Bail if no host is found
451 if ( is_null( $url_info['host'] ) )
452 return false;
453
454 // Bail if the image alredy went through Photon
455 if ( preg_match( '#^i[\d]{1}.wp.com$#i', $url_info['host'] ) )
456 return false;
457
458 // Bail if no path is found
459 if ( is_null( $url_info['path'] ) )
460 return false;
461
462 // Ensure image extension is acceptable
463 if ( ! in_array( strtolower( pathinfo( $url_info['path'], PATHINFO_EXTENSION ) ), self::$extensions ) )
464 return false;
465
466 // If we got this far, we should have an acceptable image URL
467 return true;
468 }
469
470 /**
471 * Provide an array of available image sizes and corresponding dimensions.
472 * Similar to get_intermediate_image_sizes() except that it includes image sizes' dimensions, not just their names.
473 *
474 * @global $wp_additional_image_sizes
475 * @uses get_option
476 * @return array
477 */
478 protected static function image_sizes() {
479 if ( null == self::$image_sizes ) {
480 global $_wp_additional_image_sizes;
481
482 // Populate an array matching the data structure of $_wp_additional_image_sizes so we have a consistent structure for image sizes
483 $images = array(
484 'thumb' => array(
485 'width' => intval( get_option( 'thumbnail_size_w' ) ),
486 'height' => intval( get_option( 'thumbnail_size_h' ) ),
487 'crop' => (bool) get_option( 'thumbnail_crop' )
488 ),
489 'medium' => array(
490 'width' => intval( get_option( 'medium_size_w' ) ),
491 'height' => intval( get_option( 'medium_size_h' ) ),
492 'crop' => false
493 ),
494 'large' => array(
495 'width' => intval( get_option( 'large_size_w' ) ),
496 'height' => intval( get_option( 'large_size_h' ) ),
497 'crop' => false
498 ),
499 'full' => array(
500 'width' => null,
501 'height' => null,
502 'crop' => false
503 )
504 );
505
506 // Compatibility mapping as found in wp-includes/media.php
507 $images['thumbnail'] = $images['thumb'];
508
509 // Update class variable, merging in $_wp_additional_image_sizes if any are set
510 if ( is_array( $_wp_additional_image_sizes ) && ! empty( $_wp_additional_image_sizes ) )
511 self::$image_sizes = array_merge( $images, $_wp_additional_image_sizes );
512 else
513 self::$image_sizes = $images;
514 }
515
516 return is_array( self::$image_sizes ) ? self::$image_sizes : array();
517 }
518
519 /**
520 * Pass og:image URLs through Photon
521 *
522 * @param array $tags
523 * @param array $parameters
524 * @uses jetpack_photon_url
525 * @return array
526 */
527 function filter_open_graph_tags( $tags, $parameters ) {
528 if ( empty( $tags['og:image'] ) ) {
529 return $tags;
530 }
531
532 $photon_args = array(
533 'fit' => sprintf( '%d,%d', 2 * $parameters['image_width'], 2 * $parameters['image_height'] ),
534 );
535
536 if ( is_array( $tags['og:image'] ) ) {
537 $images = array();
538 foreach ( $tags['og:image'] as $image ) {
539 $images[] = jetpack_photon_url( $image, $photon_args );
540 }
541 $tags['og:image'] = $images;
542 } else {
543 $tags['og:image'] = jetpack_photon_url( $tags['og:image'], $photon_args );
544 }
545
546 return $tags;
547 }
548
549 /**
550 * Enqueue Photon helper script
551 *
552 * @uses wp_enqueue_script, plugins_url
553 * @action wp_enqueue_script
554 * @return null
555 */
556 public function action_wp_enqueue_scripts() {
557 wp_enqueue_script( 'jetpack-photon', plugins_url( 'modules/photon/photon.js', __FILE__ ), array( 'jquery' ), 20130122, true );
558 }
559 }
560