diff --git a/src/wp-includes/media.php b/src/wp-includes/media.php index 93d1c269d1..f9b41311c2 100644 --- a/src/wp-includes/media.php +++ b/src/wp-includes/media.php @@ -1491,11 +1491,42 @@ function wp_calculate_image_sizes( $size, $image_src = null, $image_meta = null, return apply_filters( 'wp_calculate_image_sizes', $sizes, $size, $image_src, $image_meta, $attachment_id ); } +/** + * Determines an image's width and height dimensions based on the source file. + * + * @since 5.5.0 + * + * @param string $image_src The image source file. + * @param array $image_meta The image meta data as returned by 'wp_get_attachment_metadata()'. + * @return array|false Array with first element being the width and second element being the height, + * or false if dimensions cannot be determined. + */ +function wp_image_src_get_dimensions( $image_src, $image_meta ) { + $image_filename = wp_basename( $image_src ); + + if ( wp_basename( $image_meta['file'] ) === $image_filename ) { + return array( + (int) $image_meta['width'], + (int) $image_meta['height'], + ); + } + + foreach ( $image_meta['sizes'] as $image_size_data ) { + if ( $image_filename === $image_size_data['file'] ) { + return array( + (int) $image_size_data['width'], + (int) $image_size_data['height'], + ); + } + } + + return false; +} + /** * Adds 'srcset' and 'sizes' attributes to an existing 'img' element. * * @since 4.4.0 - * @since 5.5.0 `width` and `height` are now added if not already present. * * @see wp_calculate_image_srcset() * @see wp_calculate_image_sizes() @@ -1526,41 +1557,19 @@ function wp_image_add_srcset_and_sizes( $image, $image_meta, $attachment_id ) { return $image; } - $attr = ''; - $width = preg_match( '/ width="([0-9]+)"/', $image, $match_width ) ? (int) $match_width[1] : 0; $height = preg_match( '/ height="([0-9]+)"/', $image, $match_height ) ? (int) $match_height[1] : 0; - if ( ! $width || ! $height ) { - /* - * If attempts to parse the size value failed, attempt to use the image meta data to match - * the image file name from 'src' against the available sizes for an attachment. - */ - $image_filename = wp_basename( $image_src ); - - if ( wp_basename( $image_meta['file'] ) === $image_filename ) { - $width = (int) $image_meta['width']; - $height = (int) $image_meta['height']; - } else { - foreach ( $image_meta['sizes'] as $image_size_data ) { - if ( $image_filename === $image_size_data['file'] ) { - $width = (int) $image_size_data['width']; - $height = (int) $image_size_data['height']; - break; - } - } - } - - if ( ! $width || ! $height ) { + if ( $width && $height ) { + $size_array = array( $width, $height ); + } else { + $size_array = wp_image_src_get_dimensions( $image_src, $image_meta ); + if ( ! $size_array ) { return $image; } - - // Add width and height if not present. - $attr .= ' ' . trim( image_hwstring( $width, $height ) ); } - $size_array = array( $width, $height ); - $srcset = wp_calculate_image_srcset( $size_array, $image_src, $image_meta, $attachment_id ); + $srcset = wp_calculate_image_srcset( $size_array, $image_src, $image_meta, $attachment_id ); if ( $srcset ) { // Check if there is already a 'sizes' attribute. @@ -1573,19 +1582,17 @@ function wp_image_add_srcset_and_sizes( $image, $image_meta, $attachment_id ) { if ( $srcset && $sizes ) { // Format the 'srcset' and 'sizes' string and escape attributes. - $attr .= sprintf( ' srcset="%s"', esc_attr( $srcset ) ); + $attr = sprintf( ' srcset="%s"', esc_attr( $srcset ) ); if ( is_string( $sizes ) ) { $attr .= sprintf( ' sizes="%s"', esc_attr( $sizes ) ); } + + // Add extra attributes to the image markup. + return preg_replace( '/]+?)[\/ ]*>/', '', $image ); } - if ( empty( $attr ) ) { - return $image; - } - - // Add extra attributes to the image markup. - return preg_replace( '/]+?)[\/ ]*>/', '', $image ); + return $image; } /** @@ -1621,8 +1628,9 @@ function wp_lazy_loading_enabled( $tag_name, $context ) { * * @since 5.5.0 * - * @see wp_img_tag_add_loading_attr() + * @see wp_img_tag_add_width_and_height_attr() * @see wp_img_tag_add_srcset_and_sizes_attr() + * @see wp_img_tag_add_loading_attr() * * @param string $content The HTML content to be filtered. * @param string $context Optional. Additional context to pass to the filters. @@ -1676,6 +1684,11 @@ function wp_filter_content_tags( $content, $context = null ) { foreach ( $images as $image => $attachment_id ) { $filtered_image = $image; + // Add 'width' and 'height' attributes if applicable. + if ( $attachment_id > 0 && false === strpos( $filtered_image, ' width=' ) && false === strpos( $filtered_image, ' height=' ) ) { + $filtered_image = wp_img_tag_add_width_and_height_attr( $filtered_image, $context, $attachment_id ); + } + // Add 'srcset' and 'sizes' attributes if applicable. if ( $attachment_id > 0 && false === strpos( $filtered_image, ' srcset=' ) ) { $filtered_image = wp_img_tag_add_srcset_and_sizes_attr( $filtered_image, $context, $attachment_id ); @@ -1723,25 +1736,57 @@ function wp_img_tag_add_loading_attr( $image, $context ) { $value = 'lazy'; } - // Images should have dimension attributes for the `loading` attribute to be added. - if ( false === strpos( $image, ' width=' ) || false === strpos( $image, ' height=' ) ) { + // Images should have source and dimension attributes for the `loading` attribute to be added. + if ( false === strpos( $image, ' src=' ) || false === strpos( $image, ' width=' ) || false === strpos( $image, ' height=' ) ) { return $image; } - $quote = null; + return str_replace( '_get_image_size_array_from_meta( $image_meta, 'medium' ); @@ -1974,7 +1973,6 @@ EOF; // Function used to build HTML for the editor. $img = get_image_tag( self::$large_id, '', '', '', 'medium' ); - $img = wp_img_tag_add_loading_attr( $img, 'test' ); $img_no_size_in_class = str_replace( 'size-', '', $img ); $img_no_width_height = str_replace( ' width="' . $size_array[0] . '"', '', $img ); $img_no_width_height = str_replace( ' height="' . $size_array[1] . '"', '', $img_no_width_height ); @@ -1983,12 +1981,10 @@ EOF; $img_xhtml = str_replace( ' />', '/>', $img ); $img_html5 = str_replace( ' />', '>', $img ); - $hwstring = image_hwstring( $size_array[0], $size_array[1] ); - // Manually add srcset and sizes to the markup from get_image_tag(). $respimg = preg_replace( '|]+) />|', '', $img ); $respimg_no_size_in_class = preg_replace( '|]+) />|', '', $img_no_size_in_class ); - $respimg_no_width_height = preg_replace( '|]+) />|', '', $img_no_width_height ); + $respimg_no_width_height = preg_replace( '|]+) />|', '', $img_no_width_height ); $respimg_with_sizes_attr = preg_replace( '|]+) />|', '', $img_with_sizes_attr ); $respimg_xhtml = preg_replace( '|]+)/>|', '', $img_xhtml ); $respimg_html5 = preg_replace( '|]+)>|', '', $img_html5 ); @@ -2000,7 +1996,7 @@ EOF;

Image, no size class. Should have srcset and sizes.

%2$s -

Image, no width and height attributes. Should have width, height, srcset and sizes (from matching the file name).

+

Image, no width and height attributes. Should have srcset and sizes (from matching the file name).

%3$s

Image, no attachment ID class. Should NOT have srcset and sizes.

@@ -2018,7 +2014,14 @@ EOF; $content_unfiltered = sprintf( $content, $img, $img_no_size_in_class, $img_no_width_height, $img_no_size_id, $img_with_sizes_attr, $img_xhtml, $img_html5 ); $content_filtered = sprintf( $content, $respimg, $respimg_no_size_in_class, $respimg_no_width_height, $img_no_size_id, $respimg_with_sizes_attr, $respimg_xhtml, $respimg_html5 ); + // Do not add width, height, and loading. + add_filter( 'wp_img_tag_add_width_and_height_attr', '__return_false' ); + add_filter( 'wp_img_tag_add_loading_attr', '__return_false' ); + $this->assertSame( $content_filtered, wp_filter_content_tags( $content_unfiltered ) ); + + remove_filter( 'wp_img_tag_add_width_and_height_attr', '__return_false' ); + remove_filter( 'wp_img_tag_add_loading_attr', '__return_false' ); } /** @@ -2032,7 +2035,7 @@ EOF; * @ticket 34898 * @ticket 33641 */ - function test_wp_filter_content_tags_wrong() { + function test_wp_filter_content_tags_srcset_sizes_wrong() { $img = get_image_tag( self::$large_id, '', '', '', 'medium' ); $img = wp_img_tag_add_loading_attr( $img, 'test' ); @@ -2045,7 +2048,7 @@ EOF; /** * @ticket 33641 */ - function test_wp_filter_content_tags_with_preexisting_srcset() { + function test_wp_filter_content_tags_srcset_sizes_with_preexisting_srcset() { // Generate HTML and add a dummy srcset attribute. $img = get_image_tag( self::$large_id, '', '', '', 'medium' ); $img = wp_img_tag_add_loading_attr( $img, 'test' ); @@ -2531,11 +2534,55 @@ EOF; $this->assertSame( $expected, $url ); } + /** + * @ticket 50367 + */ + function test_wp_filter_content_tags_width_height() { + $image_meta = wp_get_attachment_metadata( self::$large_id ); + $size_array = $this->_get_image_size_array_from_meta( $image_meta, 'medium' ); + + $img = get_image_tag( self::$large_id, '', '', '', 'medium' ); + $img_no_width_height = str_replace( ' width="' . $size_array[0] . '"', '', $img ); + $img_no_width_height = str_replace( ' height="' . $size_array[1] . '"', '', $img_no_width_height ); + $img_no_width = str_replace( ' width="' . $size_array[0] . '"', '', $img ); + $img_no_height = str_replace( ' height="' . $size_array[1] . '"', '', $img ); + + $hwstring = image_hwstring( $size_array[0], $size_array[1] ); + + // Manually add width and height to the markup from get_image_tag(). + $respimg_no_width_height = str_replace( 'assertSame( $content_filtered, wp_filter_content_tags( $content_unfiltered ) ); + + remove_filter( 'wp_img_tag_add_loading_attr', '__return_false' ); + remove_filter( 'wp_img_tag_add_srcset_and_sizes_attr', '__return_false' ); + } + /** * @ticket 44427 * @ticket 50367 */ - function test_wp_lazy_load_content_media() { + function test_wp_filter_content_tags_loading_lazy() { $image_meta = wp_get_attachment_metadata( self::$large_id ); $size_array = $this->_get_image_size_array_from_meta( $image_meta, 'medium' ); @@ -2570,18 +2617,20 @@ EOF; $content_unfiltered = sprintf( $content, $img, $img_xhtml, $img_html5, $img_eager, $img_no_width_height, $iframe ); $content_filtered = sprintf( $content, $lazy_img, $lazy_img_xhtml, $lazy_img_html5, $img_eager, $img_no_width_height, $iframe ); - // Do not add srcset and sizes. + // Do not add width, height, srcset, and sizes. + add_filter( 'wp_img_tag_add_width_and_height_attr', '__return_false' ); add_filter( 'wp_img_tag_add_srcset_and_sizes_attr', '__return_false' ); $this->assertSame( $content_filtered, wp_filter_content_tags( $content_unfiltered ) ); + remove_filter( 'wp_img_tag_add_width_and_height_attr', '__return_false' ); remove_filter( 'wp_img_tag_add_srcset_and_sizes_attr', '__return_false' ); } /** * @ticket 44427 */ - function test_wp_lazy_load_content_media_opted_in() { + function test_wp_filter_content_tags_loading_lazy_opted_in() { $img = get_image_tag( self::$large_id, '', '', '', 'medium' ); $lazy_img = wp_img_tag_add_loading_attr( $img, 'test' ); @@ -2606,7 +2655,7 @@ EOF; /** * @ticket 44427 */ - function test_wp_lazy_load_content_media_opted_out() { + function test_wp_filter_content_tags_loading_lazy_opted_out() { $img = get_image_tag( self::$large_id, '', '', '', 'medium' ); $content = ' @@ -2626,13 +2675,13 @@ EOF; } /** - * @ticket 44427 + * @ticket 50367 */ - function test_wp_img_tag_add_loading_attr_single_quote() { - $img = ""; + function test_wp_img_tag_add_loading_attr_without_src() { + $img = ' width='; $img = wp_img_tag_add_loading_attr( $img, 'test' ); - $this->assertContains( " loading='lazy'", $img ); + $this->assertNotContains( ' loading="lazy"', $img ); } }