Changeset 56347
- Timestamp:
- 08/02/2023 05:56:16 PM (16 months ago)
- Location:
- trunk
- Files:
-
- 2 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/wp-includes/media.php
r56283 r56347 5605 5605 global $wp_query; 5606 5606 5607 /*5608 * Closure for postprocessing logic.5609 * It is here to avoid duplicate logic in many places below, without having5610 * 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 5634 5607 $loading_attrs = array(); 5635 5608 … … 5652 5625 } 5653 5626 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; 5640 } 5641 } 5642 5643 /* 5644 * The key function logic starts here. 5645 */ 5646 $maybe_in_viewport = null; 5647 $increase_count = false; 5648 $maybe_increase_count = false; 5649 5650 // Logic to handle a `loading` attribute that is already provided. 5654 5651 if ( isset( $attr['loading'] ) ) { 5655 5652 /* 5656 * While any `loading` value could be set in `$loading_attrs`, for5657 * consistency we only do it for `loading="lazy"` since that is the5658 * only possible value that WordPress core would apply on its own.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). 5659 5656 */ 5660 5657 if ( 'lazy' === $attr['loading'] ) { 5658 $maybe_in_viewport = false; 5659 } else { 5660 $maybe_in_viewport = true; 5661 } 5662 } 5663 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 ); 5679 /* 5680 * Set `fetchpriority` here for backward-compatibility as we should 5681 * not override what a developer decided, even though it seems 5682 * incorrect. 5683 */ 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; 5749 } 5750 } 5751 5752 /* 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". 5757 */ 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 ) ) { 5661 5763 $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 ); 5668 } 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 ); 5764 } 5677 5765 } 5678 5766 5679 5767 /* 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. 5682 */ 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 } 5696 5697 // Special handling for programmatically created image tags. 5698 if ( 'the_post_thumbnail' === $context || 'wp_get_attachment_image' === $context || 'widget_media_image' === $context ) { 5699 /* 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. 5705 */ 5706 if ( doing_filter( 'the_content' ) ) { 5707 return $loading_attrs; 5708 } 5709 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() 5714 /* 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. 5718 */ 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 ); 5724 } 5725 } 5726 5727 /* 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. 5731 */ 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() ) { 5735 $loading_attrs['loading'] = 'lazy'; 5736 return $postprocess( $loading_attrs, false ); 5737 } 5738 5739 // Increase the counter since this is a main query content element. 5740 $content_media_count = wp_increase_content_media_count(); 5741 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 ); 5746 } 5747 } 5748 5749 // Lazy-load by default for any unknown context. 5750 $loading_attrs['loading'] = 'lazy'; 5751 return $postprocess( $loading_attrs, false ); 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 ); 5777 5778 if ( $wp_min_priority_img_pixels <= $attr['width'] * $attr['height'] ) { 5779 wp_increase_content_media_count(); 5780 } 5781 } 5782 5783 return $loading_attrs; 5752 5784 } 5753 5785 -
trunk/tests/phpunit/tests/media.php
r56214 r56347 4957 4957 $attr['fetchpriority'] = 'high'; 4958 4958 4959 $this->assert Same(4959 $this->assertEqualSetsWithIndex( 4960 4960 array( 4961 4961 'loading' => 'lazy',
Note: See TracChangeset
for help on using the changeset viewer.