/**
* Identify images in post content, and if images are local (uploaded to the current site), pass through Photon.
*
* @param string $content
* @uses self::validate_image_url, apply_filters, jetpack_photon_url, esc_url
* @filter the_content
* @return string
*/
public static function filter_the_content($content)
{
$images = Jetpack_Photon::parse_images_from_html($content);
if (!empty($images)) {
$content_width = Jetpack::get_content_width();
$image_sizes = self::image_sizes();
$upload_dir = wp_upload_dir();
foreach ($images[0] as $index => $tag) {
// Default to resize, though fit may be used in certain cases where a dimension cannot be ascertained
$transform = 'resize';
// Start with a clean attachment ID each time
$attachment_id = false;
// Flag if we need to munge a fullsize URL
$fullsize_url = false;
// Identify image source
$src = $src_orig = $images['img_url'][$index];
/**
* Allow specific images to be skipped by Photon.
*
* @module photon
*
* @since 2.0.3
*
* @param bool false Should Photon ignore this image. Default to false.
* @param string $src Image URL.
* @param string $tag Image Tag (Image HTML output).
*/
if (apply_filters('jetpack_photon_skip_image', false, $src, $tag)) {
continue;
}
// Support Automattic's Lazy Load plugin
// Can't modify $tag yet as we need unadulterated version later
if (preg_match('#data-lazy-src=["|\'](.+?)["|\']#i', $images['img_tag'][$index], $lazy_load_src)) {
$placeholder_src = $placeholder_src_orig = $src;
$src = $src_orig = $lazy_load_src[1];
} elseif (preg_match('#data-lazy-original=["|\'](.+?)["|\']#i', $images['img_tag'][$index], $lazy_load_src)) {
$placeholder_src = $placeholder_src_orig = $src;
$src = $src_orig = $lazy_load_src[1];
}
// Check if image URL should be used with Photon
if (self::validate_image_url($src)) {
// Find the width and height attributes
$width = $height = false;
// First, check the image tag
if (preg_match('#width=["|\']?([\\d%]+)["|\']?#i', $images['img_tag'][$index], $width_string)) {
$width = $width_string[1];
}
if (preg_match('#height=["|\']?([\\d%]+)["|\']?#i', $images['img_tag'][$index], $height_string)) {
$height = $height_string[1];
}
// Can't pass both a relative width and height, so unset the height in favor of not breaking the horizontal layout.
if (false !== strpos($width, '%') && false !== strpos($height, '%')) {
$width = $height = false;
}
// Detect WP registered image size from HTML class
if (preg_match('#class=["|\']?[^"\']*size-([^"\'\\s]+)[^"\']*["|\']?#i', $images['img_tag'][$index], $size)) {
$size = array_pop($size);
if (false === $width && false === $height && 'full' != $size && array_key_exists($size, $image_sizes)) {
$width = (int) $image_sizes[$size]['width'];
$height = (int) $image_sizes[$size]['height'];
$transform = $image_sizes[$size]['crop'] ? 'resize' : 'fit';
}
} else {
unset($size);
}
// WP Attachment ID, if uploaded to this site
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')))) {
$attachment_id = intval(array_pop($attachment_id));
if ($attachment_id) {
$attachment = get_post($attachment_id);
// Basic check on returned post object
if (is_object($attachment) && !is_wp_error($attachment) && 'attachment' == $attachment->post_type) {
$src_per_wp = wp_get_attachment_image_src($attachment_id, isset($size) ? $size : 'full');
if (self::validate_image_url($src_per_wp[0])) {
$src = $src_per_wp[0];
$fullsize_url = true;
// Prevent image distortion if a detected dimension exceeds the image's natural dimensions
if (false !== $width && $width > $src_per_wp[1] || false !== $height && $height > $src_per_wp[2]) {
$width = false == $width ? false : min($width, $src_per_wp[1]);
$height = false == $height ? false : min($height, $src_per_wp[2]);
}
// If no width and height are found, max out at source image's natural dimensions
// Otherwise, respect registered image sizes' cropping setting
if (false == $width && false == $height) {
$width = $src_per_wp[1];
$height = $src_per_wp[2];
$transform = 'fit';
} elseif (isset($size) && array_key_exists($size, $image_sizes) && isset($image_sizes[$size]['crop'])) {
$transform = (bool) $image_sizes[$size]['crop'] ? 'resize' : 'fit';
}
}
} else {
unset($attachment_id);
unset($attachment);
}
}
}
// If image tag lacks width and height arguments, try to determine from strings WP appends to resized image filenames.
if (false === $width && false === $height) {
list($width, $height) = Jetpack_Photon::parse_dimensions_from_filename($src);
}
// If width is available, constrain to $content_width
if (false !== $width && false === strpos($width, '%') && is_numeric($content_width)) {
if ($width > $content_width && false !== $height && false === strpos($height, '%')) {
$height = round($content_width * $height / $width);
$width = $content_width;
} elseif ($width > $content_width) {
$width = $content_width;
}
}
// Set a width if none is found and $content_width is available
// If width is set in this manner and height is available, use `fit` instead of `resize` to prevent skewing
if (false === $width && is_numeric($content_width)) {
$width = (int) $content_width;
if (false !== $height) {
$transform = 'fit';
}
}
// Detect if image source is for a custom-cropped thumbnail and prevent further URL manipulation.
if (!$fullsize_url && preg_match_all('#-e[a-z0-9]+(-\\d+x\\d+)?\\.(' . implode('|', self::$extensions) . '){1}$#i', basename($src), $filename)) {
$fullsize_url = true;
}
// Build URL, first maybe removing WP's resized string so we pass the original image to Photon
if (!$fullsize_url) {
$src = self::strip_image_dimensions_maybe($src);
}
// Build array of Photon args and expose to filter before passing to Photon URL function
$args = array();
if (false !== $width && false !== $height && false === strpos($width, '%') && false === strpos($height, '%')) {
$args[$transform] = $width . ',' . $height;
} elseif (false !== $width) {
$args['w'] = $width;
} elseif (false !== $height) {
$args['h'] = $height;
}
/**
* Filter the array of Photon arguments added to an image when it goes through Photon.
* By default, only includes width and height values.
* @see https://developer.wordpress.com/docs/photon/api/
*
* @module photon
*
* @since 2.0.0
*
* @param array $args Array of Photon Arguments.
* @param array $args {
* Array of image details.
*
* @type $tag Image tag (Image HTML output).
* @type $src Image URL.
* @type $src_orig Original Image URL.
* @type $width Image width.
* @type $height Image height.
* }
*/
$args = apply_filters('jetpack_photon_post_image_args', $args, compact('tag', 'src', 'src_orig', 'width', 'height'));
$photon_url = jetpack_photon_url($src, $args);
// Modify image tag if Photon function provides a URL
// 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.
if ($src != $photon_url) {
$new_tag = $tag;
// If present, replace the link href with a Photoned URL for the full-size image.
if (!empty($images['link_url'][$index]) && self::validate_image_url($images['link_url'][$index])) {
$new_tag = preg_replace('#(href=["|\'])' . $images['link_url'][$index] . '(["|\'])#i', '\\1' . jetpack_photon_url($images['link_url'][$index]) . '\\2', $new_tag, 1);
}
// Supplant the original source value with our Photon URL
$photon_url = esc_url($photon_url);
$new_tag = str_replace($src_orig, $photon_url, $new_tag);
// If Lazy Load is in use, pass placeholder image through Photon
if (isset($placeholder_src) && self::validate_image_url($placeholder_src)) {
$placeholder_src = jetpack_photon_url($placeholder_src);
if ($placeholder_src != $placeholder_src_orig) {
$new_tag = str_replace($placeholder_src_orig, esc_url($placeholder_src), $new_tag);
}
unset($placeholder_src);
}
// Remove the width and height arguments from the tag to prevent distortion
$new_tag = preg_replace('#(?<=\\s)(width|height)=["|\']?[\\d%]+["|\']?\\s?#i', '', $new_tag);
// Tag an image for dimension checking
$new_tag = preg_replace('#(\\s?/)?>(\\s*</a>)?$#i', ' data-recalc-dims="1"\\1>\\2', $new_tag);
// Replace original tag with modified version
$content = str_replace($tag, $new_tag, $content);
}
} elseif (preg_match('#^http(s)?://i[\\d]{1}.wp.com#', $src) && !empty($images['link_url'][$index]) && self::validate_image_url($images['link_url'][$index])) {
$new_tag = preg_replace('#(href=["|\'])' . $images['link_url'][$index] . '(["|\'])#i', '\\1' . jetpack_photon_url($images['link_url'][$index]) . '\\2', $tag, 1);
$content = str_replace($tag, $new_tag, $content);
}
}
}
return $content;
}