wp_get_loading_optimization_attributes( string $tag_name, array $attr, string $context ): array
Gets loading optimization attributes.
Contents
Description
This function returns an array of attributes that should be merged into the given attributes array to optimize loading performance. Potential attributes returned by this function are:
loading
attribute with a value of "lazy"fetchpriority
attribute with a value of "high"
If any of these attributes are already present in the given attributes, they will not be modified. Note that no element should have both loading="lazy"
and fetchpriority="high"
, so the function will trigger a warning in case both attributes are present with those values.
Parameters
-
$tag_name
string Required -
The tag name.
-
$attr
array Required -
Array of the attributes for the tag.
-
$context
string Required -
Context for the element for which the loading optimization attribute is requested.
Return
array Loading optimization attributes.
Source
File: wp-includes/media.php
.
View all references
function wp_get_loading_optimization_attributes( $tag_name, $attr, $context ) {
global $wp_query;
/*
* Closure for postprocessing logic.
* It is here to avoid duplicate logic in many places below, without having
* to introduce a very specific private global function.
*/
$postprocess = static function( $loading_attributes, $with_fetchpriority = false ) use ( $tag_name, $attr, $context ) {
// Potentially add `fetchpriority="high"`.
if ( $with_fetchpriority ) {
$loading_attributes = wp_maybe_add_fetchpriority_high_attr( $loading_attributes, $tag_name, $attr );
}
// Potentially strip `loading="lazy"` if the feature is disabled.
if ( isset( $loading_attributes['loading'] ) && ! wp_lazy_loading_enabled( $tag_name, $context ) ) {
unset( $loading_attributes['loading'] );
}
return $loading_attributes;
};
// Closure to increase media count for images with certain minimum threshold, mostly used for header images.
$maybe_increase_content_media_count = static function() use ( $attr ) {
/** This filter is documented in wp-admin/includes/media.php */
$wp_min_priority_img_pixels = apply_filters( 'wp_min_priority_img_pixels', 50000 );
// Images with a certain minimum size in the header of the page are also counted towards the threshold.
if ( $wp_min_priority_img_pixels <= $attr['width'] * $attr['height'] ) {
wp_increase_content_media_count();
}
};
$loading_attrs = array();
/*
* Skip lazy-loading for the overall block template, as it is handled more granularly.
* The skip is also applicable for `fetchpriority`.
*/
if ( 'template' === $context ) {
return $loading_attrs;
}
// For now this function only supports images and iframes.
if ( 'img' !== $tag_name && 'iframe' !== $tag_name ) {
return $loading_attrs;
}
// For any resources, width and height must be provided, to avoid layout shifts.
if ( ! isset( $attr['width'], $attr['height'] ) ) {
return $loading_attrs;
}
if ( isset( $attr['loading'] ) ) {
/*
* While any `loading` value could be set in `$loading_attrs`, for
* consistency we only do it for `loading="lazy"` since that is the
* only possible value that WordPress core would apply on its own.
*/
if ( 'lazy' === $attr['loading'] ) {
$loading_attrs['loading'] = 'lazy';
if ( isset( $attr['fetchpriority'] ) && 'high' === $attr['fetchpriority'] ) {
_doing_it_wrong(
__FUNCTION__,
__( 'An image should not be lazy-loaded and marked as high priority at the same time.' ),
'6.3.0'
);
}
}
return $postprocess( $loading_attrs, true );
}
// An image with `fetchpriority="high"` cannot be assigned `loading="lazy"` at the same time.
if ( isset( $attr['fetchpriority'] ) && 'high' === $attr['fetchpriority'] ) {
return $postprocess( $loading_attrs, true );
}
/*
* Do not lazy-load images in the header block template part, as they are likely above the fold.
* For classic themes, this is handled in the condition below using the 'get_header' action.
*/
$header_area = WP_TEMPLATE_PART_AREA_HEADER;
if ( "template_part_{$header_area}" === $context ) {
// Increase media count if there are images in header above a certian minimum size threshold.
$maybe_increase_content_media_count();
return $postprocess( $loading_attrs, true );
}
// The custom header image is always expected to be in the header.
if ( 'get_header_image_tag' === $context ) {
// Increase media count if there are images in header above a certian minimum size threshold.
$maybe_increase_content_media_count();
return $postprocess( $loading_attrs, true );
}
// Special handling for programmatically created image tags.
if ( 'the_post_thumbnail' === $context || 'wp_get_attachment_image' === $context || 'widget_media_image' === $context ) {
/*
* Skip programmatically created images within post content as they need to be handled together with the other
* images within the post content.
* Without this clause, they would already be considered below which skews the image count and can result in
* the first post content image being lazy-loaded or an image further down the page being marked as a high
* priority.
*/
if ( doing_filter( 'the_content' ) ) {
return $loading_attrs;
}
// Conditionally skip lazy-loading on images before the loop.
if (
// Only apply for main query but before the loop.
$wp_query->before_loop && $wp_query->is_main_query()
/*
* Any image before the loop, but after the header has started should not be lazy-loaded,
* except when the footer has already started which can happen when the current template
* does not include any loop.
*/
&& did_action( 'get_header' ) && ! did_action( 'get_footer' )
) {
// Increase media count if there are images in header above a certian minimum size threshold.
$maybe_increase_content_media_count();
return $postprocess( $loading_attrs, true );
}
}
/*
* The first elements in 'the_content' or 'the_post_thumbnail' should not be lazy-loaded,
* as they are likely above the fold. Shortcodes are processed after content images, so if
* thresholds haven't already been met, apply the same logic to those as well.
*/
if ( 'the_content' === $context || 'the_post_thumbnail' === $context || 'do_shortcode' === $context ) {
// Only elements within the main query loop have special handling.
if ( is_admin() || ! in_the_loop() || ! is_main_query() ) {
$loading_attrs['loading'] = 'lazy';
return $postprocess( $loading_attrs, false );
}
// Increase the counter since this is a main query content element.
$content_media_count = wp_increase_content_media_count();
// If the count so far is below the threshold, `loading` attribute is omitted.
if ( $content_media_count <= wp_omit_loading_attr_threshold() ) {
// The first largest image will still get `fetchpriority='high'`.
return $postprocess( $loading_attrs, true );
}
}
// Lazy-load by default for any unknown context.
$loading_attrs['loading'] = 'lazy';
return $postprocess( $loading_attrs, false );
}
Hooks
-
apply_filters( 'wp_min_priority_img_pixels',
int $threshold ) -
Filters the minimum square-pixels threshold for an image to be eligible as the high-priority image.
Changelog
Version | Description |
---|---|
6.3.0 | Introduced. |