: str_replace(): Passing null to parameter #2 ($replace) of type array|string is deprecated in
if ( empty( $decoding_val ) ) {
* Filters the `decoding` attribute value to add to an image. Default `async`.
* Returning a falsey value will omit the attribute.
* @param string|false|null $value The `decoding` attribute value. Returning a falsey value
* will result in the attribute being omitted for the image.
* Otherwise, it may be: 'async', 'sync', or 'auto'. Defaults to false.
* @param string $image The HTML `img` tag to be filtered.
* @param string $context Additional context about how the function was called
* or where the img tag is.
$filtered_decoding_attr = apply_filters(
'wp_img_tag_add_decoding_attr',
isset( $optimization_attrs['decoding'] ) ? $optimization_attrs['decoding'] : false,
// Validate the values after filtering.
if ( isset( $optimization_attrs['decoding'] ) && ! $filtered_decoding_attr ) {
// Unset `decoding` attribute if `$filtered_decoding_attr` is set to `false`.
unset( $optimization_attrs['decoding'] );
} elseif ( in_array( $filtered_decoding_attr, array( 'async', 'sync', 'auto' ), true ) ) {
$optimization_attrs['decoding'] = $filtered_decoding_attr;
if ( ! empty( $optimization_attrs['decoding'] ) ) {
$image = str_replace( '<img', '<img decoding="' . esc_attr( $optimization_attrs['decoding'] ) . '"', $image );
// Images should have dimension attributes for the 'loading' and 'fetchpriority' attributes to be added.
if ( ! str_contains( $image, ' width="' ) || ! str_contains( $image, ' height="' ) ) {
// Retained for backward compatibility.
$loading_attrs_enabled = wp_lazy_loading_enabled( 'img', $context );
if ( empty( $loading_val ) && $loading_attrs_enabled ) {
* Filters the `loading` attribute value to add to an image. Default `lazy`.
* Returning `false` or an empty string will not add the attribute.
* Returning `true` will add the default value.
* @param string|bool $value The `loading` attribute value. Returning a falsey value will result in
* the attribute being omitted for the image.
* @param string $image The HTML `img` tag to be filtered.
* @param string $context Additional context about how the function was called or where the img tag is.
$filtered_loading_attr = apply_filters(
'wp_img_tag_add_loading_attr',
isset( $optimization_attrs['loading'] ) ? $optimization_attrs['loading'] : false,
// Validate the values after filtering.
if ( isset( $optimization_attrs['loading'] ) && ! $filtered_loading_attr ) {
// Unset `loading` attributes if `$filtered_loading_attr` is set to `false`.
unset( $optimization_attrs['loading'] );
} elseif ( in_array( $filtered_loading_attr, array( 'lazy', 'eager' ), true ) ) {
* If the filter changed the loading attribute to "lazy" when a fetchpriority attribute
* with value "high" is already present, trigger a warning since those two attribute
* values should be mutually exclusive.
* The same warning is present in `wp_get_loading_optimization_attributes()`, and here it
* is only intended for the specific scenario where the above filtered caused the problem.
if ( isset( $optimization_attrs['fetchpriority'] ) && 'high' === $optimization_attrs['fetchpriority'] &&
( isset( $optimization_attrs['loading'] ) ? $optimization_attrs['loading'] : false ) !== $filtered_loading_attr &&
'lazy' === $filtered_loading_attr
__( 'An image should not be lazy-loaded and marked as high priority at the same time.' ),
// The filtered value will still be respected.
$optimization_attrs['loading'] = $filtered_loading_attr;
if ( ! empty( $optimization_attrs['loading'] ) ) {
$image = str_replace( '<img', '<img loading="' . esc_attr( $optimization_attrs['loading'] ) . '"', $image );
if ( empty( $fetchpriority_val ) && ! empty( $optimization_attrs['fetchpriority'] ) ) {
$image = str_replace( '<img', '<img fetchpriority="' . esc_attr( $optimization_attrs['fetchpriority'] ) . '"', $image );
* Adds `width` and `height` attributes to an `img` HTML tag.
* @param string $image The HTML `img` tag where the attribute should be added.
* @param string $context Additional context to pass to the filters.
* @param int $attachment_id Image attachment ID.
* @return string Converted 'img' element with 'width' and 'height' attributes added.
function wp_img_tag_add_width_and_height_attr( $image, $context, $attachment_id ) {
$image_src = preg_match( '/src="([^"]+)"/', $image, $match_src ) ? $match_src[1] : '';
list( $image_src ) = explode( '?', $image_src );
// Return early if we couldn't get the image source.
* Filters whether to add the missing `width` and `height` HTML attributes to the img tag. Default `true`.
* Returning anything else than `true` will not add the attributes.
* @param bool $value The filtered value, defaults to `true`.
* @param string $image The HTML `img` tag where the attribute should be added.
* @param string $context Additional context about how the function was called or where the img tag is.
* @param int $attachment_id The image attachment ID.
$add = apply_filters( 'wp_img_tag_add_width_and_height_attr', true, $image, $context, $attachment_id );
$image_meta = wp_get_attachment_metadata( $attachment_id );
$size_array = wp_image_src_get_dimensions( $image_src, $image_meta, $attachment_id );
if ( $size_array && $size_array[0] && $size_array[1] ) {
// If the width is enforced through style (e.g. in an inline image), calculate the dimension attributes.
$style_width = preg_match( '/style="width:\s*(\d+)px;"/', $image, $match_width ) ? (int) $match_width[1] : 0;
$size_array[1] = (int) round( $size_array[1] * $style_width / $size_array[0] );
$size_array[0] = $style_width;
$hw = trim( image_hwstring( $size_array[0], $size_array[1] ) );
return str_replace( '<img', "<img {$hw}", $image );
* Adds `srcset` and `sizes` attributes to an existing `img` HTML tag.
* @param string $image The HTML `img` tag where the attribute should be added.
* @param string $context Additional context to pass to the filters.
* @param int $attachment_id Image attachment ID.
* @return string Converted 'img' element with 'loading' attribute added.
function wp_img_tag_add_srcset_and_sizes_attr( $image, $context, $attachment_id ) {
* Filters whether to add the `srcset` and `sizes` HTML attributes to the img tag. Default `true`.
* Returning anything else than `true` will not add the attributes.
* @param bool $value The filtered value, defaults to `true`.
* @param string $image The HTML `img` tag where the attribute should be added.
* @param string $context Additional context about how the function was called or where the img tag is.
* @param int $attachment_id The image attachment ID.
$add = apply_filters( 'wp_img_tag_add_srcset_and_sizes_attr', true, $image, $context, $attachment_id );
$image_meta = wp_get_attachment_metadata( $attachment_id );
return wp_image_add_srcset_and_sizes( $image, $image_meta, $attachment_id );
* Adds `loading` attribute to an `iframe` HTML tag.
* @param string $iframe The HTML `iframe` tag where the attribute should be added.
* @param string $context Additional context to pass to the filters.
* @return string Converted `iframe` tag with `loading` attribute added.
function wp_iframe_tag_add_loading_attr( $iframe, $context ) {
* Get loading attribute value to use. This must occur before the conditional check below so that even iframes that
* are ineligible for being lazy-loaded are considered.
$optimization_attrs = wp_get_loading_optimization_attributes(
* The concrete values for width and height are not important here for now
* since fetchpriority is not yet supported for iframes.
* TODO: Use WP_HTML_Tag_Processor to extract actual values once support is
'width' => str_contains( $iframe, ' width="' ) ? 100 : null,
'height' => str_contains( $iframe, ' height="' ) ? 100 : null,
// This function is never called when a 'loading' attribute is already present.
// Iframes should have source and dimension attributes for the `loading` attribute to be added.
if ( ! str_contains( $iframe, ' src="' ) || ! str_contains( $iframe, ' width="' ) || ! str_contains( $iframe, ' height="' ) ) {
$value = isset( $optimization_attrs['loading'] ) ? $optimization_attrs['loading'] : false;
* Filters the `loading` attribute value to add to an iframe. Default `lazy`.
* Returning `false` or an empty string will not add the attribute.
* Returning `true` will add the default value.
* @param string|bool $value The `loading` attribute value. Returning a falsey value will result in
* the attribute being omitted for the iframe.
* @param string $iframe The HTML `iframe` tag to be filtered.
* @param string $context Additional context about how the function was called or where the iframe tag is.
$value = apply_filters( 'wp_iframe_tag_add_loading_attr', $value, $iframe, $context );
if ( ! in_array( $value, array( 'lazy', 'eager' ), true ) ) {
return str_replace( '<iframe', '<iframe loading="' . esc_attr( $value ) . '"', $iframe );
* Adds a 'wp-post-image' class to post thumbnails. Internal use only.
* Uses the {@see 'begin_fetch_post_thumbnail_html'} and {@see 'end_fetch_post_thumbnail_html'}
* action hooks to dynamically add/remove itself so as to only filter post thumbnails.
* @param string[] $attr Array of thumbnail attributes including src, class, alt, title, keyed by attribute name.
* @return string[] Modified array of attributes including the new 'wp-post-image' class.
function _wp_post_thumbnail_class_filter( $attr ) {
$attr['class'] .= ' wp-post-image';
* Adds '_wp_post_thumbnail_class_filter' callback to the 'wp_get_attachment_image_attributes'
* filter hook. Internal use only.
* @param string[] $attr Array of thumbnail attributes including src, class, alt, title, keyed by attribute name.
function _wp_post_thumbnail_class_filter_add( $attr ) {
add_filter( 'wp_get_attachment_image_attributes', '_wp_post_thumbnail_class_filter' );
* Removes the '_wp_post_thumbnail_class_filter' callback from the 'wp_get_attachment_image_attributes'
* filter hook. Internal use only.
* @param string[] $attr Array of thumbnail attributes including src, class, alt, title, keyed by attribute name.
function _wp_post_thumbnail_class_filter_remove( $attr ) {
remove_filter( 'wp_get_attachment_image_attributes', '_wp_post_thumbnail_class_filter' );
* Overrides the context used in {@see wp_get_attachment_image()}. Internal use only.
* Uses the {@see 'begin_fetch_post_thumbnail_html'} and {@see 'end_fetch_post_thumbnail_html'}
* action hooks to dynamically add/remove itself so as to only filter post thumbnails.
* @param string $context The context for rendering an attachment image.
* @return string Modified context set to 'the_post_thumbnail'.
function _wp_post_thumbnail_context_filter( $context ) {
return 'the_post_thumbnail';
* Adds the '_wp_post_thumbnail_context_filter' callback to the 'wp_get_attachment_image_context'
* filter hook. Internal use only.
function _wp_post_thumbnail_context_filter_add() {
add_filter( 'wp_get_attachment_image_context', '_wp_post_thumbnail_context_filter' );
* Removes the '_wp_post_thumbnail_context_filter' callback from the 'wp_get_attachment_image_context'
* filter hook. Internal use only.
function _wp_post_thumbnail_context_filter_remove() {
remove_filter( 'wp_get_attachment_image_context', '_wp_post_thumbnail_context_filter' );
add_shortcode( 'wp_caption', 'img_caption_shortcode' );
add_shortcode( 'caption', 'img_caption_shortcode' );
* Builds the Caption shortcode output.
* Allows a plugin to replace the content that would otherwise be returned. The
* filter is {@see 'img_caption_shortcode'} and passes an empty string, the attr
* parameter and the content parameter values.
* The supported attributes for the shortcode are 'id', 'caption_id', 'align',
* 'width', 'caption', and 'class'.
* @since 3.9.0 The `class` attribute was added.
* @since 5.1.0 The `caption_id` attribute was added.
* @since 5.9.0 The `$content` parameter default value changed from `null` to `''`.
* Attributes of the caption shortcode.
* @type string $id ID of the image and caption container element, i.e. `<figure>` or `<div>`.
* @type string $caption_id ID of the caption element, i.e. `<figcaption>` or `<p>`.
* @type string $align Class name that aligns the caption. Default 'alignnone'. Accepts 'alignleft',
* 'aligncenter', alignright', 'alignnone'.
* @type int $width The width of the caption, in pixels.
* @type string $caption The caption text.
* @type string $class Additional class name(s) added to the caption container.
* @param string $content Optional. Shortcode content. Default empty string.
* @return string HTML content to display the caption.
function img_caption_shortcode( $attr, $content = '' ) {
// New-style shortcode with the caption inside the shortcode with the link and image tags.
if ( ! isset( $attr['caption'] ) ) {
if ( preg_match( '#((?:<a [^>]+>\s*)?<img [^>]+>(?:\s*</a>)?)(.*)#is', $content, $matches ) ) {
$attr['caption'] = trim( $matches[2] );
} elseif ( str_contains( $attr['caption'], '<' ) ) {
$attr['caption'] = wp_kses( $attr['caption'], 'post' );
* Filters the default caption shortcode output.
* If the filtered output isn't empty, it will be used instead of generating
* the default caption template.
* @see img_caption_shortcode()
* @param string $output The caption output. Default empty.
* @param array $attr Attributes of the caption shortcode.
* @param string $content The image element, possibly wrapped in a hyperlink.
$output = apply_filters( 'img_caption_shortcode', '', $attr, $content );
if ( ! empty( $output ) ) {
$atts['width'] = (int) $atts['width'];
if ( $atts['width'] < 1 || empty( $atts['caption'] ) ) {
$atts['id'] = sanitize_html_class( $atts['id'] );
$id = 'id="' . esc_attr( $atts['id'] ) . '" ';
if ( $atts['caption_id'] ) {
$atts['caption_id'] = sanitize_html_class( $atts['caption_id'] );
} elseif ( $atts['id'] ) {
$atts['caption_id'] = 'caption-' . str_replace( '_', '-', $atts['id'] );
if ( $atts['caption_id'] ) {
$caption_id = 'id="' . esc_attr( $atts['caption_id'] ) . '" ';
$describedby = 'aria-describedby="' . esc_attr( $atts['caption_id'] ) . '" ';
$class = trim( 'wp-caption ' . $atts['align'] . ' ' . $atts['class'] );
$html5 = current_theme_supports( 'html5', 'caption' );
// HTML5 captions never added the extra 10px to the image width.
$width = $html5 ? $atts['width'] : ( 10 + $atts['width'] );
* Filters the width of an image's caption.
* By default, the caption is 10 pixels greater than the width of the image,
* to prevent post content from running up against a floated image.
* @see img_caption_shortcode()
* @param int $width Width of the caption in pixels. To remove this inline style,
* @param array $atts Attributes of the caption shortcode.
* @param string $content The image element, possibly wrapped in a hyperlink.
$caption_width = apply_filters( 'img_caption_shortcode_width', $width, $atts, $content );
$style = 'style="width: ' . (int) $caption_width . 'px" ';
'<figure %s%s%sclass="%s">%s%s</figure>',
do_shortcode( $content ),
'<figcaption %sclass="wp-caption-text">%s</figcaption>',
'<div %s%sclass="%s">%s%s</div>',
str_replace( '<img ', '<img ' . $describedby, do_shortcode( $content ) ),
'<p %sclass="wp-caption-text">%s</p>',