Skip to content

Commit

Permalink
Merge pull request #206 from ResponsiveImagesCG/filtering-function-up…
Browse files Browse the repository at this point in the history
…dates

Refactor display filtering functions

Now that we're no longer using a preg_replace_callback function in
tevkori_filter_content_images(), it doesn't make as much sense to use
the callback function the way we originally set it up. However, rather
that merging the two function, this turns the callback into a useful
utility function that accepts an img element and returns the HTML
including srcset and sizes attributes if we can.

Additionally, since we only add srcset and sizes when we're able to
parse the attachment id from the markup, we also no longer need to limit
our matches in the content filter by files containing the path to our
uploads folder. This resolves #190.
  • Loading branch information
joemcgill committed Oct 6, 2015
2 parents 3159dc2 + c77b441 commit 3deda6c
Showing 1 changed file with 46 additions and 67 deletions.
113 changes: 46 additions & 67 deletions wp-tevko-responsive-images.php
Original file line number Diff line number Diff line change
Expand Up @@ -301,111 +301,87 @@ function tevkori_get_srcset_string( $id, $size = 'medium' ) {
* @return string Converted content with 'srcset' and 'sizes' added to images.
*/
function tevkori_filter_content_images( $content ) {

// Only match images in our uploads directory.
$uploads_dir = wp_upload_dir();
$path_to_upload_dir = $uploads_dir['baseurl'];

// Pattern for matching all images with a `src` from the uploads directory.
$pattern = '|<img ([^>]+' . preg_quote( $path_to_upload_dir ) . '[^>]+)>|i';
preg_match_all( $pattern, $content, $matches );
if ( ! preg_match_all( '/<img [^>]+ wp-image-([0-9]+)[^>]+>/i', $content, $matches ) ) {
return $content;
}

$images = $matches[0];
$ids = array();

foreach( $images as $image ) {
if ( preg_match( '/wp-image-([0-9]+)/i', $image, $class_id ) ) {
(int) $id = $class_id[1];
if ( $id ) {
$ids[] = $id;
}
}
}
$attachment_ids = array_unique( $matches[1] );

if ( 0 < count( $ids ) ) {
if ( 0 < count( $attachment_ids ) ) {
/*
* Warm object caches for use with wp_get_attachment_metadata.
*
* To avoid making a database call for each image, a single query
* warms the object cache with the meta information for all images.
**/
_prime_post_caches( $ids, false, true );
*/
_prime_post_caches( $attachment_ids, false, true );
}

foreach( $matches[0] as $k => $image ) {
$match = array( $image, $matches[1][$k] );
$needle = $image;
$replacement = _tevkori_filter_content_images_callback( $match );
if ( false === $replacement ) {
continue;
}
$content = str_replace( $image, $replacement, $content );
foreach( $images as $image ) {
$content = str_replace( $image, tevkori_img_add_srcset_and_sizes( $image ), $content );
}

return $content;
}
add_filter( 'the_content', 'tevkori_filter_content_images', 5, 1 );

/**
* Private preg_replace callback used in tevkori_filter_content_images()
* Add srcset and sizes to an 'img' element.
*
* @access private
* @since 2.5.0
* @since 2.6.0
*
* @param string $image An HTML 'img' element to be filtered.
* @return string Converted 'img' element with 'srcset' and 'sizes' added.
*/
function _tevkori_filter_content_images_callback( $image ) {
if ( empty( $image ) ) {
return false;
}

list( $image_html, $atts ) = $image;

// Bail early if a 'srcset' attribute already exists.
if ( false !== strpos( $atts, 'srcset=' ) ) {

function tevkori_img_add_srcset_and_sizes( $image ) {
// Return early if a 'srcset' attribute already exists.
if ( false !== strpos( $image, ' srcset="' ) ) {
/*
* Backward compatibility.
*
* Prior to version 2.5 a 'srcset' and 'data-sizes' attribute
* were added to the image while inserting the image in the content.
* We replace the 'data-sizes' attribute by a 'sizes' attribute.
*/
$image_html = str_replace( ' data-sizes="', ' sizes="', $image_html );
$image = str_replace( ' data-sizes="', ' sizes="', $image );

return $image_html;
return $image;
}

// Grab ID and size info from core classes.
$id = preg_match( '/wp-image-([0-9]+)/i', $atts, $class_id ) ? (int) $class_id[1] : false;
$size = preg_match( '/size-([^\s|"]+)/i', $atts, $class_size ) ? $class_size[1] : false;
$width = preg_match( '/ width="([0-9]+)"/', $atts, $atts_width ) ? (int) $atts_width[1] : false;
$height = preg_match( '/ height="([0-9]+)"/', $atts, $atts_height ) ? (int) $atts_height[1] : false;
// Parse id, size, width, and height from the `img` element.
$id = preg_match( '/wp-image-([0-9]+)/i', $image, $match_id ) ? (int) $match_id[1] : false;
$size = preg_match( '/size-([^\s|"]+)/i', $image, $match_size ) ? $match_size[1] : false;
$width = preg_match( '/ width="([0-9]+)"/', $image, $match_width ) ? (int) $match_width[1] : false;
$height = preg_match( '/ height="([0-9]+)"/', $image, $match_height ) ? (int) $match_height[1] : false;

if ( $id && false === $size ) {
$size = array(
$width,
$height
$height,
);
}

/*
* If attempts to parse the size value failed, attempt to use the image
* metadata to match the 'src' angainst the available sizes for an attachment.
* metadata to match the 'src' against the available sizes for an attachment.
*/
if ( ! $size && ! empty( $id ) && $meta = wp_get_attachment_metadata( $id ) ) {
// Parse the image `src` value from the `img` element.
$src = preg_match( '/src="([^"]+)"/', $image, $match_src ) ? $match_src[1] : false;

preg_match( '/src="([^"]+)"/', $atts, $url );

// Sanity check the 'src' value and bail early it doesn't exist.
if ( ! $url[1] ) {
return $image_html;
// Return early if the `src` value is empty.
if ( ! $src ) {
return $image;
}

$image_filename = basename( $url[1] );

/*
* First, see if the file is the full size image. If not, we loop through
* the intermediate sizes until we find a match.
* the intermediate sizes until we find a file that matches.
*/
$image_filename = wp_basename( $src );

if ( $image_filename === basename( $meta['file'] ) ) {
$size = 'full';
} else {
Expand All @@ -420,23 +396,26 @@ function _tevkori_filter_content_images_callback( $image ) {
}

// If we have an ID and size, try for 'srcset' and 'sizes' and update the markup.
if ( $id && $size && $srcset = tevkori_get_srcset_string( $id, $size ) ) {
if ( $id && $size && $srcset = tevkori_get_srcset( $id, $size ) ) {

// Pass height and width to `tevkori_get_sizes_string()`.
/**
* Pass the 'height' and 'width' to 'tevkori_get_sizes()' to avoid
* recalculating the image size.
*/
$args = array(
'width' => $width,
'height' => $height,
'width' => $width,
);
$sizes = tevkori_get_sizes( $id, $size, $args );

$sizes = tevkori_get_sizes_string( $id, $size, $args );

// Strip trailing slashes and whitespaces from the `$atts` string.
$atts = trim( rtrim( $atts, '/' ) );
// Format the srcset and sizes string and escape attributes.
$srcset_and_sizes = sprintf( ' srcset="%s" sizes="%s"', esc_attr( $srcset ), esc_attr( $sizes) );

$image_html = "<img " . $atts . " " . $srcset . " " . $sizes . " />";
// Add srcset and sizes attributes to the image markup.
$image = preg_replace( '/<img ([^>]+)[\s?][\/?]>/', '<img $1' . $srcset_and_sizes . ' />', $image );
};

return $image_html;
return $image;
}

/**
Expand Down

0 comments on commit 3deda6c

Please sign in to comment.