Media: Conditionally skip lazy-loading on images before the loop to improve LCP performance.
When the logic to exclude images that likely appear above the fold from being lazy-loaded was introduced in WordPress 5.9, initially only images that appear within the main query loop were being considered. However, there is a good chance that images above the fold are rendered before the loop starts, for example in the header template part. It is particularly common for a theme to display the featured image for a single post in the header. Based on HTTP Archive data from February 2023, the majority of LCP images that are still being lazy-loaded on WordPress sites use the `wp-post-image` class, i.e. are featured images. This changeset enhances the logic in `wp_get_loading_attr_default()` to not lazy-load images that appear within or after the header template part and before the query loop, using a new `WP_Query::$before_loop` property. For block themes, this was for the most part already addressed in [55318], however this enhancement implements the solution in a more generally applicable way that brings the improvement to classic themes as well. Props thekt12, flixos90, spacedmonkey, costdev, zunaid321, mukesh27. Fixes #58211. See #53675, #56930. Built from https://develop.svn.wordpress.org/trunk@55847 git-svn-id: http://core.svn.wordpress.org/trunk@55359 1a063a9b-81f0-0310-95a4-ce76da25c4cd
This commit is contained in:
parent
e182459c6d
commit
c6f9238b77
|
@ -108,6 +108,14 @@ class WP_Query {
|
||||||
*/
|
*/
|
||||||
public $current_post = -1;
|
public $current_post = -1;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether the caller is before the loop.
|
||||||
|
*
|
||||||
|
* @since 6.3.0
|
||||||
|
* @var bool
|
||||||
|
*/
|
||||||
|
public $before_loop = true;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Whether the loop has started and the caller is in the loop.
|
* Whether the loop has started and the caller is in the loop.
|
||||||
*
|
*
|
||||||
|
@ -517,6 +525,7 @@ class WP_Query {
|
||||||
$this->post_count = 0;
|
$this->post_count = 0;
|
||||||
$this->current_post = -1;
|
$this->current_post = -1;
|
||||||
$this->in_the_loop = false;
|
$this->in_the_loop = false;
|
||||||
|
$this->before_loop = true;
|
||||||
unset( $this->request );
|
unset( $this->request );
|
||||||
unset( $this->post );
|
unset( $this->post );
|
||||||
unset( $this->comments );
|
unset( $this->comments );
|
||||||
|
@ -3631,6 +3640,7 @@ class WP_Query {
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->in_the_loop = true;
|
$this->in_the_loop = true;
|
||||||
|
$this->before_loop = false;
|
||||||
|
|
||||||
if ( -1 == $this->current_post ) { // Loop has just started.
|
if ( -1 == $this->current_post ) { // Loop has just started.
|
||||||
/**
|
/**
|
||||||
|
@ -3671,6 +3681,8 @@ class WP_Query {
|
||||||
// Do some cleaning up after the loop.
|
// Do some cleaning up after the loop.
|
||||||
$this->rewind_posts();
|
$this->rewind_posts();
|
||||||
} elseif ( 0 === $this->post_count ) {
|
} elseif ( 0 === $this->post_count ) {
|
||||||
|
$this->before_loop = false;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Fires if no results are found in a post query.
|
* Fires if no results are found in a post query.
|
||||||
*
|
*
|
||||||
|
|
|
@ -5490,32 +5490,54 @@ function wp_get_webp_info( $filename ) {
|
||||||
*
|
*
|
||||||
* @since 5.9.0
|
* @since 5.9.0
|
||||||
*
|
*
|
||||||
|
* @global WP_Query $wp_query WordPress Query object.
|
||||||
|
*
|
||||||
* @param string $context Context for the element for which the `loading` attribute value is requested.
|
* @param string $context Context for the element for which the `loading` attribute value is requested.
|
||||||
* @return string|bool The default `loading` attribute value. Either 'lazy', 'eager', or a boolean `false`, to indicate
|
* @return string|bool The default `loading` attribute value. Either 'lazy', 'eager', or a boolean `false`, to indicate
|
||||||
* that the `loading` attribute should be skipped.
|
* that the `loading` attribute should be skipped.
|
||||||
*/
|
*/
|
||||||
function wp_get_loading_attr_default( $context ) {
|
function wp_get_loading_attr_default( $context ) {
|
||||||
|
global $wp_query;
|
||||||
|
|
||||||
// Skip lazy-loading for the overall block template, as it is handled more granularly.
|
// Skip lazy-loading for the overall block template, as it is handled more granularly.
|
||||||
if ( 'template' === $context ) {
|
if ( 'template' === $context ) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Do not lazy-load images in the header block template part, as they are likely above the fold.
|
// 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;
|
$header_area = WP_TEMPLATE_PART_AREA_HEADER;
|
||||||
if ( "template_part_{$header_area}" === $context ) {
|
if ( "template_part_{$header_area}" === $context ) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Special handling for programmatically created image tags.
|
||||||
|
if ( ( 'the_post_thumbnail' === $context || 'wp_get_attachment_image' === $context ) ) {
|
||||||
/*
|
/*
|
||||||
* Skip programmatically created images within post content as they need to be handled together with the other
|
* Skip programmatically created images within post content as they need to be handled together with the other
|
||||||
* images within the post content.
|
* images within the post content.
|
||||||
* Without this clause, they would already be counted below which skews the number and can result in the first
|
* Without this clause, they would already be counted below which skews the number and can result in the first
|
||||||
* post content image being lazy-loaded only because there are images elsewhere in the post content.
|
* post content image being lazy-loaded only because there are images elsewhere in the post content.
|
||||||
*/
|
*/
|
||||||
if ( ( 'the_post_thumbnail' === $context || 'wp_get_attachment_image' === $context ) && doing_filter( 'the_content' ) ) {
|
if ( doing_filter( 'the_content' ) ) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 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' )
|
||||||
|
) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The first elements in 'the_content' or 'the_post_thumbnail' should not be lazy-loaded,
|
* The first elements in 'the_content' or 'the_post_thumbnail' should not be lazy-loaded,
|
||||||
* as they are likely above the fold.
|
* as they are likely above the fold.
|
||||||
|
|
|
@ -16,7 +16,7 @@
|
||||||
*
|
*
|
||||||
* @global string $wp_version
|
* @global string $wp_version
|
||||||
*/
|
*/
|
||||||
$wp_version = '6.3-alpha-55846';
|
$wp_version = '6.3-alpha-55847';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Holds the WordPress DB revision, increments when changes are made to the WordPress DB schema.
|
* Holds the WordPress DB revision, increments when changes are made to the WordPress DB schema.
|
||||||
|
|
Loading…
Reference in New Issue