├── .gitignore
├── inc
├── class-my-photon-settings.php
├── class-my-photon.php
└── functions.php
├── my-photon.php
└── readme.txt
/.gitignore:
--------------------------------------------------------------------------------
1 | .idea
--------------------------------------------------------------------------------
/inc/class-my-photon-settings.php:
--------------------------------------------------------------------------------
1 | false,
11 | 'base-url' => '',
12 | );
13 |
14 | const SLUG = 'my-photon';
15 |
16 | protected static $instance;
17 |
18 | public static function instance() {
19 | if ( ! isset( self::$instance ) ) {
20 | self::$instance = new My_Photon_Settings;
21 | self::$instance->setup_actions();
22 | }
23 | return self::$instance;
24 | }
25 |
26 | protected function __construct() {
27 | /** Don't do anything **/
28 | }
29 |
30 | public static function get( $key = null, $default = null ) {
31 | if ( ! isset( self::$options ) ) {
32 | self::$options = get_option( self::SLUG, array() );
33 | self::$options = wp_parse_args( self::$options, self::$defaults );
34 | }
35 |
36 | if ( isset( $key ) ) {
37 | return ! empty( self::$options[ $key ] ) ? self::$options[ $key ] : $default;
38 | } else {
39 | return self::$options;
40 | }
41 | }
42 |
43 | protected function setup_actions() {
44 | add_action( 'admin_init', array( self::$instance, 'action_admin_init' ) );
45 | add_action( 'admin_menu', array( self::$instance, 'action_admin_menu' ) );
46 | }
47 |
48 | public function action_admin_init() {
49 | register_setting( self::SLUG, self::SLUG, array( self::$instance, 'sanitize_options' ) );
50 | add_settings_section( 'general', false, '__return_false', self::SLUG );
51 | add_settings_field( 'active', __( 'Activate My Photon', 'my-photon' ), array( self::$instance, 'field' ), self::SLUG, 'general', array( 'name' => 'active', 'type' => 'checkbox', 'label' => __( 'Active', 'my-photon' ) ) );
52 | add_settings_field( 'base-url', __( 'Base URL', 'my-photon' ), array( self::$instance, 'field' ), self::SLUG, 'general', array( 'name' => 'base-url' ) );
53 | }
54 |
55 | public function action_admin_menu() {
56 | add_options_page( __( 'My Photon Settings', 'my-photon' ), __( 'My Photon Settings', 'my-photon' ), $this->options_capability, self::SLUG, array( self::$instance, 'view_settings_page' ) );
57 | }
58 |
59 | public function field( $args ) {
60 | $args = wp_parse_args( $args, array(
61 | 'name' => '',
62 | 'type' => 'text',
63 | 'label' => null,
64 | ) );
65 | switch ( $args['type'] ) {
66 | case 'checkbox' :
67 | printf(
68 | '',
69 | self::SLUG,
70 | esc_attr( $args['name'] ),
71 | checked( $this->get( $args['name'] ), true, false ),
72 | $args['label']
73 | );
74 | break;
75 |
76 | default :
77 | printf( '', self::SLUG, esc_attr( $args['name'] ), esc_attr( $this->get( $args['name'] ) ) );
78 | break;
79 | }
80 | }
81 |
82 | public function sanitize_options( $in ) {
83 | $in = wp_parse_args( $in, self::$defaults );
84 |
85 | // Validate base-url
86 | $out['active'] = ( '1' == $in['active'] );
87 | $out['base-url'] = esc_url_raw( $in['base-url'] );
88 | return $out;
89 | }
90 |
91 | public function view_settings_page() {
92 | ?>
93 |
94 |
99 |
100 | setup();
33 | }
34 |
35 | return self::$__instance;
36 | }
37 |
38 | /**
39 | * Silence is golden.
40 | */
41 | private function __construct() {}
42 |
43 | /**
44 | * Register actions and filters, but only if basic Photon functions are available.
45 | * The basic functions are found in ./functions.photon.php.
46 | *
47 | * @uses add_action, add_filter
48 | * @return null
49 | */
50 | private function setup() {
51 | if ( ! function_exists( 'my_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 |
62 |
63 | /**
64 | ** IN-CONTENT IMAGE MANIPULATION FUNCTIONS
65 | **/
66 |
67 | /**
68 | * Match all images and any relevant tags in a block of HTML.
69 | *
70 | * @param string $content Some HTML.
71 | * @return array An array of $images matches, where $images[0] is
72 | * an array of full matches, and the link_url, img_tag,
73 | * and img_url keys are arrays of those matches.
74 | */
75 | public static function parse_images_from_html( $content ) {
76 | $images = array();
77 |
78 | if ( preg_match_all( '#(?:]+?href=["|\'](?P[^\s]+?)["|\'][^>]*?>\s*)?(?P
]+?src=["|\'](?P[^\s]+?)["|\'].*?>){1}(?:\s*)?#is', $content, $images ) ) {
79 | foreach ( $images as $key => $unused ) {
80 | // Simplify the output as much as possible, mostly for confirming test results.
81 | if ( is_numeric( $key ) && $key > 0 )
82 | unset( $images[$key] );
83 | }
84 |
85 | return $images;
86 | }
87 |
88 | return array();
89 | }
90 |
91 | /**
92 | * Try to determine height and width from strings WP appends to resized image filenames.
93 | *
94 | * @param string $src The image URL.
95 | * @return array An array consisting of width and height.
96 | */
97 | public static function parse_dimensions_from_filename( $src ) {
98 | $width_height_string = array();
99 |
100 | if ( preg_match( '#-(\d+)x(\d+)\.(?:' . implode('|', self::$extensions ) . '){1}$#i', $src, $width_height_string ) ) {
101 | $width = (int) $width_height_string[1];
102 | $height = (int) $width_height_string[2];
103 |
104 | if ( $width && $height )
105 | return array( $width, $height );
106 | }
107 |
108 | return array( false, false );
109 | }
110 |
111 | /**
112 | * Identify images in post content, and if images are local (uploaded to the current site), pass through Photon.
113 | *
114 | * @param string $content
115 | * @uses self::validate_image_url, apply_filters, my_photon_url, esc_url
116 | * @filter the_content
117 | * @return string
118 | */
119 | public static function filter_the_content( $content ) {
120 |
121 | $images = My_Photon::parse_images_from_html( $content );
122 |
123 | if ( ! empty( $images ) ) {
124 | global $content_width;
125 |
126 | $image_sizes = self::image_sizes();
127 | $upload_dir = wp_upload_dir();
128 |
129 | foreach ( $images[0] as $index => $tag ) {
130 | // Default to resize, though fit may be used in certain cases where a dimension cannot be ascertained
131 | $transform = 'resize';
132 |
133 | // Start with a clean attachment ID each time
134 | $attachment_id = false;
135 |
136 | // Flag if we need to munge a fullsize URL
137 | $fullsize_url = false;
138 |
139 | // Identify image source
140 | $src = $src_orig = $images['img_url'][ $index ];
141 |
142 | // Allow specific images to be skipped
143 | if ( apply_filters( 'my_photon_skip_image', false, $src, $tag ) )
144 | continue;
145 |
146 | // Support Automattic's Lazy Load plugin
147 | // Can't modify $tag yet as we need unadulterated version later
148 | if ( preg_match( '#data-lazy-src=["|\'](.+?)["|\']#i', $images['img_tag'][ $index ], $lazy_load_src ) ) {
149 | $placeholder_src = $placeholder_src_orig = $src;
150 | $src = $src_orig = $lazy_load_src[1];
151 | }
152 |
153 | // Check if image URL should be used with Photon
154 | if ( self::validate_image_url( $src ) ) {
155 | // Find the width and height attributes
156 | $width = $height = false;
157 |
158 | // First, check the image tag
159 | if ( preg_match( '#width=["|\']?([\d%]+)["|\']?#i', $images['img_tag'][ $index ], $width_string ) )
160 | $width = $width_string[1];
161 |
162 | if ( preg_match( '#height=["|\']?([\d%]+)["|\']?#i', $images['img_tag'][ $index ], $height_string ) )
163 | $height = $height_string[1];
164 |
165 | // Can't pass both a relative width and height, so unset the height in favor of not breaking the horizontal layout.
166 | if ( false !== strpos( $width, '%' ) && false !== strpos( $height, '%' ) )
167 | $width = $height = false;
168 |
169 | // Detect WP registered image size from HTML class
170 | if ( preg_match( '#class=["|\']?[^"\']*size-([^"\'\s]+)[^"\']*["|\']?#i', $images['img_tag'][ $index ], $size ) ) {
171 | $size = array_pop( $size );
172 |
173 | if ( false === $width && false === $height && 'full' != $size && array_key_exists( $size, $image_sizes ) ) {
174 | $width = (int) $image_sizes[ $size ]['width'];
175 | $height = (int) $image_sizes[ $size ]['height'];
176 | $transform = $image_sizes[ $size ]['crop'] ? 'resize' : 'fit';
177 | }
178 | } else {
179 | unset( $size );
180 | }
181 |
182 | // WP Attachment ID, if uploaded to this site
183 | if ( preg_match( '#class=["|\']?[^"\']*wp-image-([\d]+)[^"\']*["|\']?#i', $images['img_tag'][ $index ], $attachment_id ) && ( 0 === strpos( $src, $upload_dir['baseurl'] ) || apply_filters( 'my_photon_image_is_local', false, compact( 'src', 'tag', 'images', 'index' ) ) ) ) {
184 | $attachment_id = intval( array_pop( $attachment_id ) );
185 |
186 | if ( $attachment_id ) {
187 | $attachment = get_post( $attachment_id );
188 |
189 | // Basic check on returned post object
190 | if ( is_object( $attachment ) && ! is_wp_error( $attachment ) && 'attachment' == $attachment->post_type ) {
191 | $src_per_wp = wp_get_attachment_image_src( $attachment_id, isset( $size ) ? $size : 'full' );
192 |
193 | if ( self::validate_image_url( $src_per_wp[0] ) ) {
194 | $src = $src_per_wp[0];
195 | $fullsize_url = true;
196 |
197 | // Prevent image distortion if a detected dimension exceeds the image's natural dimensions
198 | if ( ( false !== $width && $width > $src_per_wp[1] ) || ( false !== $height && $height > $src_per_wp[2] ) ) {
199 | $width = false == $width ? false : min( $width, $src_per_wp[1] );
200 | $height = false == $height ? false : min( $height, $src_per_wp[2] );
201 | }
202 |
203 | // If no width and height are found, max out at source image's natural dimensions
204 | // Otherwise, respect registered image sizes' cropping setting
205 | if ( false == $width && false == $height ) {
206 | $width = $src_per_wp[1];
207 | $height = $src_per_wp[2];
208 | $transform = 'fit';
209 | } elseif ( isset( $size ) && array_key_exists( $size, $image_sizes ) && isset( $image_sizes[ $size ]['crop'] ) ) {
210 | $transform = (bool) $image_sizes[ $size ]['crop'] ? 'resize' : 'fit';
211 | }
212 | }
213 | } else {
214 | unset( $attachment_id );
215 | unset( $attachment );
216 | }
217 | }
218 | }
219 |
220 | // If image tag lacks width and height arguments, try to determine from strings WP appends to resized image filenames.
221 | if ( false === $width && false === $height ) {
222 | list( $width, $height ) = My_Photon::parse_dimensions_from_filename( $src );
223 | }
224 |
225 | // If width is available, constrain to $content_width
226 | if ( false !== $width && false === strpos( $width, '%' ) && is_numeric( $content_width ) ) {
227 | if ( $width > $content_width && false !== $height && false === strpos( $height, '%' ) ) {
228 | $height = round( ( $content_width * $height ) / $width );
229 | $width = $content_width;
230 | } elseif ( $width > $content_width ) {
231 | $width = $content_width;
232 | }
233 | }
234 |
235 | // Set a width if none is found and $content_width is available
236 | // If width is set in this manner and height is available, use `fit` instead of `resize` to prevent skewing
237 | if ( false === $width && is_numeric( $content_width ) ) {
238 | $width = (int) $content_width;
239 |
240 | if ( false !== $height )
241 | $transform = 'fit';
242 | }
243 |
244 | // Detect if image source is for a custom-cropped thumbnail and prevent further URL manipulation.
245 | if ( ! $fullsize_url && preg_match_all( '#-e[a-z0-9]+(-\d+x\d+)?\.(' . implode('|', self::$extensions ) . '){1}$#i', basename( $src ), $filename ) )
246 | $fullsize_url = true;
247 |
248 | // Build URL, first maybe removing WP's resized string so we pass the original image to Photon
249 | if ( ! $fullsize_url ) {
250 | $src = self::strip_image_dimensions_maybe( $src );
251 | }
252 |
253 | // Build array of Photon args and expose to filter before passing to Photon URL function
254 | $args = array();
255 |
256 | if ( false !== $width && false !== $height && false === strpos( $width, '%' ) && false === strpos( $height, '%' ) )
257 | $args[ $transform ] = $width . ',' . $height;
258 | elseif ( false !== $width )
259 | $args['w'] = $width;
260 | elseif ( false !== $height )
261 | $args['h'] = $height;
262 |
263 | $args = apply_filters( 'my_photon_post_image_args', $args, compact( 'tag', 'src', 'src_orig', 'width', 'height' ) );
264 |
265 | $photon_url = my_photon_url( $src, $args );
266 |
267 | // Modify image tag if Photon function provides a URL
268 | // 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.
269 | if ( $src != $photon_url ) {
270 | $new_tag = $tag;
271 |
272 | // If present, replace the link href with a Photoned URL for the full-size image.
273 | if ( ! empty( $images['link_url'][ $index ] ) && self::validate_image_url( $images['link_url'][ $index ] ) )
274 | $new_tag = preg_replace( '#(href=["|\'])' . $images['link_url'][ $index ] . '(["|\'])#i', '\1' . my_photon_url( $images['link_url'][ $index ] ) . '\2', $new_tag, 1 );
275 |
276 | // Supplant the original source value with our Photon URL
277 | $photon_url = esc_url( $photon_url );
278 | $new_tag = str_replace( $src_orig, $photon_url, $new_tag );
279 |
280 | // If Lazy Load is in use, pass placeholder image through Photon
281 | if ( isset( $placeholder_src ) && self::validate_image_url( $placeholder_src ) ) {
282 | $placeholder_src = my_photon_url( $placeholder_src );
283 |
284 | if ( $placeholder_src != $placeholder_src_orig )
285 | $new_tag = str_replace( $placeholder_src_orig, esc_url( $placeholder_src ), $new_tag );
286 |
287 | unset( $placeholder_src );
288 | }
289 |
290 | // Remove the width and height arguments from the tag to prevent distortion
291 | $new_tag = preg_replace( '#(?<=\s)(width|height)=["|\']?[\d%]+["|\']?\s?#i', '', $new_tag );
292 |
293 | // Tag an image for dimension checking
294 | $new_tag = preg_replace( '#(\s?/)?>()?$#i', ' data-recalc-dims="1"\1>\2', $new_tag );
295 |
296 | // Replace original tag with modified version
297 | $content = str_replace( $tag, $new_tag, $content );
298 | }
299 | } elseif ( false !== strpos( $src, My_Photon_Settings::get( 'base-url' ) ) && ! empty( $images['link_url'][ $index ] ) && self::validate_image_url( $images['link_url'][ $index ] ) ) {
300 | $new_tag = preg_replace( '#(href=["|\'])' . $images['link_url'][ $index ] . '(["|\'])#i', '\1' . my_photon_url( $images['link_url'][ $index ] ) . '\2', $tag, 1 );
301 |
302 | $content = str_replace( $tag, $new_tag, $content );
303 | }
304 | }
305 | }
306 |
307 | return $content;
308 | }
309 |
310 | /**
311 | * Filter Core galleries
312 | *
313 | * @param array $galleries Gallery array.
314 | * @return array
315 | */
316 | public static function filter_the_galleries( $galleries ) {
317 | if ( empty( $galleries ) || ! is_array( $galleries ) ) {
318 | return $galleries;
319 | }
320 |
321 | // Pass by reference, so we can modify them in place.
322 | foreach ( $galleries as &$this_gallery ) {
323 | if ( is_string( $this_gallery ) ) {
324 | $this_gallery = self::filter_the_content( $this_gallery );
325 | }
326 | }
327 | unset( $this_gallery ); // break the reference.
328 |
329 | return $galleries;
330 | }
331 |
332 | /**
333 | ** CORE IMAGE RETRIEVAL
334 | **/
335 |
336 | /**
337 | * Filter post thumbnail image retrieval, passing images through Photon
338 | *
339 | * @param string|bool $image
340 | * @param int $attachment_id
341 | * @param string|array $size
342 | * @uses is_admin, apply_filters, wp_get_attachment_url, self::validate_image_url, this::image_sizes, my_photon_url
343 | * @filter image_downsize
344 | * @return string|bool
345 | */
346 | public function filter_image_downsize( $image, $attachment_id, $size ) {
347 | // Don't foul up the admin side of things, and provide plugins a way of preventing Photon from being applied to images.
348 | if ( is_admin() || apply_filters( 'my_photon_override_image_downsize', false, compact( 'image', 'attachment_id', 'size' ) ) )
349 | return $image;
350 |
351 | // Get the image URL and proceed with Photon-ification if successful
352 | $image_url = wp_get_attachment_url( $attachment_id );
353 |
354 | if ( $image_url ) {
355 | // Check if image URL should be used with Photon
356 | if ( ! self::validate_image_url( $image_url ) )
357 | return $image;
358 |
359 | // If an image is requested with a size known to WordPress, use that size's settings with Photon
360 | if ( ( is_string( $size ) || is_int( $size ) ) && array_key_exists( $size, self::image_sizes() ) ) {
361 | $image_args = self::image_sizes();
362 | $image_args = $image_args[ $size ];
363 |
364 | $photon_args = array();
365 |
366 | // `full` is a special case in WP
367 | // To ensure filter receives consistent data regardless of requested size, `$image_args` is overridden with dimensions of original image.
368 | if ( 'full' == $size ) {
369 | $image_meta = wp_get_attachment_metadata( $attachment_id );
370 | if ( isset( $image_meta['width'], $image_meta['height'] ) ) {
371 | // 'crop' is true so Photon's `resize` method is used
372 | $image_args = array(
373 | 'width' => $image_meta['width'],
374 | 'height' => $image_meta['height'],
375 | 'crop' => true
376 | );
377 | }
378 | }
379 |
380 | // Expose determined arguments to a filter before passing to Photon.
381 | $transform = $image_args['crop'] ? 'resize' : 'fit';
382 |
383 | // Check specified image dimensions and account for possible zero values; photon fails to resize if a dimension is zero.
384 | if ( 0 === $image_args['width'] || 0 === $image_args['height'] ) {
385 | if ( 0 === $image_args['width'] && 0 < $image_args['height'] ) {
386 | $photon_args['h'] = $image_args['height'];
387 | } elseif ( 0 === $image_args['height'] && 0 < $image_args['width'] ) {
388 | $photon_args['w'] = $image_args['width'];
389 | }
390 | } else {
391 | $image_meta = wp_get_attachment_metadata( $attachment_id );
392 | if ( ( 'resize' === $transform ) && $image_meta ) {
393 | if ( isset( $image_meta['width'], $image_meta['height'] ) ) {
394 | // Lets make sure that we don't upscale images since wp never upscales them as well.
395 | $smaller_width = ( ( $image_meta['width'] < $image_args['width'] ) ? $image_meta['width'] : $image_args['width'] );
396 | $smaller_height = ( ( $image_meta['height'] < $image_args['height'] ) ? $image_meta['height'] : $image_args['height'] );
397 |
398 | $photon_args[ $transform ] = $smaller_width . ',' . $smaller_height;
399 | }
400 | } else {
401 | $photon_args[ $transform ] = $image_args['width'] . ',' . $image_args['height'];
402 | }
403 | }
404 |
405 | $photon_args = apply_filters( 'my_photon_image_downsize_string', $photon_args, compact( 'image_args', 'image_url', 'attachment_id', 'size', 'transform' ) );
406 |
407 | // Generate Photon URL
408 | $image = array(
409 | my_photon_url( $image_url, $photon_args ),
410 | false,
411 | false
412 | );
413 | } elseif ( is_array( $size ) ) {
414 | // Pull width and height values from the provided array, if possible
415 | $width = isset( $size[0] ) ? (int) $size[0] : false;
416 | $height = isset( $size[1] ) ? (int) $size[1] : false;
417 |
418 | // Don't bother if necessary parameters aren't passed.
419 | if ( ! $width || ! $height )
420 | return $image;
421 |
422 | // Expose arguments to a filter before passing to Photon
423 | $photon_args = array(
424 | 'fit' => $width . ',' . $height
425 | );
426 |
427 | $photon_args = apply_filters( 'my_photon_image_downsize_array', $photon_args, compact( 'width', 'height', 'image_url', 'attachment_id' ) );
428 |
429 | // Generate Photon URL
430 | $image = array(
431 | my_photon_url( $image_url, $photon_args ),
432 | false,
433 | false
434 | );
435 | }
436 | }
437 |
438 | return $image;
439 | }
440 |
441 | /**
442 | ** GENERAL FUNCTIONS
443 | **/
444 |
445 | /**
446 | * Ensure image URL is valid for Photon.
447 | * 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.
448 | *
449 | * @param string $url
450 | * @uses wp_parse_args
451 | * @return bool
452 | */
453 | protected static function validate_image_url( $url ) {
454 | $base_url = My_Photon_Settings::get( 'base-url' );
455 | $base_url_parsed = @parse_url( $base_url );
456 | $parsed_url = @parse_url( $url );
457 |
458 | if ( ! $parsed_url ) {
459 | return false;
460 | }
461 |
462 | // Parse URL and ensure needed keys exist, since the array returned by `parse_url` only includes the URL components it finds.
463 | $url_info = wp_parse_args( $parsed_url, array(
464 | 'scheme' => null,
465 | 'host' => null,
466 | 'port' => null,
467 | 'path' => null
468 | ) );
469 |
470 | // Ensure port/protocol matches that of the image server.
471 | if ( $url_info['scheme'] !== $base_url_parsed['scheme']
472 | || ( 'https' === $url_info['scheme']
473 | && apply_filters( 'my_photon_reject_https', false )
474 | )
475 | ) {
476 | return false;
477 | }
478 |
479 | // Bail if no host is found
480 | if ( is_null( $url_info['host'] ) ) {
481 | return false;
482 | }
483 |
484 | // Bail if the image alredy went through Photon
485 | if ( false !== strpos( $base_url, $url_info['host'] ) ) {
486 | return false;
487 | }
488 |
489 | // Bail if no path is found
490 | if ( is_null( $url_info['path'] ) ) {
491 | return false;
492 | }
493 |
494 | // Ensure image extension is acceptable
495 | if ( ! in_array(
496 | strtolower( pathinfo( $url_info['path'], PATHINFO_EXTENSION ) ),
497 | self::$extensions
498 | ) ) {
499 | return false;
500 | }
501 |
502 | /**
503 | * Allow themes and plugins to add additional logic to determine
504 | * whether the URL should be Photonized.
505 | *
506 | * @param bool $is_valid Whether the image URL should be Photonized.
507 | * @param string $url The URL that is being examined.
508 | * @param array $parsed_url The URL as passed through parse_url().
509 | */
510 | return apply_filters(
511 | 'photon_validate_image_url',
512 | true,
513 | $url,
514 | $parsed_url
515 | );
516 | }
517 |
518 | /**
519 | * Checks if the file exists before it passes the file to photon
520 | *
521 | * @param string $src The image URL
522 | * @return string
523 | **/
524 | protected static function strip_image_dimensions_maybe( $src ) {
525 | $stripped_src = $src;
526 |
527 | // Build URL, first removing WP's resized string so we pass the original image to Photon
528 | if ( preg_match( '#(-\d+x\d+)\.(' . implode('|', self::$extensions ) . '){1}$#i', $src, $src_parts ) ) {
529 | $stripped_src = str_replace( $src_parts[1], '', $src );
530 | $upload_dir = wp_upload_dir();
531 |
532 | // Extracts the file path to the image minus the base url
533 | $file_path = substr( $stripped_src, strlen ( $upload_dir['baseurl'] ) );
534 |
535 | if( file_exists( $upload_dir["basedir"] . $file_path ) )
536 | $src = $stripped_src;
537 | }
538 |
539 | return $src;
540 | }
541 |
542 | /**
543 | * Provide an array of available image sizes and corresponding dimensions.
544 | * Similar to get_intermediate_image_sizes() except that it includes image sizes' dimensions, not just their names.
545 | *
546 | * @global $wp_additional_image_sizes
547 | * @uses get_option
548 | * @return array
549 | */
550 | protected static function image_sizes() {
551 | if ( null == self::$image_sizes ) {
552 | global $_wp_additional_image_sizes;
553 |
554 | // Populate an array matching the data structure of $_wp_additional_image_sizes so we have a consistent structure for image sizes
555 | $images = array(
556 | 'thumb' => array(
557 | 'width' => intval( get_option( 'thumbnail_size_w' ) ),
558 | 'height' => intval( get_option( 'thumbnail_size_h' ) ),
559 | 'crop' => (bool) get_option( 'thumbnail_crop' )
560 | ),
561 | 'medium' => array(
562 | 'width' => intval( get_option( 'medium_size_w' ) ),
563 | 'height' => intval( get_option( 'medium_size_h' ) ),
564 | 'crop' => false
565 | ),
566 | 'large' => array(
567 | 'width' => intval( get_option( 'large_size_w' ) ),
568 | 'height' => intval( get_option( 'large_size_h' ) ),
569 | 'crop' => false
570 | ),
571 | 'full' => array(
572 | 'width' => null,
573 | 'height' => null,
574 | 'crop' => false
575 | )
576 | );
577 |
578 | // Compatibility mapping as found in wp-includes/media.php
579 | $images['thumbnail'] = $images['thumb'];
580 |
581 | // Update class variable, merging in $_wp_additional_image_sizes if any are set
582 | if ( is_array( $_wp_additional_image_sizes ) && ! empty( $_wp_additional_image_sizes ) )
583 | self::$image_sizes = array_merge( $images, $_wp_additional_image_sizes );
584 | else
585 | self::$image_sizes = $images;
586 | }
587 |
588 | return is_array( self::$image_sizes ) ? self::$image_sizes : array();
589 | }
590 |
591 | /**
592 | * Pass og:image URLs through Photon
593 | *
594 | * @param array $tags
595 | * @param array $parameters
596 | * @uses my_photon_url
597 | * @return array
598 | */
599 | function filter_open_graph_tags( $tags, $parameters ) {
600 | if ( empty( $tags['og:image'] ) ) {
601 | return $tags;
602 | }
603 |
604 | $photon_args = array(
605 | 'fit' => sprintf( '%d,%d', 2 * $parameters['image_width'], 2 * $parameters['image_height'] ),
606 | );
607 |
608 | if ( is_array( $tags['og:image'] ) ) {
609 | $images = array();
610 | foreach ( $tags['og:image'] as $image ) {
611 | $images[] = my_photon_url( $image, $photon_args );
612 | }
613 | $tags['og:image'] = $images;
614 | } else {
615 | $tags['og:image'] = my_photon_url( $tags['og:image'], $photon_args );
616 | }
617 |
618 | return $tags;
619 | }
620 | }
621 | My_Photon::instance();
622 |
--------------------------------------------------------------------------------
/inc/functions.php:
--------------------------------------------------------------------------------
1 | '300', 'resize' => array( 123, 456 ) ), or in string form (w=123&h=456)
10 | * @return string The raw final URL. You should run this through esc_url() before displaying it.
11 | */
12 | function my_photon_url( $image_url, $args = array(), $scheme = null ) {
13 | $image_url = trim( $image_url );
14 |
15 | $image_url = apply_filters( 'my_photon_pre_image_url', $image_url, $args, $scheme );
16 | $args = apply_filters( 'my_photon_pre_args', $args, $image_url, $scheme );
17 |
18 | if ( empty( $image_url ) )
19 | return $image_url;
20 |
21 | $image_url_parts = @parse_url( $image_url );
22 |
23 | // Unable to parse
24 | if ( ! is_array( $image_url_parts ) || empty( $image_url_parts['host'] ) || empty( $image_url_parts['path'] ) )
25 | return $image_url;
26 |
27 | if ( is_array( $args ) ){
28 | // Convert values that are arrays into strings
29 | foreach ( $args as $arg => $value ) {
30 | if ( is_array( $value ) ) {
31 | $args[$arg] = implode( ',', $value );
32 | }
33 | }
34 |
35 | // Encode values
36 | // See http://core.trac.wordpress.org/ticket/17923
37 | $args = rawurlencode_deep( $args );
38 | }
39 |
40 | // You can't run a Photon URL through Photon again because query strings are stripped.
41 | // So if the image is already a Photon URL, append the new arguments to the existing URL.
42 | if ( false !== strpos( My_Photon_Settings::get( 'base-url' ), $image_url_parts['host'] ) ) {
43 | $photon_url = add_query_arg( $args, $image_url );
44 |
45 | return my_photon_url_scheme( $photon_url, $scheme );
46 | }
47 |
48 | // This setting is Photon Server dependent
49 | if ( ! apply_filters( 'my_photon_any_extension_for_domain', false, $image_url_parts['host'] ) ) {
50 | // Photon doesn't support query strings so we ignore them and look only at the path.
51 | // However some source images are served via PHP so check the no-query-string extension.
52 | // For future proofing, this is a blacklist of common issues rather than a whitelist.
53 | $extension = pathinfo( $image_url_parts['path'], PATHINFO_EXTENSION );
54 | if ( empty( $extension ) || in_array( $extension, array( 'php' ) ) )
55 | return $image_url;
56 | }
57 |
58 | $image_host_path = $image_url_parts['host'] . $image_url_parts['path'];
59 |
60 | $photon_url = My_Photon_Settings::get( 'base-url' ) . $image_host_path;
61 |
62 | // This setting is Photon Server dependent
63 | if ( isset( $image_url_parts['query'] ) && apply_filters( 'my_photon_add_query_string_to_domain', false, $image_url_parts['host'] ) ) {
64 | $photon_url .= '?q=' . rawurlencode( $image_url_parts['query'] );
65 | }
66 |
67 | if ( $args ) {
68 | if ( is_array( $args ) ) {
69 | $photon_url = add_query_arg( $args, $photon_url );
70 | } else {
71 | // You can pass a query string for complicated requests but where you still want CDN subdomain help, etc.
72 | $photon_url .= '?' . $args;
73 | }
74 | }
75 |
76 | return my_photon_url_scheme( $photon_url, $scheme );
77 | }
78 | add_filter( 'my_photon_url', 'my_photon_url', 10, 3 );
79 |
80 |
81 | function my_photon_url_scheme( $url, $scheme ) {
82 | if ( ! in_array( $scheme, array( 'http', 'https', 'network_path' ) ) ) {
83 | $scheme = is_ssl() ? 'https' : 'http';
84 | }
85 |
86 | if ( 'network_path' == $scheme ) {
87 | $scheme_slashes = '//';
88 | } else {
89 | $scheme_slashes = "$scheme://";
90 | }
91 |
92 | return preg_replace( '#^[a-z:]+//#i', $scheme_slashes, $url );
93 | }
94 |
--------------------------------------------------------------------------------
/my-photon.php:
--------------------------------------------------------------------------------
1 | Use of this service is for users of the Jetpack by WordPress.com plugin only,
45 | > and may be used by sites hosted on WordPress.com, or on Jetpack-connected
46 | > WordPress sites. If you move to another platform, or disconnect Jetpack from
47 | > your site, we can't promise it will continue to work.
48 |
49 | == Changelog ==
50 |
51 | = 0.1 =
52 |
53 | * Initial release
--------------------------------------------------------------------------------