From 5bc7cd95f25ed0c01e6d60449731683feb52ffca Mon Sep 17 00:00:00 2001 From: David Newton Date: Mon, 20 Apr 2015 12:44:11 -0400 Subject: [PATCH 01/28] ImageMagick biz --- class-respimg.php | 245 ++++++++++++++++++++++++++++++ class-wp-image-editor-respimg.php | 210 +++++++++++++++++++++++++ wp-tevko-responsive-images.php | 15 ++ 3 files changed, 470 insertions(+) create mode 100644 class-respimg.php create mode 100644 class-wp-image-editor-respimg.php diff --git a/class-respimg.php b/class-respimg.php new file mode 100644 index 0000000..120fc52 --- /dev/null +++ b/class-respimg.php @@ -0,0 +1,245 @@ + + * + * @package wp-respimg + * @version 0.0.1 + */ + + if (class_exists('Imagick')) { + class RespimgImagick extends Imagick { } + } else { + class RespimgImagick { } + } + + + /** + * An Imagick extension to provide better (higher quality, lower file size) image resizes. + * + * This class extends Imagick () based on + * research into optimal image resizing techniques (). + * + * Using these methods with their default settings should provide image resizing that is + * visually indistinguishable from Photoshop’s “Save for Web…”, but at lower file sizes. + * + * @author David Newton + * @copyright 2015 David Newton + * @license https://raw.githubusercontent.com/nwtn/php-respimg/master/LICENSE MIT + * @version 1.0.0 + */ + + class Respimg extends RespimgImagick { + + /** + * Resizes the image using smart defaults for high quality and low file size. + * + * This function is basically equivalent to: + * + * $optim == true: `mogrify -path OUTPUT_PATH -filter Triangle -define filter:support=2.0 -thumbnail OUTPUT_WIDTH -unsharp 0.25x0.08+8.3+0.045 -dither None -posterize 136 -quality 82 -define jpeg:fancy-upsampling=off -define png:compression-filter=5 -define png:compression-level=9 -define png:compression-strategy=1 -define png:exclude-chunk=all -interlace none -colorspace sRGB INPUT_PATH` + * + * $optim == false: `mogrify -path OUTPUT_PATH -filter Triangle -define filter:support=2.0 -thumbnail OUTPUT_WIDTH -unsharp 0.25x0.25+8+0.065 -dither None -posterize 136 -quality 82 -define jpeg:fancy-upsampling=off -define png:compression-filter=5 -define png:compression-level=9 -define png:compression-strategy=1 -define png:exclude-chunk=all -interlace none -colorspace sRGB -strip INPUT_PATH` + * + * @access public + * + * @param integer $columns The number of columns in the output image. 0 = maintain aspect ratio based on $rows. + * @param integer $rows The number of rows in the output image. 0 = maintain aspect ratio based on $columns. + * @param bool $optim Whether you intend to perform optimization on the resulting image. Note that setting this to `true` doesn’t actually perform any optimization. + */ + + public function smartResize($columns, $rows, $optim = false) { + + $this->setOption('filter:support', '2.0'); + $this->thumbnailImage($columns, $rows, false, false, Imagick::FILTER_TRIANGLE); + if ($optim) { + $this->unsharpMaskImage(0.25, 0.08, 8.3, 0.045); + } else { + $this->unsharpMaskImage(0.25, 0.25, 8, 0.065); + } + $this->posterizeImage(136, false); + $this->setImageCompressionQuality(82); + $this->setOption('jpeg:fancy-upsampling', 'off'); + $this->setOption('png:compression-filter', '5'); + $this->setOption('png:compression-level', '9'); + $this->setOption('png:compression-strategy', '1'); + $this->setOption('png:exclude-chunk', 'all'); + $this->setInterlaceScheme(Imagick::INTERLACE_NO); + $this->setColorspace(Imagick::COLORSPACE_SRGB); + if (!$optim) { + $this->stripImage(); + } + + } + + + /** + * Changes the size of an image to the given dimensions and removes any associated profiles. + * + * `thumbnailImage` changes the size of an image to the given dimensions and + * removes any associated profiles. The goal is to produce small low cost + * thumbnail images suited for display on the Web. + * + * With the original Imagick thumbnailImage implementation, there is no way to choose a + * resampling filter. This class recreates Imagick’s C implementation and adds this + * additional feature. + * + * Note: has been filed for this issue. + * + * @access public + * + * @param integer $columns The number of columns in the output image. 0 = maintain aspect ratio based on $rows. + * @param integer $rows The number of rows in the output image. 0 = maintain aspect ratio based on $columns. + * @param bool $bestfit Treat $columns and $rows as a bounding box in which to fit the image. + * @param bool $fill Fill in the bounding box with the background colour. + * @param integer $filter The resampling filter to use. Refer to the list of filter constants at . + * + * @return bool Indicates whether the operation was performed successfully. + */ + + public function thumbnailImage($columns, $rows, $bestfit = false, $fill = false, $filter = Imagick::FILTER_TRIANGLE) { + + // sample factor; defined in original ImageMagick thumbnailImage function + // the scale to which the image should be resized using the `sample` function + $SampleFactor = 5; + + // filter whitelist + $filters = array( + Imagick::FILTER_POINT, + Imagick::FILTER_BOX, + Imagick::FILTER_TRIANGLE, + Imagick::FILTER_HERMITE, + Imagick::FILTER_HANNING, + Imagick::FILTER_HAMMING, + Imagick::FILTER_BLACKMAN, + Imagick::FILTER_GAUSSIAN, + Imagick::FILTER_QUADRATIC, + Imagick::FILTER_CUBIC, + Imagick::FILTER_CATROM, + Imagick::FILTER_MITCHELL, + Imagick::FILTER_LANCZOS, + Imagick::FILTER_BESSEL, + Imagick::FILTER_SINC + ); + + // Parse parameters given to function + $columns = (double) ($columns); + $rows = (double) ($rows); + $bestfit = (bool) $bestfit; + $fill = (bool) $fill; + + // We can’t resize to (0,0) + if ($rows < 1 && $columns < 1) { + return false; + } + + // Set a default filter if an acceptable one wasn’t passed + if (!in_array($filter, $filters)) { + $filter = Imagick::FILTER_TRIANGLE; + } + + // figure out the output width and height + $width = (double) $this->getImageWidth(); + $height = (double) $this->getImageHeight(); + $new_width = $columns; + $new_height = $rows; + + $x_factor = $columns / $width; + $y_factor = $rows / $height; + if ($rows < 1) { + $new_height = round($x_factor * $height); + } elseif ($columns < 1) { + $new_width = round($y_factor * $width); + } + + // if bestfit is true, the new_width/new_height of the image will be different than + // the columns/rows parameters; those will define a bounding box in which the image will be fit + if ($bestfit && $x_factor > $y_factor) { + $x_factor = $y_factor; + $new_width = round($y_factor * $width); + } elseif ($bestfit && $y_factor > $x_factor) { + $y_factor = $x_factor; + $new_height = round($x_factor * $height); + } + if ($new_width < 1) { + $new_width = 1; + } + if ($new_height < 1) { + $new_height = 1; + } + + // if we’re resizing the image to more than about 1/3 it’s original size + // then just use the resize function + if (($x_factor * $y_factor) > 0.1) { + $this->resizeImage($new_width, $new_height, $filter, 1); + + // if we’d be using sample to scale to smaller than 128x128, just use resize + } elseif ((($SampleFactor * $new_width) < 128) || (($SampleFactor * $new_height) < 128)) { + $this->resizeImage($new_width, $new_height, $filter, 1); + + // otherwise, use sample first, then resize + } else { + $this->sampleImage($SampleFactor * $new_width, $SampleFactor * $new_height); + $this->resizeImage($new_width, $new_height, $filter, 1); + } + + // if the alpha channel is not defined, make it opaque + if ($this->getImageAlphaChannel() == Imagick::ALPHACHANNEL_UNDEFINED) { + $this->setImageAlphaChannel(Imagick::ALPHACHANNEL_OPAQUE); + } + + // set the image’s bit depth to 8 bits + $this->setImageDepth(8); + + // turn off interlacing + $this->setInterlaceScheme(Imagick::INTERLACE_NO); + + // Strip all profiles except color profiles. + foreach ($this->getImageProfiles('*', true) as $key => $value) { + if ($key != 'icc' && $key != 'icm') { + $this->removeImageProfile($key); + } + } + + if (method_exists($this, 'deleteImageProperty')) { + $this->deleteImageProperty('comment'); + $this->deleteImageProperty('Thumb::URI'); + $this->deleteImageProperty('Thumb::MTime'); + $this->deleteImageProperty('Thumb::Size'); + $this->deleteImageProperty('Thumb::Mimetype'); + $this->deleteImageProperty('software'); + $this->deleteImageProperty('Thumb::Image::Width'); + $this->deleteImageProperty('Thumb::Image::Height'); + $this->deleteImageProperty('Thumb::Document::Pages'); + } else { + $this->setImageProperty('comment', ''); + $this->setImageProperty('Thumb::URI', ''); + $this->setImageProperty('Thumb::MTime', ''); + $this->setImageProperty('Thumb::Size', ''); + $this->setImageProperty('Thumb::Mimetype', ''); + $this->setImageProperty('software', ''); + $this->setImageProperty('Thumb::Image::Width', ''); + $this->setImageProperty('Thumb::Image::Height', ''); + $this->setImageProperty('Thumb::Document::Pages', ''); + } + + // In case user wants to fill use extent for it rather than creating a new canvas + // …fill out the bounding box + if ($bestfit && $fill && ($new_width != $columns || $new_height != $rows)) { + $extent_x = 0; + $extent_y = 0; + + if ($columns > $new_width) { + $extent_x = ($columns - $new_width) / 2; + } + if ($rows > $new_height) { + $extent_y = ($rows - $new_height) / 2; + } + + $this->extentImage($columns, $rows, 0 - $extent_x, $extent_y); + } + + return true; + + } + + } diff --git a/class-wp-image-editor-respimg.php b/class-wp-image-editor-respimg.php new file mode 100644 index 0000000..e21c487 --- /dev/null +++ b/class-wp-image-editor-respimg.php @@ -0,0 +1,210 @@ +file into new Respimg Object. + * + * @access protected + * + * @return boolean|WP_Error True if loaded; WP_Error on failure. + */ + public function load() { + if ( $this->image instanceof Respimg ) + return true; + + if ( ! is_file( $this->file ) && ! preg_match( '|^https?://|', $this->file ) ) + return new WP_Error( 'error_loading_image', __('File doesn’t exist?'), $this->file ); + + /** This filter is documented in wp-includes/class-wp-image-editor-imagick.php */ + // Even though Imagick uses less PHP memory than GD, set higher limit for users that have low PHP.ini limits + @ini_set( 'memory_limit', apply_filters( 'image_memory_limit', WP_MAX_MEMORY_LIMIT ) ); + + try { + $this->image = new Respimg( $this->file ); + + if( ! $this->image->valid() ) + return new WP_Error( 'invalid_image', __('File is not an image.'), $this->file); + + // Select the first frame to handle animated images properly + if ( is_callable( array( $this->image, 'setIteratorIndex' ) ) ) + $this->image->setIteratorIndex(0); + + $this->mime_type = $this->get_mime_type( $this->image->getImageFormat() ); + } + catch ( Exception $e ) { + return new WP_Error( 'invalid_image', $e->getMessage(), $this->file ); + } + + $updated_size = $this->update_size(); + if ( is_wp_error( $updated_size ) ) { + return $updated_size; + } + + return $this->set_quality(); + } + + /** + * Resizes current image. + * + * At minimum, either a height or width must be provided. + * If one of the two is set to null, the resize will + * maintain aspect ratio according to the provided dimension. + * + * @access public + * + * @param int|null $max_w Image width. + * @param int|null $max_h Image height. + * @param boolean $crop + * @return boolean|WP_Error + */ + public function resize( $max_w, $max_h, $crop = false ) { + if ( ( $this->size['width'] == $max_w ) && ( $this->size['height'] == $max_h ) ) + return true; + + $dims = image_resize_dimensions( $this->size['width'], $this->size['height'], $max_w, $max_h, $crop ); + if ( ! $dims ) + return new WP_Error( 'error_getting_dimensions', __('Could not calculate resized image dimensions') ); + list( $dst_x, $dst_y, $src_x, $src_y, $dst_w, $dst_h, $src_w, $src_h ) = $dims; + + if ( $crop ) { + return $this->crop( $src_x, $src_y, $src_w, $src_h, $dst_w, $dst_h ); + } + + try { + $this->image->smartResize( $dst_w, $dst_h, false ); + } + catch ( Exception $e ) { + return new WP_Error( 'image_resize_error', $e->getMessage() ); + } + + return $this->update_size( $dst_w, $dst_h ); + } + + /** + * Resize multiple images from a single source. + * + * @access public + * + * @param array $sizes { + * An array of image size arrays. Default sizes are 'small', 'medium', 'large'. + * + * Either a height or width must be provided. + * If one of the two is set to null, the resize will + * maintain aspect ratio according to the provided dimension. + * + * @type array $size { + * @type int ['width'] Optional. Image width. + * @type int ['height'] Optional. Image height. + * @type bool $crop Optional. Whether to crop the image. Default false. + * } + * } + * @return array An array of resized images' metadata by size. + */ + public function multi_resize( $sizes ) { + $metadata = array(); + $orig_size = $this->size; + $orig_image = clone $this->image; + + foreach ( $sizes as $size => $size_data ) { + if ( ! $this->image ) + $this->image = clone $orig_image; + + if ( ! isset( $size_data['width'] ) && ! isset( $size_data['height'] ) ) { + continue; + } + + if ( ! isset( $size_data['width'] ) ) { + $size_data['width'] = null; + } + if ( ! isset( $size_data['height'] ) ) { + $size_data['height'] = null; + } + + if ( ! isset( $size_data['crop'] ) ) { + $size_data['crop'] = false; + } + + $resize_result = $this->resize( $size_data['width'], $size_data['height'], $size_data['crop'] ); + $duplicate = ( ( $orig_size['width'] == $size_data['width'] ) && ( $orig_size['height'] == $size_data['height'] ) ); + + if ( ! is_wp_error( $resize_result ) && ! $duplicate ) { + $resized = $this->_save( $this->image ); + + $this->image->clear(); + $this->image->destroy(); + $this->image = null; + + if ( ! is_wp_error( $resized ) && $resized ) { + unset( $resized['path'] ); + $metadata[$size] = $resized; + } + } + + $this->size = $orig_size; + } + + $this->image = $orig_image; + + return $metadata; + } + + /** + * Crops Image. + * + * @access public + * + * @param int $src_x The start x position to crop from. + * @param int $src_y The start y position to crop from. + * @param int $src_w The width to crop. + * @param int $src_h The height to crop. + * @param int $dst_w Optional. The destination width. + * @param int $dst_h Optional. The destination height. + * @param boolean $src_abs Optional. If the source crop points are absolute. + * @return boolean|WP_Error + */ + public function crop( $src_x, $src_y, $src_w, $src_h, $dst_w = null, $dst_h = null, $src_abs = false ) { + if ( $src_abs ) { + $src_w -= $src_x; + $src_h -= $src_y; + } + + try { + $this->image->cropImage( $src_w, $src_h, $src_x, $src_y ); + $this->image->setImagePage( $src_w, $src_h, 0, 0); + + if ( $dst_w || $dst_h ) { + // If destination width/height isn't specified, use same as + // width/height from source. + if ( ! $dst_w ) + $dst_w = $src_w; + if ( ! $dst_h ) + $dst_h = $src_h; + + $this->image->smartResize( $dst_w, $dst_h, false ); + return $this->update_size(); + } + } + catch ( Exception $e ) { + return new WP_Error( 'image_crop_error', $e->getMessage() ); + } + return $this->update_size(); + } + + } diff --git a/wp-tevko-responsive-images.php b/wp-tevko-responsive-images.php index abd0d59..9ebfaad 100644 --- a/wp-tevko-responsive-images.php +++ b/wp-tevko-responsive-images.php @@ -1,5 +1,8 @@ Date: Wed, 22 Apr 2015 12:48:03 -0400 Subject: [PATCH 02/28] bypass GIFs --- class-wp-image-editor-respimg.php | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/class-wp-image-editor-respimg.php b/class-wp-image-editor-respimg.php index e21c487..5683984 100644 --- a/class-wp-image-editor-respimg.php +++ b/class-wp-image-editor-respimg.php @@ -88,7 +88,11 @@ public function resize( $max_w, $max_h, $crop = false ) { } try { - $this->image->smartResize( $dst_w, $dst_h, false ); + if ($this->mime_type === 'image/gif') { + $this->image->scaleImage( $dst_w, $dst_h ); + } else { + $this->image->smartResize( $dst_w, $dst_h, false ); + } } catch ( Exception $e ) { return new WP_Error( 'image_resize_error', $e->getMessage() ); @@ -197,7 +201,11 @@ public function crop( $src_x, $src_y, $src_w, $src_h, $dst_w = null, $dst_h = nu if ( ! $dst_h ) $dst_h = $src_h; - $this->image->smartResize( $dst_w, $dst_h, false ); + if ($this->mime_type === 'image/gif') { + $this->image->scaleImage( $dst_w, $dst_h ); + } else { + $this->image->smartResize( $dst_w, $dst_h, false ); + } return $this->update_size(); } } From 761d8cd9bdce6feaf62ba261fa79cf098d63e339 Mon Sep 17 00:00:00 2001 From: David Newton Date: Thu, 23 Apr 2015 08:55:50 -0400 Subject: [PATCH 03/28] make fancy IM stuff optional --- wp-tevko-responsive-images.php | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/wp-tevko-responsive-images.php b/wp-tevko-responsive-images.php index 9ebfaad..afd0544 100644 --- a/wp-tevko-responsive-images.php +++ b/wp-tevko-responsive-images.php @@ -309,8 +309,10 @@ function tevkori_filter_content_sizes( $content ) { * * @return array editors **/ -function tevkori_wp_image_editors($editors) { - array_unshift($editors, 'WP_Image_Editor_Respimg'); +function tevkori_wp_image_editors( $editors ) { + if ( current_theme_supports( 'advanced-image-compression' ) ) { + array_unshift( $editors, 'WP_Image_Editor_Respimg' ); + } return $editors; } add_filter('wp_image_editors', 'tevkori_wp_image_editors'); From d6f1f9b43ddff4aa21034eb4167ec2eeab1dc8fa Mon Sep 17 00:00:00 2001 From: Jasper de Groot Date: Tue, 7 Apr 2015 09:47:02 +0200 Subject: [PATCH 04/28] Improve performance of get_srcset_array --- wp-tevko-responsive-images.php | 36 ++++++++++++++++------------------ 1 file changed, 17 insertions(+), 19 deletions(-) diff --git a/wp-tevko-responsive-images.php b/wp-tevko-responsive-images.php index abd0d59..ad127c0 100644 --- a/wp-tevko-responsive-images.php +++ b/wp-tevko-responsive-images.php @@ -156,31 +156,29 @@ function tevkori_get_srcset_array( $id, $size = 'thumbnail' ) { $default_sizes['full'] = array( 'width' => $image_meta['width'], 'height' => $image_meta['height'], - 'file' => $image_meta['file'] + 'file' => substr( $image_meta['file'], strrpos( $image_meta['file'], '/' ) + 1 ) ); - - // Remove any hard-crops + + // Image base url + $img_base_url = substr( $img_url, 0, strrpos( $img_url, '/' ) + 1 ); + + // Image aspect ratio + $img_ratio = $img_height / $img_width; + + // Only use sizes with same aspect ratio foreach ( $default_sizes as $key => $image_size ) { - // calculate the height we would expect if this is a soft crop given the size width - $soft_height = (int) round( $image_size['width'] * $img_height / $img_width ); + // Calculate the height we would expect if this is a soft crop given the size width + $soft_height = (int) round( $image_size['width'] * $img_ratio ); - // If image height varies more than 1px over the expected, throw it out. - if ( $image_size['height'] <= $soft_height - 2 || $image_size['height'] >= $soft_height + 2 ) { - unset( $default_sizes[$key] ); + // If image height doesn't varies more than 2px over the expected, use it. + if ( $image_size['height'] >= $soft_height - 2 && $image_size['height'] <= $soft_height + 2 ) { + $arr[] = $img_base_url . $image_size['file'] . ' ' . $image_size['width'] .'w'; } } - - // No sizes? Checkout early - if( ! $default_sizes ) - return false; - - // Loop through each size we know should exist - foreach( $default_sizes as $key => $size ) { - - // Reference the size directly by it's pixel dimension - $image_src = wp_get_attachment_image_src( $id, $key ); - $arr[] = $image_src[0] . ' ' . $size['width'] .'w'; + + if ( empty( $arr ) ) { + return false; } return $arr; From c489349c6c3c18cf49d6ead8e77a331e3d6b43da Mon Sep 17 00:00:00 2001 From: Tim Evko Date: Fri, 24 Apr 2015 11:34:24 -0400 Subject: [PATCH 05/28] proactive readme updates --- readme.md | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/readme.md b/readme.md index 266f5b4..a024a21 100644 --- a/readme.md +++ b/readme.md @@ -17,6 +17,18 @@ No configuration is needed! Just install the plugin and enjoy automatic responsi This plugin includes several functions that can be used by theme and plugin developers in templates. +###Advanced Image Compression + +**This is an experimental feature, if used, please provide us with feedback!** + +This feature turns on advanced compression, which will deliver higher quality images at a smaller file size. To enable, place the following code in your `functions.php` file - +``` +function custom_theme_setup() { + add_theme_support( 'advanced-image-compression' ); +} +add_action( 'after_setup_theme', 'custom_theme_setup' ); +``` + ####tevkori_get_sizes( $id, $size, $args ) Returns a valid source size value for use in a 'sizes' attribute. The parameters include the ID of the image, the default size of the image, and an array or string containing of size information. The ID parameter is required. [Link](https://github.com/ResponsiveImagesCG/wp-tevko-responsive-images/blob/master/wp-tevko-responsive-images.php#L28) @@ -119,10 +131,14 @@ We use a hook because if you attempt to dequeue a script before it's enqueued, w ##Version -2.2.1 +2.3.0 ##Changelog +- Added smart sizes option (available by adding hook to functions.php) + +**2.2.1** + - JS patch for wordpress **2.2.0** From e1a902ac38a28ffe2c1fa55ed09314ef6ad8c91c Mon Sep 17 00:00:00 2001 From: Tim Evko Date: Fri, 24 Apr 2015 11:35:34 -0400 Subject: [PATCH 06/28] formatting edit --- readme.md | 1 + 1 file changed, 1 insertion(+) diff --git a/readme.md b/readme.md index a024a21..b93e696 100644 --- a/readme.md +++ b/readme.md @@ -28,6 +28,7 @@ function custom_theme_setup() { } add_action( 'after_setup_theme', 'custom_theme_setup' ); ``` +--- ####tevkori_get_sizes( $id, $size, $args ) From b874cc1e81863ae894a6d47896b3865ccf2f327f Mon Sep 17 00:00:00 2001 From: Tim Evko Date: Mon, 27 Apr 2015 10:32:34 -0400 Subject: [PATCH 07/28] Improved performance of get_srcset_array added to changelog in readme --- readme.md | 1 + 1 file changed, 1 insertion(+) diff --git a/readme.md b/readme.md index b93e696..71fbbff 100644 --- a/readme.md +++ b/readme.md @@ -136,6 +136,7 @@ We use a hook because if you attempt to dequeue a script before it's enqueued, w ##Changelog +- Improved performance of `get_srcset_array` - Added smart sizes option (available by adding hook to functions.php) **2.2.1** From cce56196ce988c9af8c8526f6f46f85f8b38d7f4 Mon Sep 17 00:00:00 2001 From: Jasper de Groot Date: Fri, 20 Mar 2015 01:35:52 +0100 Subject: [PATCH 08/28] Use wp_get_attachment_image_attributes filter for post thumbnails --- wp-tevko-responsive-images.php | 59 ++++++++++++++++++++++------------ 1 file changed, 38 insertions(+), 21 deletions(-) diff --git a/wp-tevko-responsive-images.php b/wp-tevko-responsive-images.php index b93ff89..61a0afd 100644 --- a/wp-tevko-responsive-images.php +++ b/wp-tevko-responsive-images.php @@ -187,19 +187,34 @@ function tevkori_get_srcset_array( $id, $size = 'thumbnail' ) { return $arr; } +/** + * Get the value for the 'srcset' attribute. + * + * @param int $id Image attachment ID. + * @param string $size Optional. Name of image size. Default value: 'thumbnail'. + * @return string|bool A 'srcset' value string or false. + */ +function tevkori_get_srcset( $id, $size = 'thumbnail' ) { + $srcset_array = tevkori_get_srcset_array( $id, $size ); + if ( empty( $srcset_array ) ) { + return false; + } + return implode( ', ', $srcset_array ); +} + /** * Create a 'srcset' attribute. * - * @param int $id Image attacment ID. + * @param int $id Image attachment ID. * @param string $size Optional. Name of image size. Default value: 'thumbnail'. * @return string|bool A full 'srcset' string or false. */ function tevkori_get_srcset_string( $id, $size = 'thumbnail' ) { - $srcset_array = tevkori_get_srcset_array( $id, $size ); - if ( empty( $srcset_array ) ) { + $srcset_value = tevkori_get_srcset( $id, $size ); + if ( empty( $srcset_value ) ) { return false; } - return 'srcset="' . implode( ', ', $srcset_array ) . '"'; + return 'srcset="' . $srcset_value . '"'; } /** @@ -239,28 +254,30 @@ function tevkori_extend_image_tag( $html, $id, $caption, $title, $align, $url, $ add_filter( 'image_send_to_editor', 'tevkori_extend_image_tag', 0, 8 ); /** - * Filter to add srcset attributes to post_thumbnails + * Filter to add srcset and sizes attributes to post_thumbnails and gallery images. * - * @see 'post_thumbnail_html' - * @return string HTML for image. + * @see 'wp_get_attachment_image_attributes' + * @return array attributes for image. */ -function tevkori_filter_post_thumbnail_html( $html, $post_id, $post_thumbnail_id, $size, $attr ) { - // if the HTML is empty, short circuit - if ( '' === $html ) { - return; +function tevkori_filter_attachment_image_attributes( $attr, $attachment, $size ) { + $attachment_id = $attachment->ID; + + if ( ! isset( $attr['sizes'] ) ) { + $sizes = tevkori_get_sizes( $attachment_id, $size ); + // Build the sizes attribute if sizes were returned. + if ( $sizes ) { + $attr['sizes'] = $sizes; + } } - - $sizes = tevkori_get_sizes( $post_thumbnail_id, $size ); - // Build the data-sizes attribute if sizes were returned. - if ( $sizes ) { - $sizes = 'sizes="' . $sizes . '"'; + + if ( ! isset( $attr['srcset'] ) ) { + $srcset = tevkori_get_srcset( $attachment_id, $size ); + $attr['srcset'] = $srcset; } - - $srcset = tevkori_get_srcset_string( $post_thumbnail_id, $size ); - $html = preg_replace( '/(src\s*=\s*"(.+?)")/', '$1 ' . $sizes . ' ' . $srcset, $html ); - return $html; + + return $attr; } -add_filter( 'post_thumbnail_html', 'tevkori_filter_post_thumbnail_html', 0, 5); +add_filter( 'wp_get_attachment_image_attributes', 'tevkori_filter_attachment_image_attributes', 0, 4 ); /** * Disable the editor size constraint applied for images in TinyMCE. From c0101d32fa8634f1c1f3909aad829a099cf847b4 Mon Sep 17 00:00:00 2001 From: Joe McGill Date: Sat, 9 May 2015 23:06:46 -0500 Subject: [PATCH 09/28] fix typo and clarify tevkori_get_srcset_array readme example --- readme.md | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/readme.md b/readme.md index 71fbbff..adbf34a 100644 --- a/readme.md +++ b/readme.md @@ -93,17 +93,16 @@ Returns an array of image source candidates for use in a 'srcset' attribute. The ***Usage Example*** ``` - $sources = tevkori_get_srcset_array( 11, 'medium' ); -$srcset = array(); -foreach( $srcset as $source ) { - if ( false === strpos(' 900w', $source) { - $srcset[] = $source; - } +// Optionally remove a specific source from the srcset list. +foreach( $sources as $key => $source ) { + if ( strpos( $source, '300w' ) ) { + unset( $s[$key] ); + } } - + ``` --- From 9f7050d196fdf9051c6893b7646ece6e1bd9a894 Mon Sep 17 00:00:00 2001 From: Jasper de Groot Date: Wed, 22 Apr 2015 10:58:43 +0200 Subject: [PATCH 10/28] Typo fixes, comments, and coding standards --- wp-tevko-responsive-images.php | 166 ++++++++++++++++++--------------- 1 file changed, 93 insertions(+), 73 deletions(-) diff --git a/wp-tevko-responsive-images.php b/wp-tevko-responsive-images.php index 61a0afd..c036c95 100644 --- a/wp-tevko-responsive-images.php +++ b/wp-tevko-responsive-images.php @@ -1,7 +1,7 @@ array( array( - 'size_value' => '100vw', - 'mq_value' => $img_width, - 'mq_name' => 'max-width' + 'size_value' => '100vw', + 'mq_value' => $img_width, + 'mq_name' => 'max-width' ), array( - 'size_value' => $img_width + 'size_value' => $img_width ), ) ); $args = wp_parse_args( $args, $defaults ); - // If sizes is passed as a string, just use the string + // If sizes is passed as a string, just use the string. if ( is_string( $args['sizes'] ) ) { $size_list = $args['sizes']; - - // Otherwise, breakdown the array and build a sizes string + + // Otherwise, breakdown the array and build a sizes string. } elseif ( is_array( $args['sizes'] ) ) { $size_list = ''; - foreach( $args['sizes'] as $size ) { + foreach ( $args['sizes'] as $size ) { + // Use 100vw as the size value unless something else is specified. $size_value = ( $size['size_value'] ) ? $size['size_value'] : '100vw'; // If a media length is specified, build the media query. - if ( ! empty($size['mq_value']) ) { + if ( ! empty( $size['mq_value'] ) ) { $media_length = $size['mq_value']; // Use max-width as the media condition unless min-width is specified. - $media_condition = ( ! empty($size['mq_name']) ) ? $size['mq_name'] : 'max-width'; + $media_condition = ( ! empty( $size['mq_name'] ) ) ? $size['mq_name'] : 'max-width'; // If a media_length was set, create the media query. $media_query = '(' . $media_condition . ": " . $media_length . ') '; } else { - // If not meda length was set, $media_query is blank + + // If not meda length was set, $media_query is blank. $media_query = ''; } @@ -101,7 +104,7 @@ function tevkori_get_sizes( $id, $size = 'thumbnail', $args = null ) { } // Remove the trailing comma and space from the end of the string. - $size_list = substr($size_list, 0, -2); + $size_list = substr( $size_list, 0, -2 ); } // If $size_list is defined set the string, otherwise set false. @@ -111,19 +114,19 @@ function tevkori_get_sizes( $id, $size = 'thumbnail', $args = null ) { } /** -* Return a source size list for an image from an array of values. -* -* @since 2.2.0 -* -* @param int $id Image attacment ID. -* @param string $size Optional. Name of image size. Default value: 'thumbnail'. -* @param array $args { -* Optional. Arguments to retrieve posts. -* -* @type array|string $sizes An array or string containing of size information. -* } -* @return string|bool A valid source size list as a 'sizes' attribute or false. -*/ + * Return a source size list for an image from an array of values. + * + * @since 2.2.0 + * + * @param int $id Image attachment ID. + * @param string $size Optional. Name of image size. Default value: 'thumbnail'. + * @param array $args { + * Optional. Arguments to retrieve posts. + * + * @type array|string $sizes An array or string containing of size information. + * } + * @return string|bool A valid source size list as a 'sizes' attribute or false. + */ function tevkori_get_sizes_string( $id, $size = 'thumbnail', $args = null ) { $sizes = tevkori_get_sizes( $id, $size, $args ); $sizes_string = $sizes ? 'sizes="' . $sizes . '"' : false; @@ -134,44 +137,44 @@ function tevkori_get_sizes_string( $id, $size = 'thumbnail', $args = null ) { /** * Get an array of image sources candidates for use in a 'srcset' attribute. * - * @param int $id Image attacment ID. - * @param string $size Optional. Name of image size. Default value: 'thumbnail'. - * @return array|bool An array of of srcset values or false. + * @param int $id Image attachment ID. + * @param string $size Optional. Name of image size. Default value: 'thumbnail'. + * @return array|bool An array of of srcset values or false. */ function tevkori_get_srcset_array( $id, $size = 'thumbnail' ) { $arr = array(); - // See which image is being returned and bail if none is found + // See which image is being returned and bail if none is found. if ( ! $image = wp_get_attachment_image_src( $id, $size ) ) { return false; }; - // break image data into url, width, and height + // Break image data into url, width, and height. list( $img_url, $img_width, $img_height ) = $image; - // image meta + // Get the image meta data. $image_meta = wp_get_attachment_metadata( $id ); - // default sizes + // Build an array with default sizes. $default_sizes = $image_meta['sizes']; - // add full size to the default_sizes array + // Add full size to the default_sizes array. $default_sizes['full'] = array( 'width' => $image_meta['width'], 'height' => $image_meta['height'], 'file' => substr( $image_meta['file'], strrpos( $image_meta['file'], '/' ) + 1 ) ); - // Image base url + // Get the image base url. $img_base_url = substr( $img_url, 0, strrpos( $img_url, '/' ) + 1 ); - // Image aspect ratio + // Calculate the image aspect ratio. $img_ratio = $img_height / $img_width; - // Only use sizes with same aspect ratio + // Only use sizes with same aspect ratio. foreach ( $default_sizes as $key => $image_size ) { - // Calculate the height we would expect if this is a soft crop given the size width + // Calculate the height we would expect if this is a soft crop given the size width. $soft_height = (int) round( $image_size['width'] * $img_ratio ); // If image height doesn't varies more than 2px over the expected, use it. @@ -190,30 +193,38 @@ function tevkori_get_srcset_array( $id, $size = 'thumbnail' ) { /** * Get the value for the 'srcset' attribute. * - * @param int $id Image attachment ID. - * @param string $size Optional. Name of image size. Default value: 'thumbnail'. - * @return string|bool A 'srcset' value string or false. + * @since 2.3.0 + * + * @param int $id Image attachment ID. + * @param string $size Optional. Name of image size. Default value: 'thumbnail'. + * @return string|bool A 'srcset' value string or false. */ function tevkori_get_srcset( $id, $size = 'thumbnail' ) { $srcset_array = tevkori_get_srcset_array( $id, $size ); + if ( empty( $srcset_array ) ) { return false; } + return implode( ', ', $srcset_array ); } /** * Create a 'srcset' attribute. * - * @param int $id Image attachment ID. - * @param string $size Optional. Name of image size. Default value: 'thumbnail'. - * @return string|bool A full 'srcset' string or false. + * @since 2.1.0 + * + * @param int $id Image attachment ID. + * @param string $size Optional. Name of image size. Default value: 'thumbnail'. + * @return string|bool A full 'srcset' string or false. */ function tevkori_get_srcset_string( $id, $size = 'thumbnail' ) { $srcset_value = tevkori_get_srcset( $id, $size ); + if ( empty( $srcset_value ) ) { return false; } + return 'srcset="' . $srcset_value . '"'; } @@ -221,49 +232,55 @@ function tevkori_get_srcset_string( $id, $size = 'thumbnail' ) { * Create a 'srcset' attribute. * * @deprecated 2.1.0 - * @deprecated Use tevkori_get_srcset_string + * @deprecated Use tevkori_get_srcset_string instead. * @see tevkori_get_srcset_string * - * @param int $id Image attacment ID. - * @return string|bool A full 'srcset' string or false. + * @param int $id Image attachment ID. + * @return string|bool A full 'srcset' string or false. */ function tevkori_get_src_sizes( $id, $size = 'thumbnail' ) { return tevkori_get_srcset_string( $id, $size ); } /** - * Filter for extending image tag to include srcset attribute + * Filter for extending image tag to include srcset attribute. * - * @see 'images_send_to_editor' + * @see images_send_to_editor * @return string HTML for image. */ function tevkori_extend_image_tag( $html, $id, $caption, $title, $align, $url, $size, $alt ) { add_filter( 'editor_max_image_size', 'tevkori_editor_image_size' ); $sizes = tevkori_get_sizes( $id, $size ); + // Build the data-sizes attribute if sizes were returned. if ( $sizes ) { $sizes = 'data-sizes="' . $sizes . '"'; } + // Build the srcset attribute. $srcset = tevkori_get_srcset_string( $id, $size ); + remove_filter( 'editor_max_image_size', 'tevkori_editor_image_size' ); + $html = preg_replace( '/(src\s*=\s*"(.+?)")/', '$1 ' . $sizes . ' ' . $srcset, $html ); + return $html; } add_filter( 'image_send_to_editor', 'tevkori_extend_image_tag', 0, 8 ); /** - * Filter to add srcset and sizes attributes to post_thumbnails and gallery images. + * Filter to add srcset and sizes attributes to post thumbnails and gallery images. * - * @see 'wp_get_attachment_image_attributes' - * @return array attributes for image. + * @see wp_get_attachment_image_attributes + * @return array Attributes for image. */ function tevkori_filter_attachment_image_attributes( $attr, $attachment, $size ) { $attachment_id = $attachment->ID; if ( ! isset( $attr['sizes'] ) ) { $sizes = tevkori_get_sizes( $attachment_id, $size ); + // Build the sizes attribute if sizes were returned. if ( $sizes ) { $attr['sizes'] = $sizes; @@ -282,32 +299,32 @@ function tevkori_filter_attachment_image_attributes( $attr, $attachment, $size ) /** * Disable the editor size constraint applied for images in TinyMCE. * - * @param array $max_image_size An array with the width as the first element, and the height as the second element. + * @param array $max_image_size An array with the width as the first element, and the height as the second element. * @return array A width & height array so large it shouldn't constrain reasonable images. */ -function tevkori_editor_image_size( $max_image_size ){ +function tevkori_editor_image_size( $max_image_size ) { return array( 99999, 99999 ); } /** - * Load admin scripts + * Load admin scripts. * * @param string $hook Admin page file name. */ function tevkori_load_admin_scripts( $hook ) { - if ($hook == 'post.php' || $hook == 'post-new.php') { - wp_enqueue_script( 'wp-tevko-responsive-images', plugin_dir_url( __FILE__ ) . 'js/wp-tevko-responsive-images.js', array('wp-backbone'), '2.0.0', true ); + if ( $hook == 'post.php' || $hook == 'post-new.php' ) { + wp_enqueue_script( 'wp-tevko-responsive-images', plugin_dir_url( __FILE__ ) . 'js/wp-tevko-responsive-images.js', array( 'wp-backbone' ), '2.0.0', true ); } } add_action( 'admin_enqueue_scripts', 'tevkori_load_admin_scripts' ); /** - * Filter for the_content to replace data-size attributes with size attributes + * Filter for the_content to replace data-size attributes with size attributes. * * @since 2.2.0 * - * @param string $content The raw post content to be filtered. + * @param string $content The raw post content to be filtered. */ function tevkori_filter_content_sizes( $content ) { $images = '/( Date: Wed, 22 Apr 2015 11:39:13 +0200 Subject: [PATCH 11/28] Variable names Ref ResponsiveImagesCG/wp-tevko-responsive-images/issues/33 --- wp-tevko-responsive-images.php | 87 +++++++++++++++++----------------- 1 file changed, 43 insertions(+), 44 deletions(-) diff --git a/wp-tevko-responsive-images.php b/wp-tevko-responsive-images.php index c036c95..711c178 100644 --- a/wp-tevko-responsive-images.php +++ b/wp-tevko-responsive-images.php @@ -43,14 +43,13 @@ function tevkori_get_picturefill() { * @return string|bool A valid source size value for use in a 'sizes' attribute or false. */ function tevkori_get_sizes( $id, $size = 'thumbnail', $args = null ) { - - // See which image is being returned and bail if none is found. - if ( ! $image = image_downsize( $id, $size ) ) { + // See which image is being returned and bail if none is found + if ( ! $img = image_downsize( $id, $size ) ) { return false; }; - // Get the image width. - $img_width = $image[1] . 'px'; + // Get the image width + $img_width = $img[1] . 'px'; // Set up our default values. $defaults = array( @@ -71,14 +70,14 @@ function tevkori_get_sizes( $id, $size = 'thumbnail', $args = null ) { // If sizes is passed as a string, just use the string. if ( is_string( $args['sizes'] ) ) { $size_list = $args['sizes']; - + // Otherwise, breakdown the array and build a sizes string. } elseif ( is_array( $args['sizes'] ) ) { $size_list = ''; foreach ( $args['sizes'] as $size ) { - + // Use 100vw as the size value unless something else is specified. $size_value = ( $size['size_value'] ) ? $size['size_value'] : '100vw'; @@ -94,7 +93,7 @@ function tevkori_get_sizes( $id, $size = 'thumbnail', $args = null ) { $media_query = '(' . $media_condition . ": " . $media_length . ') '; } else { - + // If not meda length was set, $media_query is blank. $media_query = ''; } @@ -144,45 +143,45 @@ function tevkori_get_sizes_string( $id, $size = 'thumbnail', $args = null ) { function tevkori_get_srcset_array( $id, $size = 'thumbnail' ) { $arr = array(); - // See which image is being returned and bail if none is found. - if ( ! $image = wp_get_attachment_image_src( $id, $size ) ) { + // See which image is being returned and bail if none is found + if ( ! $img = wp_get_attachment_image_src( $id, $size ) ) { return false; }; - // Break image data into url, width, and height. - list( $img_url, $img_width, $img_height ) = $image; + // break image data into url, width, and height + list( $img_url, $img_width, $img_height ) = $img; - // Get the image meta data. - $image_meta = wp_get_attachment_metadata( $id ); + // image meta + $img_meta = wp_get_attachment_metadata( $id ); - // Build an array with default sizes. - $default_sizes = $image_meta['sizes']; + // Build an array with image sizes. + $img_sizes = $img_meta['sizes']; - // Add full size to the default_sizes array. - $default_sizes['full'] = array( - 'width' => $image_meta['width'], - 'height' => $image_meta['height'], - 'file' => substr( $image_meta['file'], strrpos( $image_meta['file'], '/' ) + 1 ) + // Add full size to the img_sizes array. + $img_sizes['full'] = array( + 'width' => $img_meta['width'], + 'height' => $img_meta['height'], + 'file' => substr( $img_meta['file'], strrpos( $img_meta['file'], '/' ) + 1 ) ); - + // Get the image base url. $img_base_url = substr( $img_url, 0, strrpos( $img_url, '/' ) + 1 ); - + // Calculate the image aspect ratio. $img_ratio = $img_height / $img_width; - // Only use sizes with same aspect ratio. - foreach ( $default_sizes as $key => $image_size ) { + // Only use sizes with same aspect ratio + foreach ( $img_sizes as $img_size => $img ) { - // Calculate the height we would expect if this is a soft crop given the size width. - $soft_height = (int) round( $image_size['width'] * $img_ratio ); + // Calculate the height we would expect if the image size has the same aspect ratio. + $expected_height = (int) round( $img['width'] * $img_ratio ); // If image height doesn't varies more than 2px over the expected, use it. - if ( $image_size['height'] >= $soft_height - 2 && $image_size['height'] <= $soft_height + 2 ) { - $arr[] = $img_base_url . $image_size['file'] . ' ' . $image_size['width'] .'w'; + if ( $img['height'] >= $expected_height - 2 && $img['height'] <= $expected_height + 2 ) { + $arr[] = $img_base_url . $img['file'] . ' ' . $img['width'] .'w'; } } - + if ( empty( $arr ) ) { return false; } @@ -201,11 +200,11 @@ function tevkori_get_srcset_array( $id, $size = 'thumbnail' ) { */ function tevkori_get_srcset( $id, $size = 'thumbnail' ) { $srcset_array = tevkori_get_srcset_array( $id, $size ); - + if ( empty( $srcset_array ) ) { return false; } - + return implode( ', ', $srcset_array ); } @@ -220,11 +219,11 @@ function tevkori_get_srcset( $id, $size = 'thumbnail' ) { */ function tevkori_get_srcset_string( $id, $size = 'thumbnail' ) { $srcset_value = tevkori_get_srcset( $id, $size ); - + if ( empty( $srcset_value ) ) { return false; } - + return 'srcset="' . $srcset_value . '"'; } @@ -252,19 +251,19 @@ function tevkori_extend_image_tag( $html, $id, $caption, $title, $align, $url, $ add_filter( 'editor_max_image_size', 'tevkori_editor_image_size' ); $sizes = tevkori_get_sizes( $id, $size ); - + // Build the data-sizes attribute if sizes were returned. if ( $sizes ) { $sizes = 'data-sizes="' . $sizes . '"'; } - + // Build the srcset attribute. $srcset = tevkori_get_srcset_string( $id, $size ); - + remove_filter( 'editor_max_image_size', 'tevkori_editor_image_size' ); - + $html = preg_replace( '/(src\s*=\s*"(.+?)")/', '$1 ' . $sizes . ' ' . $srcset, $html ); - + return $html; } add_filter( 'image_send_to_editor', 'tevkori_extend_image_tag', 0, 8 ); @@ -277,21 +276,21 @@ function tevkori_extend_image_tag( $html, $id, $caption, $title, $align, $url, $ */ function tevkori_filter_attachment_image_attributes( $attr, $attachment, $size ) { $attachment_id = $attachment->ID; - + if ( ! isset( $attr['sizes'] ) ) { $sizes = tevkori_get_sizes( $attachment_id, $size ); - + // Build the sizes attribute if sizes were returned. if ( $sizes ) { $attr['sizes'] = $sizes; } } - + if ( ! isset( $attr['srcset'] ) ) { $srcset = tevkori_get_srcset( $attachment_id, $size ); $attr['srcset'] = $srcset; } - + return $attr; } add_filter( 'wp_get_attachment_image_attributes', 'tevkori_filter_attachment_image_attributes', 0, 4 ); @@ -347,7 +346,7 @@ function tevkori_wp_image_editors( $editors ) { if ( current_theme_supports( 'advanced-image-compression' ) ) { array_unshift( $editors, 'WP_Image_Editor_Respimg' ); } - + return $editors; } add_filter( 'wp_image_editors', 'tevkori_wp_image_editors' ); From 90643ec8734cdc35cf4c2cb2b4384bd8de7c4eba Mon Sep 17 00:00:00 2001 From: Joe McGill Date: Tue, 12 May 2015 09:06:10 -0500 Subject: [PATCH 12/28] Move list of included libraries below plugin header. --- wp-tevko-responsive-images.php | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/wp-tevko-responsive-images.php b/wp-tevko-responsive-images.php index 711c178..d6c49b4 100644 --- a/wp-tevko-responsive-images.php +++ b/wp-tevko-responsive-images.php @@ -1,7 +1,5 @@ Date: Tue, 12 May 2015 16:40:42 +0200 Subject: [PATCH 13/28] Revert unintentional changes in comments from commit ddeacce --- wp-tevko-responsive-images.php | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/wp-tevko-responsive-images.php b/wp-tevko-responsive-images.php index d6c49b4..a74972c 100644 --- a/wp-tevko-responsive-images.php +++ b/wp-tevko-responsive-images.php @@ -44,12 +44,13 @@ function tevkori_get_picturefill() { * @return string|bool A valid source size value for use in a 'sizes' attribute or false. */ function tevkori_get_sizes( $id, $size = 'thumbnail', $args = null ) { - // See which image is being returned and bail if none is found + + // See which image is being returned and bail if none is found. if ( ! $img = image_downsize( $id, $size ) ) { return false; }; - // Get the image width + // Get the image width. $img_width = $img[1] . 'px'; // Set up our default values. @@ -144,15 +145,15 @@ function tevkori_get_sizes_string( $id, $size = 'thumbnail', $args = null ) { function tevkori_get_srcset_array( $id, $size = 'thumbnail' ) { $arr = array(); - // See which image is being returned and bail if none is found + // See which image is being returned and bail if none is found. if ( ! $img = wp_get_attachment_image_src( $id, $size ) ) { return false; }; - // break image data into url, width, and height + // Break image data into url, width, and height. list( $img_url, $img_width, $img_height ) = $img; - // image meta + // Get the image meta data. $img_meta = wp_get_attachment_metadata( $id ); // Build an array with image sizes. @@ -171,7 +172,7 @@ function tevkori_get_srcset_array( $id, $size = 'thumbnail' ) { // Calculate the image aspect ratio. $img_ratio = $img_height / $img_width; - // Only use sizes with same aspect ratio + // Only use sizes with same aspect ratio. foreach ( $img_sizes as $img_size => $img ) { // Calculate the height we would expect if the image size has the same aspect ratio. @@ -276,7 +277,7 @@ function tevkori_extend_image_tag( $html, $id, $caption, $title, $align, $url, $ * @return array Attributes for image. */ function tevkori_filter_attachment_image_attributes( $attr, $attachment, $size ) { - $attachment_id = $attachment->ID; + $attachment_id = $attachment->ID; if ( ! isset( $attr['sizes'] ) ) { $sizes = tevkori_get_sizes( $attachment_id, $size ); @@ -292,7 +293,7 @@ function tevkori_filter_attachment_image_attributes( $attr, $attachment, $size ) $attr['srcset'] = $srcset; } - return $attr; + return $attr; } add_filter( 'wp_get_attachment_image_attributes', 'tevkori_filter_attachment_image_attributes', 0, 4 ); From 0fc1bf71da1d6523c590d9ce282030226603ae3b Mon Sep 17 00:00:00 2001 From: Joe McGill Date: Thu, 14 May 2015 12:35:26 -0500 Subject: [PATCH 14/28] Refactor plugin JS, ajax srcset --- js/wp-tevko-responsive-images.js | 54 ++++++++++++++++++-------------- wp-tevko-responsive-images.php | 22 ++++++++++++- 2 files changed, 52 insertions(+), 24 deletions(-) diff --git a/js/wp-tevko-responsive-images.js b/js/wp-tevko-responsive-images.js index de9ff1f..dab69c5 100644 --- a/js/wp-tevko-responsive-images.js +++ b/js/wp-tevko-responsive-images.js @@ -9,40 +9,48 @@ wp.media.events.on( 'editor:image-update', function( args ) { // arguments[0] = { Editor, image, metadata } var image = args.image, - metadata = args.metadata, - srcsetGroup = [], - srcset = '', - sizes = ''; + metadata = args.metadata; // if the image url has changed, recalculate srcset attributes if ( metadata && metadata.url !== metadata.originalUrl ) { // we need to get the postdata for the image because // the sizes array isn't passed into the editor - var imagePostData = new wp.media.model.PostImage( metadata ), - crops = imagePostData.attachment.attributes.sizes; - // grab all the sizes that match our target ratio and add them to our srcset array - _.each(crops, function(size){ - var softHeight = Math.round( size.width * metadata.height / metadata.width ); + // Update the srcset attribute + updateSrcset( image, metadata ); - // If the height is within 1 integer of the expected height, let it pass. - if ( size.height >= softHeight - 1 && size.height <= softHeight + 1 ) { - srcsetGroup.push(size.url + ' ' + size.width + 'w'); - } - }); + // Update the sizes attribute + updateSizes( image, metadata ); + } - // convert the srcsetGroup array to our srcset value - srcset = srcsetGroup.join(', '); - sizes = '(max-width: ' + metadata.width + 'px) 100vw, ' + metadata.width + 'px'; + }); + } - // update the srcset attribute of our image - image.setAttribute( 'srcset', srcset ); + /** + * Update the srcet attribute on an image in the editor + */ + var updateSrcset = function( image, metadata ) { - // update the sizes attribute of our image - image.setAttribute( 'data-sizes', sizes ); - } + var data = { + action: 'tevkori_ajax_srcset', + postID: metadata.attachment_id, + size: metadata.size + }; + + jQuery.post( ajaxurl, data, function( response ) { + image.setAttribute( 'srcset', response ); + }); + } + + /** + * Update the data-sizes attribute on an image in the editor + */ + var updateSizes = function( image, metadata ) { + + var sizes = '(max-width: ' + metadata.width + 'px) 100vw, ' + metadata.width + 'px'; - }); + // update the sizes attribute of our image + image.setAttribute( 'data-sizes', sizes ); } diff --git a/wp-tevko-responsive-images.php b/wp-tevko-responsive-images.php index a74972c..1849df1 100644 --- a/wp-tevko-responsive-images.php +++ b/wp-tevko-responsive-images.php @@ -44,7 +44,7 @@ function tevkori_get_picturefill() { * @return string|bool A valid source size value for use in a 'sizes' attribute or false. */ function tevkori_get_sizes( $id, $size = 'thumbnail', $args = null ) { - + // See which image is being returned and bail if none is found. if ( ! $img = image_downsize( $id, $size ) ) { return false; @@ -352,3 +352,23 @@ function tevkori_wp_image_editors( $editors ) { return $editors; } add_filter( 'wp_image_editors', 'tevkori_wp_image_editors' ); + + +function tevkori_ajax_srcset() { + + // Bail early if no post ID is passed. + if ( ! $postID = $_POST['postID'] ) { + return; + }; + + // Grab the image size being passed from the AJAX request. + $size = $_POST['size']; + + // Get the srcset value for our image. + $srcset = tevkori_get_srcset( $postID, $size ); + + // For AJAX requests, we echo the result and then die. + echo $srcset; + die(); +} +add_action( 'wp_ajax_tevkori_ajax_srcset', 'tevkori_ajax_srcset' ); From cd373e3e092b1ab2c71c4dad94826fdf9abb98ac Mon Sep 17 00:00:00 2001 From: Joe McGill Date: Fri, 15 May 2015 10:17:40 -0500 Subject: [PATCH 15/28] convert spaces to tabs --- js/wp-tevko-responsive-images.js | 100 +++++++++++++++---------------- 1 file changed, 50 insertions(+), 50 deletions(-) diff --git a/js/wp-tevko-responsive-images.js b/js/wp-tevko-responsive-images.js index dab69c5..078ae6b 100644 --- a/js/wp-tevko-responsive-images.js +++ b/js/wp-tevko-responsive-images.js @@ -2,56 +2,56 @@ (function() { - /** - * Recalculate srcset attribute after an image-update event - */ - if ( wp.media ) { - wp.media.events.on( 'editor:image-update', function( args ) { - // arguments[0] = { Editor, image, metadata } - var image = args.image, - metadata = args.metadata; - - // if the image url has changed, recalculate srcset attributes - if ( metadata && metadata.url !== metadata.originalUrl ) { - // we need to get the postdata for the image because - // the sizes array isn't passed into the editor - - // Update the srcset attribute - updateSrcset( image, metadata ); - - // Update the sizes attribute - updateSizes( image, metadata ); - } - - }); - } - - /** - * Update the srcet attribute on an image in the editor - */ - var updateSrcset = function( image, metadata ) { - - var data = { - action: 'tevkori_ajax_srcset', - postID: metadata.attachment_id, - size: metadata.size - }; - - jQuery.post( ajaxurl, data, function( response ) { - image.setAttribute( 'srcset', response ); - }); - } - - /** - * Update the data-sizes attribute on an image in the editor - */ - var updateSizes = function( image, metadata ) { - - var sizes = '(max-width: ' + metadata.width + 'px) 100vw, ' + metadata.width + 'px'; - - // update the sizes attribute of our image - image.setAttribute( 'data-sizes', sizes ); - } + /** + * Recalculate srcset attribute after an image-update event + */ + if ( wp.media ) { + wp.media.events.on( 'editor:image-update', function( args ) { + // arguments[0] = { Editor, image, metadata } + var image = args.image, + metadata = args.metadata; + + // if the image url has changed, recalculate srcset attributes + if ( metadata && metadata.url !== metadata.originalUrl ) { + // we need to get the postdata for the image because + // the sizes array isn't passed into the editor + + // Update the srcset attribute + updateSrcset( image, metadata ); + + // Update the sizes attribute + updateSizes( image, metadata ); + } + + }); + } + + /** + * Update the srcet attribute on an image in the editor + */ + var updateSrcset = function( image, metadata ) { + + var data = { + action: 'tevkori_ajax_srcset', + postID: metadata.attachment_id, + size: metadata.size + }; + + jQuery.post( ajaxurl, data, function( response ) { + image.setAttribute( 'srcset', response ); + }); + } + + /** + * Update the data-sizes attribute on an image in the editor + */ + var updateSizes = function( image, metadata ) { + + var sizes = '(max-width: ' + metadata.width + 'px) 100vw, ' + metadata.width + 'px'; + + // update the sizes attribute of our image + image.setAttribute( 'data-sizes', sizes ); + } })(); From 5636ebd5231070edd064e4bc71935ed9a2a528e3 Mon Sep 17 00:00:00 2001 From: Joe McGill Date: Fri, 15 May 2015 10:18:05 -0500 Subject: [PATCH 16/28] add .editorconfig --- .editorconfig | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 .editorconfig diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..e1cc194 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,21 @@ +# This file is for unifying the coding style for different editors and IDEs +# editorconfig.org + +# WordPress Coding Standards +# https://make.wordpress.org/core/handbook/coding-standards/ + +root = true + +[*] +charset = utf-8 +end_of_line = lf +insert_final_newline = true +trim_trailing_whitespace = true +indent_style = tab + +[{.jshintrc,*.json,*.yml}] +indent_style = space +indent_size = 2 + +[{*.txt,wp-config-sample.php}] +end_of_line = crlf From 8a6bdfc58a4947cb317a5c45ebf486fdf0f11337 Mon Sep 17 00:00:00 2001 From: Joe McGill Date: Fri, 15 May 2015 10:20:42 -0500 Subject: [PATCH 17/28] Remove leftover inline comments and update others for style --- js/wp-tevko-responsive-images.js | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/js/wp-tevko-responsive-images.js b/js/wp-tevko-responsive-images.js index 078ae6b..880ea97 100644 --- a/js/wp-tevko-responsive-images.js +++ b/js/wp-tevko-responsive-images.js @@ -11,15 +11,11 @@ var image = args.image, metadata = args.metadata; - // if the image url has changed, recalculate srcset attributes + // If the image url has changed, recalculate srcset attributes. if ( metadata && metadata.url !== metadata.originalUrl ) { - // we need to get the postdata for the image because - // the sizes array isn't passed into the editor - - // Update the srcset attribute + // Update the srcset attribute. updateSrcset( image, metadata ); - - // Update the sizes attribute + // Update the sizes attribute. updateSizes( image, metadata ); } @@ -49,7 +45,7 @@ var sizes = '(max-width: ' + metadata.width + 'px) 100vw, ' + metadata.width + 'px'; - // update the sizes attribute of our image + // Update the sizes attribute of our image. image.setAttribute( 'data-sizes', sizes ); } From 1872eb69c481aa6505184615a4b9696e6ac52ae8 Mon Sep 17 00:00:00 2001 From: Joe McGill Date: Fri, 15 May 2015 10:25:28 -0500 Subject: [PATCH 18/28] Add docblock for tevkori_ajax_srcset --- wp-tevko-responsive-images.php | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/wp-tevko-responsive-images.php b/wp-tevko-responsive-images.php index 1849df1..3727c0d 100644 --- a/wp-tevko-responsive-images.php +++ b/wp-tevko-responsive-images.php @@ -353,7 +353,13 @@ function tevkori_wp_image_editors( $editors ) { } add_filter( 'wp_image_editors', 'tevkori_wp_image_editors' ); - +/** + * Ajax handler for updating the srcset when an image is changed in the editor. + * + * @since 2.3.0 + * + * @return string A sourcest value. + */ function tevkori_ajax_srcset() { // Bail early if no post ID is passed. From 0251438d9d5b5a841e59b39999ec260ccb225826 Mon Sep 17 00:00:00 2001 From: Joe McGill Date: Fri, 15 May 2015 12:27:47 -0500 Subject: [PATCH 19/28] Upgrade Picturefill to 2.3.1 --- js/picturefill.min.js | 4 ++-- wp-tevko-responsive-images.php | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/js/picturefill.min.js b/js/picturefill.min.js index f05ff18..26b1d36 100755 --- a/js/picturefill.min.js +++ b/js/picturefill.min.js @@ -1,4 +1,4 @@ -/*! Picturefill - v2.3.0 - 2015-03-23 +/*! Picturefill - v2.3.1 - 2015-04-09 * http://scottjehl.github.io/picturefill * Copyright (c) 2015 https://github.com/scottjehl/picturefill/blob/master/Authors.txt; Licensed MIT */ -window.matchMedia||(window.matchMedia=function(){"use strict";var a=window.styleMedia||window.media;if(!a){var b=document.createElement("style"),c=document.getElementsByTagName("script")[0],d=null;b.type="text/css",b.id="matchmediajs-test",c.parentNode.insertBefore(b,c),d="getComputedStyle"in window&&window.getComputedStyle(b,null)||b.currentStyle,a={matchMedium:function(a){var c="@media "+a+"{ #matchmediajs-test { width: 1px; } }";return b.styleSheet?b.styleSheet.cssText=c:b.textContent=c,"1px"===d.width}}}return function(b){return{matches:a.matchMedium(b||"all"),media:b||"all"}}}()),function(a,b,c){"use strict";function d(b){"object"==typeof module&&"object"==typeof module.exports?module.exports=b:"function"==typeof define&&define.amd&&define("picturefill",function(){return b}),"object"==typeof a&&(a.picturefill=b)}function e(a){var b,c,d,e,f,i=a||{};b=i.elements||g.getAllElements();for(var j=0,k=b.length;k>j;j++)if(c=b[j],d=c.parentNode,e=void 0,f=void 0,"IMG"===c.nodeName.toUpperCase()&&(c[g.ns]||(c[g.ns]={}),i.reevaluate||!c[g.ns].evaluated)){if(d&&"PICTURE"===d.nodeName.toUpperCase()){if(g.removeVideoShim(d),e=g.getMatch(c,d),e===!1)continue}else e=void 0;(d&&"PICTURE"===d.nodeName.toUpperCase()||!g.sizesSupported&&c.srcset&&h.test(c.srcset))&&g.dodgeSrcset(c),e?(f=g.processSourceSet(e),g.applyBestCandidate(f,c)):(f=g.processSourceSet(c),(void 0===c.srcset||c[g.ns].srcset)&&g.applyBestCandidate(f,c)),c[g.ns].evaluated=!0}}function f(){function c(){var b;a._picturefillWorking||(a._picturefillWorking=!0,a.clearTimeout(b),b=a.setTimeout(function(){e({reevaluate:!0}),a._picturefillWorking=!1},60))}g.initTypeDetects(),e();var d=setInterval(function(){return e(),/^loaded|^i|^c/.test(b.readyState)?void clearInterval(d):void 0},250);a.addEventListener?a.addEventListener("resize",c,!1):a.attachEvent&&a.attachEvent("onresize",c)}if(a.HTMLPictureElement)return void d(function(){});b.createElement("picture");var g=a.picturefill||{},h=/\s+\+?\d+(e\d+)?w/;g.ns="picturefill",function(){g.srcsetSupported="srcset"in c,g.sizesSupported="sizes"in c}(),g.trim=function(a){return a.trim?a.trim():a.replace(/^\s+|\s+$/g,"")},g.makeUrl=function(){var a=b.createElement("a");return function(b){return a.href=b,a.href}}(),g.restrictsMixedContent=function(){return"https:"===a.location.protocol},g.matchesMedia=function(b){return a.matchMedia&&a.matchMedia(b).matches},g.getDpr=function(){return a.devicePixelRatio||1},g.getWidthFromLength=function(a){var c;if(!a||a.indexOf("%")>-1!=!1||!(parseFloat(a)>0||a.indexOf("calc(")>-1))return!1;a=a.replace("vw","%"),g.lengthEl||(g.lengthEl=b.createElement("div"),g.lengthEl.style.cssText="border:0;display:block;font-size:1em;left:0;margin:0;padding:0;position:absolute;visibility:hidden",g.lengthEl.className="helper-from-picturefill-js"),g.lengthEl.style.width="0px";try{g.lengthEl.style.width=a}catch(d){}return b.body.appendChild(g.lengthEl),c=g.lengthEl.offsetWidth,0>=c&&(c=!1),b.body.removeChild(g.lengthEl),c},g.detectTypeSupport=function(b,c){var d=new a.Image;return d.onerror=function(){g.types[b]=!1,e()},d.onload=function(){g.types[b]=1===d.width,e()},d.src=c,"pending"},g.types=g.types||{},g.initTypeDetects=function(){g.types["image/jpeg"]=!0,g.types["image/gif"]=!0,g.types["image/png"]=!0,g.types["image/svg+xml"]=b.implementation.hasFeature("http://www.w3.org/TR/SVG11/feature#Image","1.1"),g.types["image/webp"]=g.detectTypeSupport("image/webp","data:image/webp;base64,UklGRh4AAABXRUJQVlA4TBEAAAAvAAAAAAfQ//73v/+BiOh/AAA=")},g.verifyTypeSupport=function(a){var b=a.getAttribute("type");if(null===b||""===b)return!0;var c=g.types[b];return"string"==typeof c&&"pending"!==c?(g.types[b]=g.detectTypeSupport(b,c),"pending"):"function"==typeof c?(c(),"pending"):c},g.parseSize=function(a){var b=/(\([^)]+\))?\s*(.+)/g.exec(a);return{media:b&&b[1],length:b&&b[2]}},g.findWidthFromSourceSize=function(c){for(var d,e=g.trim(c).split(/\s*,\s*/),f=0,h=e.length;h>f;f++){var i=e[f],j=g.parseSize(i),k=j.length,l=j.media;if(k&&(!l||g.matchesMedia(l))&&(d=g.getWidthFromLength(k)))break}return d||Math.max(a.innerWidth||0,b.documentElement.clientWidth)},g.parseSrcset=function(a){for(var b=[];""!==a;){a=a.replace(/^\s+/g,"");var c,d=a.search(/\s/g),e=null;if(-1!==d){c=a.slice(0,d);var f=c.slice(-1);if((","===f||""===c)&&(c=c.replace(/,+$/,""),e=""),a=a.slice(d+1),null===e){var g=a.indexOf(",");-1!==g?(e=a.slice(0,g),a=a.slice(g+1)):(e=a,a="")}}else c=a,a="";(c||e)&&b.push({url:c,descriptor:e})}return b},g.parseDescriptor=function(a,b){var c,d=b||"100vw",e=a&&a.replace(/(^\s+|\s+$)/g,""),f=g.findWidthFromSourceSize(d);if(e)for(var h=e.split(" "),i=h.length-1;i>=0;i--){var j=h[i],k=j&&j.slice(j.length-1);if("h"!==k&&"w"!==k||g.sizesSupported){if("x"===k){var l=j&&parseFloat(j,10);c=l&&!isNaN(l)?l:1}}else c=parseFloat(parseInt(j,10)/f)}return c||1},g.getCandidatesFromSourceSet=function(a,b){for(var c=g.parseSrcset(a),d=[],e=0,f=c.length;f>e;e++){var h=c[e];d.push({url:h.url,resolution:g.parseDescriptor(h.descriptor,b)})}return d},g.dodgeSrcset=function(a){a.srcset&&(a[g.ns].srcset=a.srcset,a.srcset="",a.setAttribute("data-pfsrcset",a[g.ns].srcset))},g.processSourceSet=function(a){var b=a.getAttribute("srcset"),c=a.getAttribute("sizes"),d=[];return"IMG"===a.nodeName.toUpperCase()&&a[g.ns]&&a[g.ns].srcset&&(b=a[g.ns].srcset),b&&(d=g.getCandidatesFromSourceSet(b,c)),d},g.backfaceVisibilityFix=function(a){var b=a.style||{},c="webkitBackfaceVisibility"in b,d=b.zoom;c&&(b.zoom=".999",c=a.offsetWidth,b.zoom=d)},g.setIntrinsicSize=function(){var c={},d=function(a,b,c){b&&a.setAttribute("width",parseInt(b/c,10))};return function(e,f){var h;e[g.ns]&&!a.pfStopIntrinsicSize&&(void 0===e[g.ns].dims&&(e[g.ns].dims=e.getAttribute("width")||e.getAttribute("height")),e[g.ns].dims||(f.url in c?d(e,c[f.url],f.resolution):(h=b.createElement("img"),h.onload=function(){if(c[f.url]=h.width,!c[f.url])try{b.body.appendChild(h),c[f.url]=h.width||h.offsetWidth,b.body.removeChild(h)}catch(a){}e.src===f.url&&d(e,c[f.url],f.resolution),e=null,h.onload=null,h=null},h.src=f.url)))}}(),g.applyBestCandidate=function(a,b){var c,d,e;a.sort(g.ascendingSort),d=a.length,e=a[d-1];for(var f=0;d>f;f++)if(c=a[f],c.resolution>=g.getDpr()){e=c;break}e&&(e.url=g.makeUrl(e.url),b.src!==e.url&&(g.restrictsMixedContent()&&"http:"===e.url.substr(0,"http:".length).toLowerCase()?void 0!==window.console&&console.warn("Blocked mixed content image "+e.url):(b.src=e.url,b.currentSrc=b.src,g.backfaceVisibilityFix(b))),g.setIntrinsicSize(b,e))},g.ascendingSort=function(a,b){return a.resolution-b.resolution},g.removeVideoShim=function(a){var b=a.getElementsByTagName("video");if(b.length){for(var c=b[0],d=c.getElementsByTagName("source");d.length;)a.insertBefore(d[0],c);c.parentNode.removeChild(c)}},g.getAllElements=function(){for(var a=[],c=b.getElementsByTagName("img"),d=0,e=c.length;e>d;d++){var f=c[d];("PICTURE"===f.parentNode.nodeName.toUpperCase()||null!==f.getAttribute("srcset")||f[g.ns]&&null!==f[g.ns].srcset)&&a.push(f)}return a},g.getMatch=function(a,b){for(var c,d=b.childNodes,e=0,f=d.length;f>e;e++){var h=d[e];if(1===h.nodeType){if(h===a)return c;if("SOURCE"===h.nodeName.toUpperCase()){null!==h.getAttribute("src")&&void 0!==typeof console&&console.warn("The `src` attribute is invalid on `picture` `source` element; instead, use `srcset`.");var i=h.getAttribute("media");if(h.getAttribute("srcset")&&(!i||g.matchesMedia(i))){var j=g.verifyTypeSupport(h);if(j===!0){c=h;break}if("pending"===j)return!1}}}}return c},f(),e._=g,d(e)}(window,window.document,new window.Image); \ No newline at end of file +window.matchMedia||(window.matchMedia=function(){"use strict";var a=window.styleMedia||window.media;if(!a){var b=document.createElement("style"),c=document.getElementsByTagName("script")[0],d=null;b.type="text/css",b.id="matchmediajs-test",c.parentNode.insertBefore(b,c),d="getComputedStyle"in window&&window.getComputedStyle(b,null)||b.currentStyle,a={matchMedium:function(a){var c="@media "+a+"{ #matchmediajs-test { width: 1px; } }";return b.styleSheet?b.styleSheet.cssText=c:b.textContent=c,"1px"===d.width}}}return function(b){return{matches:a.matchMedium(b||"all"),media:b||"all"}}}()),function(a,b,c){"use strict";function d(b){"object"==typeof module&&"object"==typeof module.exports?module.exports=b:"function"==typeof define&&define.amd&&define("picturefill",function(){return b}),"object"==typeof a&&(a.picturefill=b)}function e(a){var b,c,d,e,f,i=a||{};b=i.elements||g.getAllElements();for(var j=0,k=b.length;k>j;j++)if(c=b[j],d=c.parentNode,e=void 0,f=void 0,"IMG"===c.nodeName.toUpperCase()&&(c[g.ns]||(c[g.ns]={}),i.reevaluate||!c[g.ns].evaluated)){if(d&&"PICTURE"===d.nodeName.toUpperCase()){if(g.removeVideoShim(d),e=g.getMatch(c,d),e===!1)continue}else e=void 0;(d&&"PICTURE"===d.nodeName.toUpperCase()||!g.sizesSupported&&c.srcset&&h.test(c.srcset))&&g.dodgeSrcset(c),e?(f=g.processSourceSet(e),g.applyBestCandidate(f,c)):(f=g.processSourceSet(c),(void 0===c.srcset||c[g.ns].srcset)&&g.applyBestCandidate(f,c)),c[g.ns].evaluated=!0}}function f(){function c(){clearTimeout(d),d=setTimeout(h,60)}g.initTypeDetects(),e();var d,f=setInterval(function(){return e(),/^loaded|^i|^c/.test(b.readyState)?void clearInterval(f):void 0},250),h=function(){e({reevaluate:!0})};a.addEventListener?a.addEventListener("resize",c,!1):a.attachEvent&&a.attachEvent("onresize",c)}if(a.HTMLPictureElement)return void d(function(){});b.createElement("picture");var g=a.picturefill||{},h=/\s+\+?\d+(e\d+)?w/;g.ns="picturefill",function(){g.srcsetSupported="srcset"in c,g.sizesSupported="sizes"in c,g.curSrcSupported="currentSrc"in c}(),g.trim=function(a){return a.trim?a.trim():a.replace(/^\s+|\s+$/g,"")},g.makeUrl=function(){var a=b.createElement("a");return function(b){return a.href=b,a.href}}(),g.restrictsMixedContent=function(){return"https:"===a.location.protocol},g.matchesMedia=function(b){return a.matchMedia&&a.matchMedia(b).matches},g.getDpr=function(){return a.devicePixelRatio||1},g.getWidthFromLength=function(a){var c;if(!a||a.indexOf("%")>-1!=!1||!(parseFloat(a)>0||a.indexOf("calc(")>-1))return!1;a=a.replace("vw","%"),g.lengthEl||(g.lengthEl=b.createElement("div"),g.lengthEl.style.cssText="border:0;display:block;font-size:1em;left:0;margin:0;padding:0;position:absolute;visibility:hidden",g.lengthEl.className="helper-from-picturefill-js"),g.lengthEl.style.width="0px";try{g.lengthEl.style.width=a}catch(d){}return b.body.appendChild(g.lengthEl),c=g.lengthEl.offsetWidth,0>=c&&(c=!1),b.body.removeChild(g.lengthEl),c},g.detectTypeSupport=function(b,c){var d=new a.Image;return d.onerror=function(){g.types[b]=!1,e()},d.onload=function(){g.types[b]=1===d.width,e()},d.src=c,"pending"},g.types=g.types||{},g.initTypeDetects=function(){g.types["image/jpeg"]=!0,g.types["image/gif"]=!0,g.types["image/png"]=!0,g.types["image/svg+xml"]=b.implementation.hasFeature("http://www.w3.org/TR/SVG11/feature#Image","1.1"),g.types["image/webp"]=g.detectTypeSupport("image/webp","data:image/webp;base64,UklGRh4AAABXRUJQVlA4TBEAAAAvAAAAAAfQ//73v/+BiOh/AAA=")},g.verifyTypeSupport=function(a){var b=a.getAttribute("type");if(null===b||""===b)return!0;var c=g.types[b];return"string"==typeof c&&"pending"!==c?(g.types[b]=g.detectTypeSupport(b,c),"pending"):"function"==typeof c?(c(),"pending"):c},g.parseSize=function(a){var b=/(\([^)]+\))?\s*(.+)/g.exec(a);return{media:b&&b[1],length:b&&b[2]}},g.findWidthFromSourceSize=function(c){for(var d,e=g.trim(c).split(/\s*,\s*/),f=0,h=e.length;h>f;f++){var i=e[f],j=g.parseSize(i),k=j.length,l=j.media;if(k&&(!l||g.matchesMedia(l))&&(d=g.getWidthFromLength(k)))break}return d||Math.max(a.innerWidth||0,b.documentElement.clientWidth)},g.parseSrcset=function(a){for(var b=[];""!==a;){a=a.replace(/^\s+/g,"");var c,d=a.search(/\s/g),e=null;if(-1!==d){c=a.slice(0,d);var f=c.slice(-1);if((","===f||""===c)&&(c=c.replace(/,+$/,""),e=""),a=a.slice(d+1),null===e){var g=a.indexOf(",");-1!==g?(e=a.slice(0,g),a=a.slice(g+1)):(e=a,a="")}}else c=a,a="";(c||e)&&b.push({url:c,descriptor:e})}return b},g.parseDescriptor=function(a,b){var c,d=b||"100vw",e=a&&a.replace(/(^\s+|\s+$)/g,""),f=g.findWidthFromSourceSize(d);if(e)for(var h=e.split(" "),i=h.length-1;i>=0;i--){var j=h[i],k=j&&j.slice(j.length-1);if("h"!==k&&"w"!==k||g.sizesSupported){if("x"===k){var l=j&&parseFloat(j,10);c=l&&!isNaN(l)?l:1}}else c=parseFloat(parseInt(j,10)/f)}return c||1},g.getCandidatesFromSourceSet=function(a,b){for(var c=g.parseSrcset(a),d=[],e=0,f=c.length;f>e;e++){var h=c[e];d.push({url:h.url,resolution:g.parseDescriptor(h.descriptor,b)})}return d},g.dodgeSrcset=function(a){a.srcset&&(a[g.ns].srcset=a.srcset,a.srcset="",a.setAttribute("data-pfsrcset",a[g.ns].srcset))},g.processSourceSet=function(a){var b=a.getAttribute("srcset"),c=a.getAttribute("sizes"),d=[];return"IMG"===a.nodeName.toUpperCase()&&a[g.ns]&&a[g.ns].srcset&&(b=a[g.ns].srcset),b&&(d=g.getCandidatesFromSourceSet(b,c)),d},g.backfaceVisibilityFix=function(a){var b=a.style||{},c="webkitBackfaceVisibility"in b,d=b.zoom;c&&(b.zoom=".999",c=a.offsetWidth,b.zoom=d)},g.setIntrinsicSize=function(){var c={},d=function(a,b,c){b&&a.setAttribute("width",parseInt(b/c,10))};return function(e,f){var h;e[g.ns]&&!a.pfStopIntrinsicSize&&(void 0===e[g.ns].dims&&(e[g.ns].dims=e.getAttribute("width")||e.getAttribute("height")),e[g.ns].dims||(f.url in c?d(e,c[f.url],f.resolution):(h=b.createElement("img"),h.onload=function(){if(c[f.url]=h.width,!c[f.url])try{b.body.appendChild(h),c[f.url]=h.width||h.offsetWidth,b.body.removeChild(h)}catch(a){}e.src===f.url&&d(e,c[f.url],f.resolution),e=null,h.onload=null,h=null},h.src=f.url)))}}(),g.applyBestCandidate=function(a,b){var c,d,e;a.sort(g.ascendingSort),d=a.length,e=a[d-1];for(var f=0;d>f;f++)if(c=a[f],c.resolution>=g.getDpr()){e=c;break}e&&(e.url=g.makeUrl(e.url),b.src!==e.url&&(g.restrictsMixedContent()&&"http:"===e.url.substr(0,"http:".length).toLowerCase()?void 0!==window.console&&console.warn("Blocked mixed content image "+e.url):(b.src=e.url,g.curSrcSupported||(b.currentSrc=b.src),g.backfaceVisibilityFix(b))),g.setIntrinsicSize(b,e))},g.ascendingSort=function(a,b){return a.resolution-b.resolution},g.removeVideoShim=function(a){var b=a.getElementsByTagName("video");if(b.length){for(var c=b[0],d=c.getElementsByTagName("source");d.length;)a.insertBefore(d[0],c);c.parentNode.removeChild(c)}},g.getAllElements=function(){for(var a=[],c=b.getElementsByTagName("img"),d=0,e=c.length;e>d;d++){var f=c[d];("PICTURE"===f.parentNode.nodeName.toUpperCase()||null!==f.getAttribute("srcset")||f[g.ns]&&null!==f[g.ns].srcset)&&a.push(f)}return a},g.getMatch=function(a,b){for(var c,d=b.childNodes,e=0,f=d.length;f>e;e++){var h=d[e];if(1===h.nodeType){if(h===a)return c;if("SOURCE"===h.nodeName.toUpperCase()){null!==h.getAttribute("src")&&void 0!==typeof console&&console.warn("The `src` attribute is invalid on `picture` `source` element; instead, use `srcset`.");var i=h.getAttribute("media");if(h.getAttribute("srcset")&&(!i||g.matchesMedia(i))){var j=g.verifyTypeSupport(h);if(j===!0){c=h;break}if("pending"===j)return!1}}}}return c},f(),e._=g,d(e)}(window,window.document,new window.Image); diff --git a/wp-tevko-responsive-images.php b/wp-tevko-responsive-images.php index a74972c..2105a5f 100644 --- a/wp-tevko-responsive-images.php +++ b/wp-tevko-responsive-images.php @@ -25,7 +25,7 @@ * Enqueue bundled version of the Picturefill library. */ function tevkori_get_picturefill() { - wp_enqueue_script( 'picturefill', plugins_url( 'js/picturefill.min.js', __FILE__ ), array(), '2.3.0', true ); + wp_enqueue_script( 'picturefill', plugins_url( 'js/picturefill.min.js', __FILE__ ), array(), '2.3.1', true ); } add_action( 'wp_enqueue_scripts', 'tevkori_get_picturefill' ); @@ -44,7 +44,7 @@ function tevkori_get_picturefill() { * @return string|bool A valid source size value for use in a 'sizes' attribute or false. */ function tevkori_get_sizes( $id, $size = 'thumbnail', $args = null ) { - + // See which image is being returned and bail if none is found. if ( ! $img = image_downsize( $id, $size ) ) { return false; From 828bac4d09309456b06bfa2feb70e829e1a0d032 Mon Sep 17 00:00:00 2001 From: fsylum Date: Sat, 16 May 2015 09:54:05 +0800 Subject: [PATCH 20/28] Use native wp_send_json to send the output --- wp-tevko-responsive-images.php | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/wp-tevko-responsive-images.php b/wp-tevko-responsive-images.php index 23f25ff..aa6ce5c 100644 --- a/wp-tevko-responsive-images.php +++ b/wp-tevko-responsive-images.php @@ -374,7 +374,6 @@ function tevkori_ajax_srcset() { $srcset = tevkori_get_srcset( $postID, $size ); // For AJAX requests, we echo the result and then die. - echo $srcset; - die(); + wp_send_json( $srcset ); } add_action( 'wp_ajax_tevkori_ajax_srcset', 'tevkori_ajax_srcset' ); From 88e5a06941bfa8e21e533051d77a69a973d1c710 Mon Sep 17 00:00:00 2001 From: fsylum Date: Sat, 16 May 2015 10:43:21 +0800 Subject: [PATCH 21/28] Fix accepted args count --- wp-tevko-responsive-images.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wp-tevko-responsive-images.php b/wp-tevko-responsive-images.php index aa6ce5c..e421965 100644 --- a/wp-tevko-responsive-images.php +++ b/wp-tevko-responsive-images.php @@ -295,7 +295,7 @@ function tevkori_filter_attachment_image_attributes( $attr, $attachment, $size ) return $attr; } -add_filter( 'wp_get_attachment_image_attributes', 'tevkori_filter_attachment_image_attributes', 0, 4 ); +add_filter( 'wp_get_attachment_image_attributes', 'tevkori_filter_attachment_image_attributes', 0, 3 ); /** * Disable the editor size constraint applied for images in TinyMCE. From a9002c45785bf34139bbbaa5c5097c85020df927 Mon Sep 17 00:00:00 2001 From: fsylum Date: Sat, 16 May 2015 10:43:58 +0800 Subject: [PATCH 22/28] Add missing semicolon --- js/wp-tevko-responsive-images.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/js/wp-tevko-responsive-images.js b/js/wp-tevko-responsive-images.js index 880ea97..77ccc7a 100644 --- a/js/wp-tevko-responsive-images.js +++ b/js/wp-tevko-responsive-images.js @@ -36,7 +36,7 @@ jQuery.post( ajaxurl, data, function( response ) { image.setAttribute( 'srcset', response ); }); - } + }; /** * Update the data-sizes attribute on an image in the editor @@ -47,7 +47,7 @@ // Update the sizes attribute of our image. image.setAttribute( 'data-sizes', sizes ); - } + }; })(); From d778e1cf4f32498f47f1c3abb5e5ba8ead6938fc Mon Sep 17 00:00:00 2001 From: Tim Evko Date: Sun, 17 May 2015 17:59:48 -0400 Subject: [PATCH 23/28] add 2.3 changelog --- readme.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/readme.md b/readme.md index adbf34a..31a1ce7 100644 --- a/readme.md +++ b/readme.md @@ -137,6 +137,12 @@ We use a hook because if you attempt to dequeue a script before it's enqueued, w - Improved performance of `get_srcset_array` - Added smart sizes option (available by adding hook to functions.php) +- Duplicate entires now filtered out from srcset array +- Upgrade picturefill to 2.3.1 +- Refactoring plugin JS, including a switch to ajax for updating the srcset value when the image is changed in the editor +- Now using wp_get_attachment_image_attributes filter for post thumbnails +- Readme and other general code typo fixes +- Gallery images will now contain a srcset attribute **2.2.1** From dabc346f933c4b7950fd5779d5e0cabd5840b8f6 Mon Sep 17 00:00:00 2001 From: Tim Evko Date: Sun, 17 May 2015 18:01:56 -0400 Subject: [PATCH 24/28] update to v2.3.0 --- wp-tevko-responsive-images.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wp-tevko-responsive-images.php b/wp-tevko-responsive-images.php index e421965..96e1f88 100644 --- a/wp-tevko-responsive-images.php +++ b/wp-tevko-responsive-images.php @@ -10,7 +10,7 @@ * Plugin Name: RICG Responsive Images * Plugin URI: http://www.smashingmagazine.com/2015/02/24/ricg-responsive-images-for-wordpress/ * Description: Bringing automatic default responsive images to wordpress - * Version: 2.2.1 + * Version: 2.3.0 * Author: The RICG * Author URI: http://responsiveimages.org/ * License: GPL-2.0+ From 2a0831668e9c8b2be1456cb7da087ef15c3aca48 Mon Sep 17 00:00:00 2001 From: Tim Evko Date: Sun, 17 May 2015 18:06:11 -0400 Subject: [PATCH 25/28] verbiage less confusing --- readme.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/readme.md b/readme.md index 31a1ce7..3b0ca16 100644 --- a/readme.md +++ b/readme.md @@ -136,7 +136,7 @@ We use a hook because if you attempt to dequeue a script before it's enqueued, w ##Changelog - Improved performance of `get_srcset_array` -- Added smart sizes option (available by adding hook to functions.php) +- Added advanced image compresson option (available by adding hook to functions.php) - Duplicate entires now filtered out from srcset array - Upgrade picturefill to 2.3.1 - Refactoring plugin JS, including a switch to ajax for updating the srcset value when the image is changed in the editor From 636f237ad4d9ae3ed5a449aed6c85ad0819fa8a5 Mon Sep 17 00:00:00 2001 From: Tim Evko Date: Sun, 17 May 2015 18:06:34 -0400 Subject: [PATCH 26/28] verbiage less confusing --- readme.txt | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/readme.txt b/readme.txt index 571e118..92958ca 100644 --- a/readme.txt +++ b/readme.txt @@ -4,7 +4,7 @@ Donate link: https://app.etapestry.com/hosted/BoweryResidentsCommittee/OnlineDon Tags: Responsive, Images, Responsive Images, SRCSET, Picturefill Requires at least: 4.1 Tested up to: 4.1 -Stable tag: 2.2.1 +Stable tag: 2.3.0 License: GPLv2 License URI: http://www.gnu.org/licenses/gpl-2.0.txt @@ -22,8 +22,19 @@ This plugin works by including all available image sizes for each image upload. 1. Upload `plugin-name.php` to the `/wp-content/plugins/` directory 2. Activate the plugin through the 'Plugins' menu in WordPress +3. If you'd like to enable the advanced image compression feature, Please see the instructions at https://github.com/ResponsiveImagesCG/wp-tevko-responsive-images/tree/dev#advanced-image-compression == Changelog == += 2.3.0 +* Improved performance of get_srcset_array +* Added advanced image compression option (available by adding hook to functions.php) +* Duplicate entires now filtered out from srcset array +* Upgrade picturefill to 2.3.1 +* Refactoring plugin JS, including a switch to ajax for updating the srcset value when the image is changed in the editor +* Now using wp_get_attachment_image_attributes filter for post thumbnails +* Readme and other general code typo fixes +* Gallery images will now contain a srcset attribute + = 2.2.1 = * Patch fixing missing javascript error From 5e961c74872785c3b44b41a37770d640e7e3cc5a Mon Sep 17 00:00:00 2001 From: Tim Evko Date: Sun, 17 May 2015 21:41:43 -0400 Subject: [PATCH 27/28] dumb typo fixes --- readme.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/readme.md b/readme.md index 3b0ca16..0b8c5cc 100644 --- a/readme.md +++ b/readme.md @@ -136,9 +136,9 @@ We use a hook because if you attempt to dequeue a script before it's enqueued, w ##Changelog - Improved performance of `get_srcset_array` -- Added advanced image compresson option (available by adding hook to functions.php) +- Added advanced image compression option (available by adding hook to functions.php) - Duplicate entires now filtered out from srcset array -- Upgrade picturefill to 2.3.1 +- Upgrade Picturefill to 2.3.1 - Refactoring plugin JS, including a switch to ajax for updating the srcset value when the image is changed in the editor - Now using wp_get_attachment_image_attributes filter for post thumbnails - Readme and other general code typo fixes @@ -146,7 +146,7 @@ We use a hook because if you attempt to dequeue a script before it's enqueued, w **2.2.1** -- JS patch for wordpress +- JS patch for WordPress **2.2.0** From aa517f73662888f017f18d029a9eb4a1a371a859 Mon Sep 17 00:00:00 2001 From: Tim Evko Date: Sun, 17 May 2015 21:43:06 -0400 Subject: [PATCH 28/28] capitalizing Picturefill --- readme.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/readme.txt b/readme.txt index 92958ca..d390954 100644 --- a/readme.txt +++ b/readme.txt @@ -29,7 +29,7 @@ This plugin works by including all available image sizes for each image upload. * Improved performance of get_srcset_array * Added advanced image compression option (available by adding hook to functions.php) * Duplicate entires now filtered out from srcset array -* Upgrade picturefill to 2.3.1 +* Upgrade Picturefill to 2.3.1 * Refactoring plugin JS, including a switch to ajax for updating the srcset value when the image is changed in the editor * Now using wp_get_attachment_image_attributes filter for post thumbnails * Readme and other general code typo fixes