@@ -5604,33 +5604,6 @@ function wp_get_webp_info( $filename ) {
56045604function wp_get_loading_optimization_attributes ( $ tag_name , $ attr , $ context ) {
56055605 global $ wp_query ;
56065606
5607- /*
5608- * Closure for postprocessing logic.
5609- * It is here to avoid duplicate logic in many places below, without having
5610- * to introduce a very specific private global function.
5611- */
5612- $ postprocess = static function ( $ loading_attributes , $ with_fetchpriority = false ) use ( $ tag_name , $ attr , $ context ) {
5613- // Potentially add `fetchpriority="high"`.
5614- if ( $ with_fetchpriority ) {
5615- $ loading_attributes = wp_maybe_add_fetchpriority_high_attr ( $ loading_attributes , $ tag_name , $ attr );
5616- }
5617- // Potentially strip `loading="lazy"` if the feature is disabled.
5618- if ( isset ( $ loading_attributes ['loading ' ] ) && ! wp_lazy_loading_enabled ( $ tag_name , $ context ) ) {
5619- unset( $ loading_attributes ['loading ' ] );
5620- }
5621- return $ loading_attributes ;
5622- };
5623-
5624- // Closure to increase media count for images with certain minimum threshold, mostly used for header images.
5625- $ maybe_increase_content_media_count = static function () use ( $ attr ) {
5626- /** This filter is documented in wp-admin/includes/media.php */
5627- $ wp_min_priority_img_pixels = apply_filters ( 'wp_min_priority_img_pixels ' , 50000 );
5628- // Images with a certain minimum size in the header of the page are also counted towards the threshold.
5629- if ( $ wp_min_priority_img_pixels <= $ attr ['width ' ] * $ attr ['height ' ] ) {
5630- wp_increase_content_media_count ();
5631- }
5632- };
5633-
56345607 $ loading_attrs = array ();
56355608
56365609 /*
@@ -5651,104 +5624,163 @@ function wp_get_loading_optimization_attributes( $tag_name, $attr, $context ) {
56515624 return $ loading_attrs ;
56525625 }
56535626
5654- if ( isset ( $ attr ['loading ' ] ) ) {
5655- /*
5656- * While any `loading` value could be set in `$loading_attrs`, for
5657- * consistency we only do it for `loading="lazy"` since that is the
5658- * only possible value that WordPress core would apply on its own.
5659- */
5660- if ( 'lazy ' === $ attr ['loading ' ] ) {
5661- $ loading_attrs ['loading ' ] = 'lazy ' ;
5662- if ( isset ( $ attr ['fetchpriority ' ] ) && 'high ' === $ attr ['fetchpriority ' ] ) {
5663- _doing_it_wrong (
5664- __FUNCTION__ ,
5665- __ ( 'An image should not be lazy-loaded and marked as high priority at the same time. ' ),
5666- '6.3.0 '
5667- );
5627+ /*
5628+ * Skip programmatically created images within post content as they need to be handled together with the other
5629+ * images within the post content.
5630+ * Without this clause, they would already be considered within their own context which skews the image count and
5631+ * can result in the first post content image being lazy-loaded or an image further down the page being marked as a
5632+ * high priority.
5633+ */
5634+ switch ( $ context ) {
5635+ case 'the_post_thumbnail ' :
5636+ case 'wp_get_attachment_image ' :
5637+ case 'widget_media_image ' :
5638+ if ( doing_filter ( 'the_content ' ) ) {
5639+ return $ loading_attrs ;
56685640 }
5669- }
5670-
5671- return $ postprocess ( $ loading_attrs , true );
5672- }
5673-
5674- // An image with `fetchpriority="high"` cannot be assigned `loading="lazy"` at the same time.
5675- if ( isset ( $ attr ['fetchpriority ' ] ) && 'high ' === $ attr ['fetchpriority ' ] ) {
5676- return $ postprocess ( $ loading_attrs , true );
56775641 }
56785642
56795643 /*
5680- * Do not lazy-load images in the header block template part, as they are likely above the fold.
5681- * For classic themes, this is handled in the condition below using the 'get_header' action.
5644+ * The key function logic starts here.
56825645 */
5683- $ header_area = WP_TEMPLATE_PART_AREA_HEADER ;
5684- if ( "template_part_ {$ header_area }" === $ context ) {
5685- // Increase media count if there are images in header above a certian minimum size threshold.
5686- $ maybe_increase_content_media_count ();
5687- return $ postprocess ( $ loading_attrs , true );
5688- }
5689-
5690- // The custom header image is always expected to be in the header.
5691- if ( 'get_header_image_tag ' === $ context ) {
5692- // Increase media count if there are images in header above a certian minimum size threshold.
5693- $ maybe_increase_content_media_count ();
5694- return $ postprocess ( $ loading_attrs , true );
5695- }
5646+ $ maybe_in_viewport = null ;
5647+ $ increase_count = false ;
5648+ $ maybe_increase_count = false ;
56965649
5697- // Special handling for programmatically created image tags .
5698- if ( ' the_post_thumbnail ' === $ context || ' wp_get_attachment_image ' === $ context || ' widget_media_image ' === $ context ) {
5650+ // Logic to handle a `loading` attribute that is already provided .
5651+ if ( isset ( $ attr [ ' loading ' ] ) ) {
56995652 /*
5700- * Skip programmatically created images within post content as they need to be handled together with the other
5701- * images within the post content.
5702- * Without this clause, they would already be considered below which skews the image count and can result in
5703- * the first post content image being lazy-loaded or an image further down the page being marked as a high
5704- * priority.
5653+ * Interpret "lazy" as not in viewport. Any other value can be
5654+ * interpreted as in viewport (realistically only "eager" or `false`
5655+ * to force-omit the attribute are other potential values).
57055656 */
5706- if ( doing_filter ( 'the_content ' ) ) {
5707- return $ loading_attrs ;
5657+ if ( 'lazy ' === $ attr ['loading ' ] ) {
5658+ $ maybe_in_viewport = false ;
5659+ } else {
5660+ $ maybe_in_viewport = true ;
57085661 }
5662+ }
57095663
5710- // Conditionally skip lazy-loading on images before the loop.
5711- if (
5712- // Only apply for main query but before the loop.
5713- $ wp_query ->before_loop && $ wp_query ->is_main_query ()
5664+ // Logic to handle a `fetchpriority` attribute that is already provided.
5665+ if ( isset ( $ attr ['fetchpriority ' ] ) && 'high ' === $ attr ['fetchpriority ' ] ) {
5666+ /*
5667+ * If the image was already determined to not be in the viewport (e.g.
5668+ * from an already provided `loading` attribute), trigger a warning.
5669+ * Otherwise, the value can be interpreted as in viewport, since only
5670+ * the most important in-viewport image should have `fetchpriority` set
5671+ * to "high".
5672+ */
5673+ if ( false === $ maybe_in_viewport ) {
5674+ _doing_it_wrong (
5675+ __FUNCTION__ ,
5676+ __ ( 'An image should not be lazy-loaded and marked as high priority at the same time. ' ),
5677+ '6.3.0 '
5678+ );
57145679 /*
5715- * Any image before the loop, but after the header has started should not be lazy-loaded,
5716- * except when the footer has already started which can happen when the current template
5717- * does not include any loop .
5680+ * Set `fetchpriority` here for backward-compatibility as we should
5681+ * not override what a developer decided, even though it seems
5682+ * incorrect .
57185683 */
5719- && did_action ( 'get_header ' ) && ! did_action ( 'get_footer ' )
5720- ) {
5721- // Increase media count if there are images in header above a certian minimum size threshold.
5722- $ maybe_increase_content_media_count ();
5723- return $ postprocess ( $ loading_attrs , true );
5684+ $ loading_attrs ['fetchpriority ' ] = 'high ' ;
5685+ } else {
5686+ $ maybe_in_viewport = true ;
5687+ }
5688+ }
5689+
5690+ if ( null === $ maybe_in_viewport ) {
5691+ switch ( $ context ) {
5692+ // Consider elements with these header-specific contexts to be in viewport.
5693+ case 'template_part_ ' . WP_TEMPLATE_PART_AREA_HEADER :
5694+ case 'get_header_image_tag ' :
5695+ $ maybe_in_viewport = true ;
5696+ $ maybe_increase_count = true ;
5697+ break ;
5698+ // Count main content elements and detect whether in viewport.
5699+ case 'the_content ' :
5700+ case 'the_post_thumbnail ' :
5701+ case 'do_shortcode ' :
5702+ // Only elements within the main query loop have special handling.
5703+ if ( ! is_admin () && in_the_loop () && is_main_query () ) {
5704+ /*
5705+ * Get the content media count, since this is a main query
5706+ * content element. This is accomplished by "increasing"
5707+ * the count by zero, as the only way to get the count is
5708+ * to call this function.
5709+ * The actual count increase happens further below, based
5710+ * on the `$increase_count` flag set here.
5711+ */
5712+ $ content_media_count = wp_increase_content_media_count ( 0 );
5713+ $ increase_count = true ;
5714+
5715+ // If the count so far is below the threshold, `loading` attribute is omitted.
5716+ if ( $ content_media_count < wp_omit_loading_attr_threshold () ) {
5717+ $ maybe_in_viewport = true ;
5718+ } else {
5719+ $ maybe_in_viewport = false ;
5720+ }
5721+ }
5722+ /*
5723+ * For the 'the_post_thumbnail' context, the following case
5724+ * clause needs to be considered as well, therefore skip the
5725+ * break statement here if the viewport has not been
5726+ * determined.
5727+ */
5728+ if ( 'the_post_thumbnail ' !== $ context || null !== $ maybe_in_viewport ) {
5729+ break ;
5730+ }
5731+ // phpcs:ignore Generic.WhiteSpace.ScopeIndent.Incorrect
5732+ // Consider elements before the loop as being in viewport.
5733+ case 'wp_get_attachment_image ' :
5734+ case 'widget_media_image ' :
5735+ if (
5736+ // Only apply for main query but before the loop.
5737+ $ wp_query ->before_loop && $ wp_query ->is_main_query ()
5738+ /*
5739+ * Any image before the loop, but after the header has started should not be lazy-loaded,
5740+ * except when the footer has already started which can happen when the current template
5741+ * does not include any loop.
5742+ */
5743+ && did_action ( 'get_header ' ) && ! did_action ( 'get_footer ' )
5744+ ) {
5745+ $ maybe_in_viewport = true ;
5746+ $ maybe_increase_count = true ;
5747+ }
5748+ break ;
57245749 }
57255750 }
57265751
57275752 /*
5728- * The first elements in 'the_content' or 'the_post_thumbnail' should not be lazy-loaded,
5729- * as they are likely above the fold. Shortcodes are processed after content images, so if
5730- * thresholds haven't already been met, apply the same logic to those as well.
5753+ * If the element is in the viewport (`true`), potentially add
5754+ * `fetchpriority` with a value of "high". Otherwise, i.e. if the element
5755+ * is not not in the viewport (`false`) or it is unknown (`null`), add
5756+ * `loading` with a value of "lazy".
57315757 */
5732- if ( 'the_content ' === $ context || 'the_post_thumbnail ' === $ context || 'do_shortcode ' === $ context ) {
5733- // Only elements within the main query loop have special handling.
5734- if ( is_admin () || ! in_the_loop () || ! is_main_query () ) {
5758+ if ( $ maybe_in_viewport ) {
5759+ $ loading_attrs = wp_maybe_add_fetchpriority_high_attr ( $ loading_attrs , $ tag_name , $ attr );
5760+ } else {
5761+ // Only add `loading="lazy"` if the feature is enabled.
5762+ if ( wp_lazy_loading_enabled ( $ tag_name , $ context ) ) {
57355763 $ loading_attrs ['loading ' ] = 'lazy ' ;
5736- return $ postprocess ( $ loading_attrs , false );
57375764 }
5765+ }
57385766
5739- // Increase the counter since this is a main query content element.
5740- $ content_media_count = wp_increase_content_media_count ();
5767+ /*
5768+ * If flag was set based on contextual logic above, increase the content
5769+ * media count, either unconditionally, or based on whether the image size
5770+ * is larger than the threshold.
5771+ */
5772+ if ( $ increase_count ) {
5773+ wp_increase_content_media_count ();
5774+ } elseif ( $ maybe_increase_count ) {
5775+ /** This filter is documented in wp-admin/includes/media.php */
5776+ $ wp_min_priority_img_pixels = apply_filters ( 'wp_min_priority_img_pixels ' , 50000 );
57415777
5742- // If the count so far is below the threshold, `loading` attribute is omitted.
5743- if ( $ content_media_count <= wp_omit_loading_attr_threshold () ) {
5744- // The first largest image will still get `fetchpriority='high'`.
5745- return $ postprocess ( $ loading_attrs , true );
5778+ if ( $ wp_min_priority_img_pixels <= $ attr ['width ' ] * $ attr ['height ' ] ) {
5779+ wp_increase_content_media_count ();
57465780 }
57475781 }
57485782
5749- // Lazy-load by default for any unknown context.
5750- $ loading_attrs ['loading ' ] = 'lazy ' ;
5751- return $ postprocess ( $ loading_attrs , false );
5783+ return $ loading_attrs ;
57525784}
57535785
57545786/**
0 commit comments