diff -r 48c4eec2b7e6 -r 8c2e4d02f4ef wp/wp-includes/media.php --- a/wp/wp-includes/media.php Fri Sep 05 18:40:08 2025 +0200 +++ b/wp/wp-includes/media.php Fri Sep 05 18:52:52 2025 +0200 @@ -6,6 +6,11 @@ * @subpackage Media */ +// Don't load directly. +if ( ! defined( 'ABSPATH' ) ) { + die( '-1' ); +} + /** * Retrieves additional image sizes. * @@ -288,7 +293,7 @@ * If true, image will be cropped to the specified dimensions using center positions. * If an array, the image will be cropped using the array to specify the crop location: * - * @type string $0 The x crop position. Accepts 'left' 'center', or 'right'. + * @type string $0 The x crop position. Accepts 'left', 'center', or 'right'. * @type string $1 The y crop position. Accepts 'top', 'center', or 'bottom'. * } */ @@ -350,7 +355,7 @@ * If true, image will be cropped to the specified dimensions using center positions. * If an array, the image will be cropped using the array to specify the crop location: * - * @type string $0 The x crop position. Accepts 'left' 'center', or 'right'. + * @type string $0 The x crop position. Accepts 'left', 'center', or 'right'. * @type string $1 The y crop position. Accepts 'top', 'center', or 'bottom'. * } */ @@ -530,7 +535,7 @@ * If true, image will be cropped to the specified dimensions using center positions. * If an array, the image will be cropped using the array to specify the crop location: * - * @type string $0 The x crop position. Accepts 'left' 'center', or 'right'. + * @type string $0 The x crop position. Accepts 'left', 'center', or 'right'. * @type string $1 The y crop position. Accepts 'top', 'center', or 'bottom'. * } * @return array|false Returned array matches parameters for `imagecopyresampled()`. False on failure. @@ -684,7 +689,7 @@ * If true, image will be cropped to the specified dimensions using center positions. * If an array, the image will be cropped using the array to specify the crop location: * - * @type string $0 The x crop position. Accepts 'left' 'center', or 'right'. + * @type string $0 The x crop position. Accepts 'left', 'center', or 'right'. * @type string $1 The y crop position. Accepts 'top', 'center', or 'bottom'. * } * @return array|false Metadata array on success. False if no image was created. @@ -1065,7 +1070,6 @@ list( $src, $width, $height ) = $image; $attachment = get_post( $attachment_id ); - $hwstring = image_hwstring( $width, $height ); $size_class = $size; if ( is_array( $size_class ) ) { @@ -1085,15 +1089,14 @@ * * @param string $context The context. Default 'wp_get_attachment_image'. */ - $context = apply_filters( 'wp_get_attachment_image_context', 'wp_get_attachment_image' ); - $attr = wp_parse_args( $attr, $default_attr ); - - $loading_attr = $attr; - $loading_attr['width'] = $width; - $loading_attr['height'] = $height; + $context = apply_filters( 'wp_get_attachment_image_context', 'wp_get_attachment_image' ); + $attr = wp_parse_args( $attr, $default_attr ); + $attr['width'] = $width; + $attr['height'] = $height; + $loading_optimization_attr = wp_get_loading_optimization_attributes( 'img', - $loading_attr, + $attr, $context ); @@ -1137,6 +1140,20 @@ } } + /** This filter is documented in wp-includes/media.php */ + $add_auto_sizes = apply_filters( 'wp_img_tag_add_auto_sizes', true ); + + // Adds 'auto' to the sizes attribute if applicable. + if ( + $add_auto_sizes && + isset( $attr['loading'] ) && + 'lazy' === $attr['loading'] && + isset( $attr['sizes'] ) && + ! wp_sizes_attribute_includes_valid_auto( $attr['sizes'] ) + ) { + $attr['sizes'] = 'auto, ' . $attr['sizes']; + } + /** * Filters the list of attachment image attributes. * @@ -1150,8 +1167,16 @@ */ $attr = apply_filters( 'wp_get_attachment_image_attributes', $attr, $attachment, $size ); - $attr = array_map( 'esc_attr', $attr ); - $html = rtrim( " $value ) { $html .= " $name=" . '"' . $value . '"'; @@ -1917,6 +1942,9 @@ // Add loading optimization attributes if applicable. $filtered_image = wp_img_tag_add_loading_optimization_attrs( $filtered_image, $context ); + // Adds 'auto' to the sizes attribute if applicable. + $filtered_image = wp_img_tag_add_auto_sizes( $filtered_image ); + /** * Filters an img tag within the content for a given context. * @@ -1964,6 +1992,103 @@ } /** + * Adds 'auto' to the sizes attribute to the image, if the image is lazy loaded and does not already include it. + * + * @since 6.7.0 + * + * @param string $image The image tag markup being filtered. + * @return string The filtered image tag markup. + */ +function wp_img_tag_add_auto_sizes( string $image ): string { + /** + * Filters whether auto-sizes for lazy loaded images is enabled. + * + * @since 6.7.1 + * + * @param boolean $enabled Whether auto-sizes for lazy loaded images is enabled. + */ + if ( ! apply_filters( 'wp_img_tag_add_auto_sizes', true ) ) { + return $image; + } + + $processor = new WP_HTML_Tag_Processor( $image ); + + // Bail if there is no IMG tag. + if ( ! $processor->next_tag( array( 'tag_name' => 'IMG' ) ) ) { + return $image; + } + + // Bail early if the image is not lazy-loaded. + $loading = $processor->get_attribute( 'loading' ); + if ( ! is_string( $loading ) || 'lazy' !== strtolower( trim( $loading, " \t\f\r\n" ) ) ) { + return $image; + } + + /* + * Bail early if the image doesn't have a width attribute. + * Per WordPress Core itself, lazy-loaded images should always have a width attribute. + * However, it is possible that lazy-loading could be added by a plugin, where we don't have that guarantee. + * As such, it still makes sense to ensure presence of a width attribute here in order to use `sizes=auto`. + */ + $width = $processor->get_attribute( 'width' ); + if ( ! is_string( $width ) || '' === $width ) { + return $image; + } + + $sizes = $processor->get_attribute( 'sizes' ); + + // Bail early if the image is not responsive. + if ( ! is_string( $sizes ) ) { + return $image; + } + + // Don't add 'auto' to the sizes attribute if it already exists. + if ( wp_sizes_attribute_includes_valid_auto( $sizes ) ) { + return $image; + } + + $processor->set_attribute( 'sizes', "auto, $sizes" ); + return $processor->get_updated_html(); +} + +/** + * Checks whether the given 'sizes' attribute includes the 'auto' keyword as the first item in the list. + * + * Per the HTML spec, if present it must be the first entry. + * + * @since 6.7.0 + * + * @param string $sizes_attr The 'sizes' attribute value. + * @return bool True if the 'auto' keyword is present, false otherwise. + */ +function wp_sizes_attribute_includes_valid_auto( string $sizes_attr ): bool { + list( $first_size ) = explode( ',', $sizes_attr, 2 ); + return 'auto' === strtolower( trim( $first_size, " \t\f\r\n" ) ); +} + +/** + * Prints a CSS rule to fix potential visual issues with images using `sizes=auto`. + * + * This rule overrides the similar rule in the default user agent stylesheet, to avoid images that use e.g. + * `width: auto` or `width: fit-content` to appear smaller. + * + * @since 6.7.1 + * @see https://html.spec.whatwg.org/multipage/rendering.html#img-contain-size + * @see https://core.trac.wordpress.org/ticket/62413 + */ +function wp_print_auto_sizes_contain_css_fix() { + /** This filter is documented in wp-includes/media.php */ + $add_auto_sizes = apply_filters( 'wp_img_tag_add_auto_sizes', true ); + if ( ! $add_auto_sizes ) { + return; + } + + ?> + + $src, 'width' => $width, 'height' => $height, 'loading' => $loading_val, @@ -3224,6 +3351,7 @@ * WordPress mp3s in a post. * * @since 3.6.0 + * @since 6.8.0 Added the 'muted' attribute. * * @param array $attr { * Attributes of the audio shortcode. @@ -3231,6 +3359,7 @@ * @type string $src URL to the source of the audio file. Default empty. * @type string $loop The 'loop' attribute for the `