WordPress.org

Make WordPress Core

Ticket #36982: media-srcset-sizes.2.patch

File media-srcset-sizes.2.patch, 13.3 KB (added by kylereicks, 4 years ago)

Update patch to remove the "context" attribute. Add a test to make sure that srcsets and sizes can be successfully updated via filters.

  • src/wp-includes/media.php

     
    893893
    894894                        if ( is_array( $image_meta ) ) {
    895895                                $size_array = array( absint( $width ), absint( $height ) );
    896                                 $srcset = wp_calculate_image_srcset( $size_array, $src, $image_meta, $attachment_id );
    897                                 $sizes = wp_calculate_image_sizes( $size_array, $src, $image_meta, $attachment_id );
     896                                $srcset = wp_calculate_image_srcset( $size_array, $src, $image_meta, $attachment_id, $attr );
     897                                $sizes = wp_calculate_image_sizes( $size_array, $src, $image_meta, $attachment_id, $attr );
    898898
    899899                                if ( $srcset && ( $sizes || ! empty( $attr['sizes'] ) ) ) {
    900900                                        $attr['srcset'] = $srcset;
     
    10101010 *                                    width and height values in pixels (in that order). Default 'medium'.
    10111011 * @param array        $image_meta    Optional. The image meta data as returned by 'wp_get_attachment_metadata()'.
    10121012 *                                    Default null.
     1013 * @param array        $image_attr    Optional. An array of image attributes to be passed to 'wp_calculate_image_srcset()'.
    10131014 * @return string|bool A 'srcset' value string or false.
    10141015 */
    1015 function wp_get_attachment_image_srcset( $attachment_id, $size = 'medium', $image_meta = null ) {
     1016function wp_get_attachment_image_srcset( $attachment_id, $size = 'medium', $image_meta = null, $image_attr = array() ) {
    10161017        if ( ! $image = wp_get_attachment_image_src( $attachment_id, $size ) ) {
    10171018                return false;
    10181019        }
     
    10271028                absint( $image[2] )
    10281029        );
    10291030
    1030         return wp_calculate_image_srcset( $size_array, $image_src, $image_meta, $attachment_id );
     1031        return wp_calculate_image_srcset( $size_array, $image_src, $image_meta, $attachment_id, $image_attr );
    10311032}
    10321033
    10331034/**
     
    10391040 * @param string $image_src     The 'src' of the image.
    10401041 * @param array  $image_meta    The image meta data as returned by 'wp_get_attachment_metadata()'.
    10411042 * @param int    $attachment_id Optional. The image attachment ID to pass to the filter. Default 0.
     1043 * @param array  $image_attr    Optional. Image attributes.
    10421044 * @return string|bool          The 'srcset' attribute value. False on error or when only one source exists.
    10431045 */
    1044 function wp_calculate_image_srcset( $size_array, $image_src, $image_meta, $attachment_id = 0 ) {
     1046function wp_calculate_image_srcset( $size_array, $image_src, $image_meta, $attachment_id = 0, $image_attr = array() ) {
    10451047        /**
    10461048         * Let plugins pre-filter the image meta to be able to fix inconsistencies in the stored data.
    10471049         *
     
    11991201         * @param string $image_src     The 'src' of the image.
    12001202         * @param array  $image_meta    The image meta data as returned by 'wp_get_attachment_metadata()'.
    12011203         * @param int    $attachment_id Image attachment ID or 0.
     1204         * @param array  $image_attr    Image attributes.
    12021205         */
    1203         $sources = apply_filters( 'wp_calculate_image_srcset', $sources, $size_array, $image_src, $image_meta, $attachment_id );
     1206        $sources = apply_filters( 'wp_calculate_image_srcset', $sources, $size_array, $image_src, $image_meta, $attachment_id, $image_attr );
    12041207
    12051208        // Only return a 'srcset' value if there is more than one source.
    12061209        if ( ! $src_matched || count( $sources ) < 2 ) {
     
    12281231 *                                    and height values in pixels (in that order). Default 'medium'.
    12291232 * @param array        $image_meta    Optional. The image meta data as returned by 'wp_get_attachment_metadata()'.
    12301233 *                                    Default null.
     1234 * @param array        $image_attr    Optional. An array of image attributes to be passed to 'wp_calculate_image_sizes()'.
    12311235 * @return string|bool A valid source size value for use in a 'sizes' attribute or false.
    12321236 */
    1233 function wp_get_attachment_image_sizes( $attachment_id, $size = 'medium', $image_meta = null ) {
     1237function wp_get_attachment_image_sizes( $attachment_id, $size = 'medium', $image_meta = null, $image_attr = array() ) {
    12341238        if ( ! $image = wp_get_attachment_image_src( $attachment_id, $size ) ) {
    12351239                return false;
    12361240        }
     
    12451249                absint( $image[2] )
    12461250        );
    12471251
    1248         return wp_calculate_image_sizes( $size_array, $image_src, $image_meta, $attachment_id );
     1252        return wp_calculate_image_sizes( $size_array, $image_src, $image_meta, $attachment_id, $image_attr );
    12491253}
    12501254
    12511255/**
     
    12601264 *                                    Default null.
    12611265 * @param int          $attachment_id Optional. Image attachment ID. Either `$image_meta` or `$attachment_id`
    12621266 *                                    is needed when using the image size name as argument for `$size`. Default 0.
     1267 * @param array        $image_attr    Optional. Image attributes.
    12631268 * @return string|bool A valid source size value for use in a 'sizes' attribute or false.
    12641269 */
    1265 function wp_calculate_image_sizes( $size, $image_src = null, $image_meta = null, $attachment_id = 0 ) {
     1270function wp_calculate_image_sizes( $size, $image_src = null, $image_meta = null, $attachment_id = 0, $image_attr = array() ) {
    12661271        $width = 0;
    12671272
    12681273        if ( is_array( $size ) ) {
     
    12971302         *                                    in pixels (in that order).
    12981303         * @param string|null  $image_src     The URL to the image file or null.
    12991304         * @param array|null   $image_meta    The image meta data as returned by wp_get_attachment_metadata() or null.
     1305         * @param array        $image_attr    Image attributes.
    13001306         * @param int          $attachment_id Image attachment ID of the original image or 0.
    13011307         */
    1302         return apply_filters( 'wp_calculate_image_sizes', $sizes, $size, $image_src, $image_meta, $attachment_id );
     1308        return apply_filters( 'wp_calculate_image_sizes', $sizes, $size, $image_src, $image_meta, $attachment_id, $image_attr );
    13031309}
    13041310
    13051311/**
     
    14141420        }
    14151421
    14161422        $size_array = array( $width, $height );
    1417         $srcset = wp_calculate_image_srcset( $size_array, $image_src, $image_meta, $attachment_id );
     1423        $image_attr = preg_match_all( '/\s([\w-]+)([=\s]([\'\"])((?!\3).+?[^\\\])\3)?/', $image, $match_attr ) ? array_combine( array_map( 'esc_attr', $match_attr[1] ), array_map( 'esc_attr', $match_attr[4] ) ) : array();
     1424        $srcset = wp_calculate_image_srcset( $size_array, $image_src, $image_meta, $attachment_id, $image_attr );
    14181425
    14191426        if ( $srcset ) {
    14201427                // Check if there is already a 'sizes' attribute.
     
    14211428                $sizes = strpos( $image, ' sizes=' );
    14221429
    14231430                if ( ! $sizes ) {
    1424                         $sizes = wp_calculate_image_sizes( $size_array, $image_src, $image_meta, $attachment_id );
     1431                        $sizes = wp_calculate_image_sizes( $size_array, $image_src, $image_meta, $attachment_id, $image_attr );
    14251432                }
    14261433        }
    14271434
  • tests/phpunit/tests/media.php

     
    20622062                $attachment_id = wp_insert_attachment( $data, '', 0 );
    20632063                $this->assertSame( 0, $attachment_id );
    20642064        }
     2065
     2066        /**
     2067         * @ticket 36982
     2068         */
     2069        public function test_filter_image_srcset_and_sizes_by_image_attributes() {
     2070
     2071                $image_meta = wp_get_attachment_metadata( self::$large_id );
     2072                $class_attribute_string = 'test-class-string test-image-full';
     2073
     2074                // Add a filter to remove srcset and sizes from the generated image.
     2075                add_filter( 'wp_calculate_image_srcset', '__return_false' );
     2076                add_filter( 'wp_calculate_image_sizes', '__return_false' );
     2077
     2078                $image_with_class_attribute_no_srcset_sizes = wp_get_attachment_image( self::$large_id, 'full', false, array( 'class' => $class_attribute_string, 'alt' => 'Full size test image' ) );
     2079                $image_without_class_attribute_no_srcset_sizes = wp_get_attachment_image( self::$large_id, 'full', false, array( 'class' => '', 'alt' => 'Full size test image' ) );
     2080
     2081                // Remove the filter to restore srcset and sizes from the generated image.
     2082                remove_filter( 'wp_calculate_image_srcset', '__return_false' );
     2083                remove_filter( 'wp_calculate_image_sizes', '__return_false' );
     2084
     2085                $default_image_without_class_attribute = wp_get_attachment_image( self::$large_id, 'full', false, array( 'class' => '', 'alt' => 'Full size test image' ) );
     2086                $default_srcset_string_without_class_attribute = wp_get_attachment_image_srcset( self::$large_id, 'full', false, array( 'class' => '', 'alt' => 'Full size test image' ) );
     2087                $default_sizes_string_without_class_attribute = wp_get_attachment_image_sizes( self::$large_id, 'full', false, array( 'class' => '', 'alt' => 'Full size test image' ) );
     2088
     2089                // Filter the srcset and sizes values.
     2090                add_filter( 'wp_calculate_image_srcset', array( $this, '_filter_36982_srcset' ), 10, 6 );
     2091                add_filter( 'wp_calculate_image_sizes', array( $this, '_filter_36982_sizes' ), 10, 6 );
     2092
     2093                // Generate an image with srcset and sizes values that should match the filtered image.
     2094                $uploads_dir_url = 'http://' . WP_TESTS_DOMAIN . '/wp-content/uploads/';
     2095                $image_file_date_dir = preg_replace( '/(\d{4}\/\d{2}\/).+/', '$1', $image_meta['file'] );
     2096
     2097                // Set sources that will match the filtered values.
     2098                $expected_sources = array(
     2099                        $image_meta['width'] => array(
     2100                                'url' => $uploads_dir_url . $image_meta['file'],
     2101                                'descriptor' => 'w',
     2102                                'value' => $image_meta['width'],
     2103                                'width' => $image_meta['width'],
     2104                                'height' => $image_meta['height'],
     2105                        ),
     2106                );
     2107
     2108                foreach( $image_meta['sizes'] as $size ) {
     2109                        $expected_sources[ $size['width'] ] = array(
     2110                                'url' => $uploads_dir_url . $image_file_date_dir . $size['file'],
     2111                                'descriptor' => 'w',
     2112                                'value' => $size['width'],
     2113                                'width' => $size['width'],
     2114                                'height' => $size['height'],
     2115                        );
     2116                }
     2117
     2118                $expected_sources = array_slice( array_filter( array_map( function( $source, $image_meta ) {
     2119                        if ( ! wp_image_matches_ratio( $image_meta['width'], $image_meta['height'], $source['width'], $source['height'] ) || $source['value'] > apply_filters( 'max_srcset_image_width', 1600, array( $image_meta['width'], $image_meta['height'] ) ) ) {
     2120                                return false;
     2121                        }
     2122                        return $source['url'] . ' ' . $source['value'] . $source['descriptor'];
     2123                }, $expected_sources, array_fill( 0, count( $expected_sources ), $image_meta ) ) ), 2 );
     2124
     2125                // Set a sizes sting value that will match the arbitrary value set in the filter.
     2126                $expected_sizes_string = sprintf( '(max-width: %1$dpx) 100vw, %1$dpx', 9999 );
     2127
     2128                $expected_image = '<img width="' . $image_meta['width'] . '" height="' . $image_meta['height'] . '" src="' . $uploads_dir_url . $image_meta['file'] . '" class="' . $class_attribute_string . '" alt="Full size test image" srcset="' . implode( ', ', $expected_sources ) . '" sizes="' . $expected_sizes_string . '" />';
     2129
     2130                // Images without a class attribute that will match the test filter. Should match the default image with unfiltered srcset and sizes values.
     2131                $this->assertSame( $default_image_without_class_attribute, wp_get_attachment_image( self::$large_id, 'full', false, array( 'class' => '', 'alt' => 'Full size test image' ) ) );
     2132                $this->assertSame( $default_image_without_class_attribute, wp_image_add_srcset_and_sizes( $image_without_class_attribute_no_srcset_sizes, $image_meta, self::$large_id ) );
     2133
     2134                // Images with a class attribute that will match the test filter. Should match the expected image with filtered srcset and sizes values.
     2135                $this->assertSame( $expected_image, wp_image_add_srcset_and_sizes( $image_with_class_attribute_no_srcset_sizes, $image_meta, self::$large_id ) );
     2136                $this->assertSame( $expected_image, wp_get_attachment_image( self::$large_id, 'full', false, array( 'class' => $class_attribute_string, 'alt' => 'Full size test image' ) ) );
     2137
     2138                // Srcset and sizes strings with class attribute string. Should match the filtered string.
     2139                $this->assertSame( implode( ', ', $expected_sources ), wp_get_attachment_image_srcset( self::$large_id, 'full', false, array( 'class' => $class_attribute_string, 'alt' => 'Full size test image' ) ) );
     2140                $this->assertSame( $expected_sizes_string, wp_get_attachment_image_sizes( self::$large_id, 'full', false, array( 'class' => $class_attribute_string, 'alt' => 'Full size test image' ) ) );
     2141
     2142                // Srcset and sizes strings without class attribute string. Should match the unfiltered default string.
     2143                $this->assertSame( $default_srcset_string_without_class_attribute, wp_get_attachment_image_srcset( self::$large_id, 'full', false, array( 'class' => '', 'alt' => 'Full size test image' ) ) );
     2144                $this->assertSame( $default_sizes_string_without_class_attribute, wp_get_attachment_image_sizes( self::$large_id, 'full', false, array( 'class' => '', 'alt' => 'Full size test image' ) ) );
     2145
     2146
     2147        }
     2148
     2149        public function _filter_36982_srcset( $sources, $size_array, $image_src, $image_meta, $attachment_id, $image_attr ) {
     2150
     2151                if ( empty( $image_attr ) ) {
     2152                        return $sources;
     2153                }
     2154
     2155                if ( empty( $image_attr['class'] ) ) {
     2156                        return $sources;
     2157                }
     2158
     2159                $class_array = explode( ' ', $image_attr['class'] );
     2160
     2161                if ( in_array( 'test-image-full', $class_array, true ) ) {
     2162                        return array_slice( $sources, 2 );
     2163                }
     2164
     2165                return $sources;
     2166        }
     2167        public function _filter_36982_sizes( $sizes, $size_array, $image_src, $image_meta, $attachment_id, $image_attr ) {
     2168
     2169                if ( empty( $image_attr ) ) {
     2170                        return $sizes;
     2171                }
     2172
     2173                if ( empty( $image_attr['class'] ) ) {
     2174                        return $sizes;
     2175                }
     2176
     2177                $class_array = explode( ' ', $image_attr['class'] );
     2178
     2179                if ( in_array( 'test-image-full', $class_array, true ) ) {
     2180                        return sprintf( '(max-width: %1$dpx) 100vw, %1$dpx', 9999 );
     2181                }
     2182
     2183                return $sizes;
     2184        }
    20652185}
    20662186
    20672187/**