* @since 4.4.0 The `$srcset` and `$sizes` attributes were added.
* @since 5.5.0 The `$loading` attribute was added.
* @param int $attachment_id Image attachment ID.
* @param string|int[] $size Optional. Image size. Accepts any registered image size name, or an array
* of width and height values in pixels (in that order). Default 'thumbnail'.
* @param bool $icon Optional. Whether the image should be treated as an icon. Default false.
* @param string|array $attr {
* Optional. Attributes for the image markup.
* @type string $src Image attachment URL.
* @type string $class CSS class name or space-separated list of classes.
* Default `attachment-$size_class size-$size_class`,
* where `$size_class` is the image size being requested.
* @type string $alt Image description for the alt attribute.
* @type string $srcset The 'srcset' attribute value.
* @type string $sizes The 'sizes' attribute value.
* @type string|false $loading The 'loading' attribute value. Passing a value of false
* will result in the attribute being omitted for the image.
* Defaults to 'lazy', depending on wp_lazy_loading_enabled().
* @return string HTML img element or empty string on failure.
function wp_get_attachment_image( $attachment_id, $size = 'thumbnail', $icon = false, $attr = '' ) {
$image = wp_get_attachment_image_src( $attachment_id, $size, $icon );
list( $src, $width, $height ) = $image;
$attachment = get_post( $attachment_id );
$hwstring = image_hwstring( $width, $height );
if ( is_array( $size_class ) ) {
$size_class = implode( 'x', $size_class );
'class' => "attachment-$size_class size-$size_class",
'alt' => trim( strip_tags( get_post_meta( $attachment_id, '_wp_attachment_image_alt', true ) ) ),
// Add `loading` attribute.
if ( wp_lazy_loading_enabled( 'img', 'wp_get_attachment_image' ) ) {
$default_attr['loading'] = 'lazy';
$attr = wp_parse_args( $attr, $default_attr );
// If the default value of `lazy` for the `loading` attribute is overridden
// to omit the attribute for this image, ensure it is not included.
if ( array_key_exists( 'loading', $attr ) && ! $attr['loading'] ) {
unset( $attr['loading'] );
// Generate 'srcset' and 'sizes' if not already present.
if ( empty( $attr['srcset'] ) ) {
$image_meta = wp_get_attachment_metadata( $attachment_id );
if ( is_array( $image_meta ) ) {
$size_array = array( absint( $width ), absint( $height ) );
$srcset = wp_calculate_image_srcset( $size_array, $src, $image_meta, $attachment_id );
$sizes = wp_calculate_image_sizes( $size_array, $src, $image_meta, $attachment_id );
if ( $srcset && ( $sizes || ! empty( $attr['sizes'] ) ) ) {
$attr['srcset'] = $srcset;
if ( empty( $attr['sizes'] ) ) {
* Filters the list of attachment image attributes.
* @param string[] $attr Array of attribute values for the image markup, keyed by attribute name.
* See wp_get_attachment_image().
* @param WP_Post $attachment Image attachment post.
* @param string|int[] $size Requested image size. Can be any registered image size name, or
* an array of width and height values in pixels (in that order).
$attr = apply_filters( 'wp_get_attachment_image_attributes', $attr, $attachment, $size );
$attr = array_map( 'esc_attr', $attr );
$html = rtrim( "<img $hwstring" );
foreach ( $attr as $name => $value ) {
$html .= " $name=" . '"' . $value . '"';
* HTML img element representing an image attachment.
* @param string $html HTML img element or empty string on failure.
* @param int $attachment_id Image attachment ID.
* @param string|int[] $size Requested image size. Can be any registered image size name, or
* an array of width and height values in pixels (in that order).
* @param bool $icon Whether the image should be treated as an icon.
* @param string[] $attr Array of attribute values for the image markup, keyed by attribute name.
* See wp_get_attachment_image().
return apply_filters( 'wp_get_attachment_image', $html, $attachment_id, $size, $icon, $attr );
* Get the URL of an image attachment.
* @param int $attachment_id Image attachment ID.
* @param string|int[] $size Optional. Image size. Accepts any registered image size name, or an array of
* width and height values in pixels (in that order). Default 'thumbnail'.
* @param bool $icon Optional. Whether the image should be treated as an icon. Default false.
* @return string|false Attachment URL or false if no image is available. If `$size` does not match
* any registered image size, the original image URL will be returned.
function wp_get_attachment_image_url( $attachment_id, $size = 'thumbnail', $icon = false ) {
$image = wp_get_attachment_image_src( $attachment_id, $size, $icon );
return isset( $image['0'] ) ? $image['0'] : false;
* Get the attachment path relative to the upload directory.
* @param string $file Attachment file name.
* @return string Attachment path relative to the upload directory.
function _wp_get_attachment_relative_path( $file ) {
$dirname = dirname( $file );
if ( '.' === $dirname ) {
if ( false !== strpos( $dirname, 'wp-content/uploads' ) ) {
// Get the directory name relative to the upload directory (back compat for pre-2.7 uploads).
$dirname = substr( $dirname, strpos( $dirname, 'wp-content/uploads' ) + 18 );
$dirname = ltrim( $dirname, '/' );
* Get the image size as array from its meta data.
* Used for responsive images.
* @param string $size_name Image size. Accepts any registered image size name.
* @param array $image_meta The image meta data.
* Array of width and height or false if the size isn't present in the meta data.
* @type int $0 Image width.
* @type int $1 Image height.
function _wp_get_image_size_from_meta( $size_name, $image_meta ) {
if ( 'full' === $size_name ) {
absint( $image_meta['width'] ),
absint( $image_meta['height'] ),
} elseif ( ! empty( $image_meta['sizes'][ $size_name ] ) ) {
absint( $image_meta['sizes'][ $size_name ]['width'] ),
absint( $image_meta['sizes'][ $size_name ]['height'] ),
* Retrieves the value for an image attachment's 'srcset' attribute.
* @see wp_calculate_image_srcset()
* @param int $attachment_id Image attachment ID.
* @param string|int[] $size Optional. Image size. Accepts any registered image size name, or an array of
* width and height values in pixels (in that order). Default 'medium'.
* @param array $image_meta Optional. The image meta data as returned by 'wp_get_attachment_metadata()'.
* @return string|false A 'srcset' value string or false.
function wp_get_attachment_image_srcset( $attachment_id, $size = 'medium', $image_meta = null ) {
$image = wp_get_attachment_image_src( $attachment_id, $size );
if ( ! is_array( $image_meta ) ) {
$image_meta = wp_get_attachment_metadata( $attachment_id );
return wp_calculate_image_srcset( $size_array, $image_src, $image_meta, $attachment_id );
* A helper function to calculate the image sources to include in a 'srcset' attribute.
* @param int[] $size_array {
* An array of width and height values.
* @type int $0 The width in pixels.
* @type int $1 The height in pixels.
* @param string $image_src The 'src' of the image.
* @param array $image_meta The image meta data as returned by 'wp_get_attachment_metadata()'.
* @param int $attachment_id Optional. The image attachment ID. Default 0.
* @return string|false The 'srcset' attribute value. False on error or when only one source exists.
function wp_calculate_image_srcset( $size_array, $image_src, $image_meta, $attachment_id = 0 ) {
* Let plugins pre-filter the image meta to be able to fix inconsistencies in the stored data.
* @param array $image_meta The image meta data as returned by 'wp_get_attachment_metadata()'.
* @param int[] $size_array {
* An array of requested width and height values.
* @type int $0 The width in pixels.
* @type int $1 The height in pixels.
* @param string $image_src The 'src' of the image.
* @param int $attachment_id The image attachment ID or 0 if not supplied.
$image_meta = apply_filters( 'wp_calculate_image_srcset_meta', $image_meta, $size_array, $image_src, $attachment_id );
if ( empty( $image_meta['sizes'] ) || ! isset( $image_meta['file'] ) || strlen( $image_meta['file'] ) < 4 ) {
$image_sizes = $image_meta['sizes'];
// Get the width and height of the image.
$image_width = (int) $size_array[0];
$image_height = (int) $size_array[1];
// Bail early if error/no width.
if ( $image_width < 1 ) {
$image_basename = wp_basename( $image_meta['file'] );
* WordPress flattens animated GIFs into one frame when generating intermediate sizes.
* To avoid hiding animation in user content, if src is a full size GIF, a srcset attribute is not generated.
* If src is an intermediate size GIF, the full size is excluded from srcset to keep a flattened GIF from becoming animated.
if ( ! isset( $image_sizes['thumbnail']['mime-type'] ) || 'image/gif' !== $image_sizes['thumbnail']['mime-type'] ) {
'width' => $image_meta['width'],
'height' => $image_meta['height'],
'file' => $image_basename,
} elseif ( strpos( $image_src, $image_meta['file'] ) ) {
// Retrieve the uploads sub-directory from the full size image.
$dirname = _wp_get_attachment_relative_path( $image_meta['file'] );
$dirname = trailingslashit( $dirname );
$upload_dir = wp_get_upload_dir();
$image_baseurl = trailingslashit( $upload_dir['baseurl'] ) . $dirname;
* If currently on HTTPS, prefer HTTPS URLs when we know they're supported by the domain
* (which is to say, when they share the domain name of the current request).
if ( is_ssl() && 'https' !== substr( $image_baseurl, 0, 5 ) && parse_url( $image_baseurl, PHP_URL_HOST ) === $_SERVER['HTTP_HOST'] ) {
$image_baseurl = set_url_scheme( $image_baseurl, 'https' );
* Images that have been edited in WordPress after being uploaded will
* contain a unique hash. Look for that hash and use it later to filter
* out images that are leftovers from previous versions.
$image_edited = preg_match( '/-e[0-9]{13}/', wp_basename( $image_src ), $image_edit_hash );
* Filters the maximum image width to be included in a 'srcset' attribute.
* @param int $max_width The maximum image width to be included in the 'srcset'. Default '2048'.
* @param int[] $size_array {
* An array of requested width and height values.
* @type int $0 The width in pixels.
* @type int $1 The height in pixels.
$max_srcset_image_width = apply_filters( 'max_srcset_image_width', 2048, $size_array );
// Array to hold URL candidates.
* To make sure the ID matches our image src, we will check to see if any sizes in our attachment
* meta match our $image_src. If no matches are found we don't return a srcset to avoid serving
* an incorrect image. See #35045.
* Loop through available images. Only use images that are resized
* versions of the same edit.
foreach ( $image_sizes as $image ) {
// Check if image meta isn't corrupted.
if ( ! is_array( $image ) ) {
// If the file name is part of the `src`, we've confirmed a match.
if ( ! $src_matched && false !== strpos( $image_src, $dirname . $image['file'] ) ) {
// Filter out images that are from previous edits.
if ( $image_edited && ! strpos( $image['file'], $image_edit_hash[0] ) ) {
* Filters out images that are wider than '$max_srcset_image_width' unless
* that file is in the 'src' attribute.
if ( $max_srcset_image_width && $image['width'] > $max_srcset_image_width && ! $is_src ) {
// If the image dimensions are within 1px of the expected size, use it.
if ( wp_image_matches_ratio( $image_width, $image_height, $image['width'], $image['height'] ) ) {
// Add the URL, descriptor, and value to the sources array to be returned.
'url' => $image_baseurl . $image['file'],
'value' => $image['width'],
// The 'src' image has to be the first in the 'srcset', because of a bug in iOS8. See #35030.
$sources = array( $image['width'] => $source ) + $sources;
$sources[ $image['width'] ] = $source;
* Filters an image's 'srcset' sources.
* @param array $sources {
* One or more arrays of source data to include in the 'srcset'.
* @type string $url The URL of an image source.
* @type string $descriptor The descriptor type used in the image candidate string,
* @type int $value The source width if paired with a 'w' descriptor, or a
* pixel density value if paired with an 'x' descriptor.
* @param array $size_array {
* An array of requested width and height values.
* @type int $0 The width in pixels.
* @type int $1 The height in pixels.
* @param string $image_src The 'src' of the image.
* @param array $image_meta The image meta data as returned by 'wp_get_attachment_metadata()'.
* @param int $attachment_id Image attachment ID or 0.
$sources = apply_filters( 'wp_calculate_image_srcset', $sources, $size_array, $image_src, $image_meta, $attachment_id );
// Only return a 'srcset' value if there is more than one source.
if ( ! $src_matched || ! is_array( $sources ) || count( $sources ) < 2 ) {
foreach ( $sources as $source ) {
$srcset .= str_replace( ' ', '%20', $source['url'] ) . ' ' . $source['value'] . $source['descriptor'] . ', ';
return rtrim( $srcset, ', ' );
* Retrieves the value for an image attachment's 'sizes' attribute.
* @see wp_calculate_image_sizes()
* @param int $attachment_id Image attachment ID.
* @param string|int[] $size Optional. Image size. Accepts any registered image size name, or an array of
* width and height values in pixels (in that order). Default 'medium'.
* @param array $image_meta Optional. The image meta data as returned by 'wp_get_attachment_metadata()'.
* @return string|false A valid source size value for use in a 'sizes' attribute or false.
function wp_get_attachment_image_sizes( $attachment_id, $size = 'medium', $image_meta = null ) {
$image = wp_get_attachment_image_src( $attachment_id, $size );
if ( ! is_array( $image_meta ) ) {
$image_meta = wp_get_attachment_metadata( $attachment_id );
return wp_calculate_image_sizes( $size_array, $image_src, $image_meta, $attachment_id );
* Creates a 'sizes' attribute value for an image.
* @param string|int[] $size Image size. Accepts any registered image size name, or an array of
* width and height values in pixels (in that order).
* @param string $image_src Optional. The URL to the image file. Default null.
* @param array $image_meta Optional. The image meta data as returned by 'wp_get_attachment_metadata()'.
* @param int $attachment_id Optional. Image attachment ID. Either `$image_meta` or `$attachment_id`
* is needed when using the image size name as argument for `$size`. Default 0.
* @return string|false A valid source size value for use in a 'sizes' attribute or false.
function wp_calculate_image_sizes( $size, $image_src = null, $image_meta = null, $attachment_id = 0 ) {
if ( is_array( $size ) ) {
$width = absint( $size[0] );
} elseif ( is_string( $size ) ) {
if ( ! $image_meta && $attachment_id ) {
$image_meta = wp_get_attachment_metadata( $attachment_id );
if ( is_array( $image_meta ) ) {
$size_array = _wp_get_image_size_from_meta( $size, $image_meta );
$width = absint( $size_array[0] );