Changeset 56037
- Timestamp:
- 06/26/2023 04:15:12 PM (16 months ago)
- Location:
- trunk
- Files:
-
- 4 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/wp-includes/deprecated.php
r56020 r56037 4659 4659 wp_lazyload_comment_meta( $comment_ids ); 4660 4660 } 4661 4662 /** 4663 * Gets the default value to use for a `loading` attribute on an element. 4664 * 4665 * This function should only be called for a tag and context if lazy-loading is generally enabled. 4666 * 4667 * The function usually returns 'lazy', but uses certain heuristics to guess whether the current element is likely to 4668 * appear above the fold, in which case it returns a boolean `false`, which will lead to the `loading` attribute being 4669 * omitted on the element. The purpose of this refinement is to avoid lazy-loading elements that are within the initial 4670 * viewport, which can have a negative performance impact. 4671 * 4672 * Under the hood, the function uses {@see wp_increase_content_media_count()} every time it is called for an element 4673 * within the main content. If the element is the very first content element, the `loading` attribute will be omitted. 4674 * This default threshold of 3 content elements to omit the `loading` attribute for can be customized using the 4675 * {@see 'wp_omit_loading_attr_threshold'} filter. 4676 * 4677 * @since 5.9.0 4678 * @deprecated 6.3.0 Use wp_get_loading_optimization_attributes() instead. 4679 * @see wp_get_loading_optimization_attributes() 4680 * 4681 * @global WP_Query $wp_query WordPress Query object. 4682 * 4683 * @param string $context Context for the element for which the `loading` attribute value is requested. 4684 * @return string|bool The default `loading` attribute value. Either 'lazy', 'eager', or a boolean `false`, to indicate 4685 * that the `loading` attribute should be skipped. 4686 */ 4687 function wp_get_loading_attr_default( $context ) { 4688 _deprecated_function( __FUNCTION__, '6.3.0', 'wp_get_loading_optimization_attributes' ); 4689 global $wp_query; 4690 4691 // Skip lazy-loading for the overall block template, as it is handled more granularly. 4692 if ( 'template' === $context ) { 4693 return false; 4694 } 4695 4696 /* 4697 * Do not lazy-load images in the header block template part, as they are likely above the fold. 4698 * For classic themes, this is handled in the condition below using the 'get_header' action. 4699 */ 4700 $header_area = WP_TEMPLATE_PART_AREA_HEADER; 4701 if ( "template_part_{$header_area}" === $context ) { 4702 return false; 4703 } 4704 4705 // Special handling for programmatically created image tags. 4706 if ( 'the_post_thumbnail' === $context || 'wp_get_attachment_image' === $context ) { 4707 /* 4708 * Skip programmatically created images within post content as they need to be handled together with the other 4709 * images within the post content. 4710 * Without this clause, they would already be counted below which skews the number and can result in the first 4711 * post content image being lazy-loaded only because there are images elsewhere in the post content. 4712 */ 4713 if ( doing_filter( 'the_content' ) ) { 4714 return false; 4715 } 4716 4717 // Conditionally skip lazy-loading on images before the loop. 4718 if ( 4719 // Only apply for main query but before the loop. 4720 $wp_query->before_loop && $wp_query->is_main_query() 4721 /* 4722 * Any image before the loop, but after the header has started should not be lazy-loaded, 4723 * except when the footer has already started which can happen when the current template 4724 * does not include any loop. 4725 */ 4726 && did_action( 'get_header' ) && ! did_action( 'get_footer' ) 4727 ) { 4728 return false; 4729 } 4730 } 4731 4732 /* 4733 * The first elements in 'the_content' or 'the_post_thumbnail' should not be lazy-loaded, 4734 * as they are likely above the fold. 4735 */ 4736 if ( 'the_content' === $context || 'the_post_thumbnail' === $context ) { 4737 // Only elements within the main query loop have special handling. 4738 if ( is_admin() || ! in_the_loop() || ! is_main_query() ) { 4739 return 'lazy'; 4740 } 4741 4742 // Increase the counter since this is a main query content element. 4743 $content_media_count = wp_increase_content_media_count(); 4744 4745 // If the count so far is below the threshold, return `false` so that the `loading` attribute is omitted. 4746 if ( $content_media_count <= wp_omit_loading_attr_threshold() ) { 4747 return false; 4748 } 4749 4750 // For elements after the threshold, lazy-load them as usual. 4751 return 'lazy'; 4752 } 4753 4754 // Lazy-load by default for any unknown context. 4755 return 'lazy'; 4756 } 4757 4758 /** 4759 * Adds `loading` attribute to an `img` HTML tag. 4760 * 4761 * @since 5.5.0 4762 * @deprecated 6.3.0 Use wp_img_tag_add_loading_optimization_attrs() instead. 4763 * @see wp_img_tag_add_loading_optimization_attrs() 4764 * 4765 * @param string $image The HTML `img` tag where the attribute should be added. 4766 * @param string $context Additional context to pass to the filters. 4767 * @return string Converted `img` tag with `loading` attribute added. 4768 */ 4769 function wp_img_tag_add_loading_attr( $image, $context ) { 4770 _deprecated_function( __FUNCTION__, '6.3.0', 'wp_img_tag_add_loading_optimization_attrs' ); 4771 /* 4772 * Get loading attribute value to use. This must occur before the conditional check below so that even images that 4773 * are ineligible for being lazy-loaded are considered. 4774 */ 4775 $value = wp_get_loading_attr_default( $context ); 4776 4777 // Images should have source and dimension attributes for the `loading` attribute to be added. 4778 if ( ! str_contains( $image, ' src="' ) || ! str_contains( $image, ' width="' ) || ! str_contains( $image, ' height="' ) ) { 4779 return $image; 4780 } 4781 4782 /** 4783 * Filters the `loading` attribute value to add to an image. Default `lazy`. 4784 * 4785 * Returning `false` or an empty string will not add the attribute. 4786 * Returning `true` will add the default value. 4787 * 4788 * @since 5.5.0 4789 * 4790 * @param string|bool $value The `loading` attribute value. Returning a falsey value will result in 4791 * the attribute being omitted for the image. 4792 * @param string $image The HTML `img` tag to be filtered. 4793 * @param string $context Additional context about how the function was called or where the img tag is. 4794 */ 4795 $value = apply_filters( 'wp_img_tag_add_loading_attr', $value, $image, $context ); 4796 4797 if ( $value ) { 4798 if ( ! in_array( $value, array( 'lazy', 'eager' ), true ) ) { 4799 $value = 'lazy'; 4800 } 4801 4802 return str_replace( '<img', '<img loading="' . esc_attr( $value ) . '"', $image ); 4803 } 4804 4805 return $image; 4806 } -
trunk/src/wp-includes/media.php
r56031 r56037 1059 1059 */ 1060 1060 $context = apply_filters( 'wp_get_attachment_image_context', 'wp_get_attachment_image' ); 1061 1062 // Add `loading` attribute. 1063 if ( wp_lazy_loading_enabled( 'img', $context ) ) { 1064 $default_attr['loading'] = wp_get_loading_attr_default( $context ); 1065 } 1066 1067 $attr = wp_parse_args( $attr, $default_attr ); 1061 $attr = wp_parse_args( $attr, $default_attr ); 1062 1063 $loading_attr = $attr; 1064 $loading_attr['width'] = $width; 1065 $loading_attr['height'] = $height; 1066 $loading_optimization_attr = wp_get_loading_optimization_attributes( 1067 'img', 1068 $loading_attr, 1069 $context 1070 ); 1071 1072 // Add loading optimization attributes if not available. 1073 $attr = array_merge( $attr, $loading_optimization_attr ); 1068 1074 1069 1075 // Omit the `decoding` attribute if the value is invalid according to the spec. … … 1074 1080 // If the default value of `lazy` for the `loading` attribute is overridden 1075 1081 // to omit the attribute for this image, ensure it is not included. 1076 if ( array_key_exists( 'loading', $attr) && ! $attr['loading'] ) {1082 if ( isset( $attr['loading'] ) && ! $attr['loading'] ) { 1077 1083 unset( $attr['loading'] ); 1084 } 1085 1086 // If the `fetchpriority` attribute is overridden and set to false or an empty string. 1087 if ( isset( $attr['fetchpriority'] ) && ! $attr['fetchpriority'] ) { 1088 unset( $attr['fetchpriority'] ); 1078 1089 } 1079 1090 … … 1781 1792 * @see wp_img_tag_add_width_and_height_attr() 1782 1793 * @see wp_img_tag_add_srcset_and_sizes_attr() 1783 * @see wp_img_tag_add_loading_ attr()1794 * @see wp_img_tag_add_loading_optimization_attrs() 1784 1795 * @see wp_iframe_tag_add_loading_attr() 1785 1796 * … … 1794 1805 } 1795 1806 1796 $add_img_loading_attr = wp_lazy_loading_enabled( 'img', $context );1797 1807 $add_iframe_loading_attr = wp_lazy_loading_enabled( 'iframe', $context ); 1798 1808 … … 1858 1868 } 1859 1869 1860 // Add 'loading' attribute if applicable. 1861 if ( $add_img_loading_attr && ! str_contains( $filtered_image, ' loading=' ) ) { 1862 $filtered_image = wp_img_tag_add_loading_attr( $filtered_image, $context ); 1863 } 1870 // Add loading optimization attributes if applicable. 1871 $filtered_image = wp_img_tag_add_loading_optimization_attrs( $filtered_image, $context ); 1864 1872 1865 1873 // Add 'decoding=async' attribute unless a 'decoding' attribute is already present. … … 1915 1923 1916 1924 /** 1917 * Adds `loading` attributeto an `img` HTML tag.1918 * 1919 * @since 5.5.01925 * Adds optimization attributes to an `img` HTML tag. 1926 * 1927 * @since 6.3.0 1920 1928 * 1921 1929 * @param string $image The HTML `img` tag where the attribute should be added. 1922 1930 * @param string $context Additional context to pass to the filters. 1923 * @return string Converted `img` tag with `loading` attribute added. 1924 */ 1925 function wp_img_tag_add_loading_attr( $image, $context ) { 1926 // Get loading attribute value to use. This must occur before the conditional check below so that even images that 1927 // are ineligible for being lazy-loaded are considered. 1928 $value = wp_get_loading_attr_default( $context ); 1929 1930 // Images should have source and dimension attributes for the `loading` attribute to be added. 1931 * @return string Converted `img` tag with optimization attributes added. 1932 */ 1933 function wp_img_tag_add_loading_optimization_attrs( $image, $context ) { 1934 $width = preg_match( '/ width=["\']([0-9]+)["\']/', $image, $match_width ) ? (int) $match_width[1] : null; 1935 $height = preg_match( '/ height=["\']([0-9]+)["\']/', $image, $match_height ) ? (int) $match_height[1] : null; 1936 $loading_val = preg_match( '/ loading=["\']([A-Za-z]+)["\']/', $image, $match_loading ) ? $match_loading[1] : null; 1937 $fetchpriority_val = preg_match( '/ fetchpriority=["\']([A-Za-z]+)["\']/', $image, $match_fetchpriority ) ? $match_fetchpriority[1] : null; 1938 1939 /* 1940 * Get loading optimization attributes to use. 1941 * This must occur before the conditional check below so that even images 1942 * that are ineligible for being lazy-loaded are considered. 1943 */ 1944 $optimization_attrs = wp_get_loading_optimization_attributes( 1945 'img', 1946 array( 1947 'width' => $width, 1948 'height' => $height, 1949 'loading' => $loading_val, 1950 'fetchpriority' => $fetchpriority_val, 1951 ), 1952 $context 1953 ); 1954 1955 // Images should have source and dimension attributes for the loading optimization attributes to be added. 1931 1956 if ( ! str_contains( $image, ' src="' ) || ! str_contains( $image, ' width="' ) || ! str_contains( $image, ' height="' ) ) { 1932 1957 return $image; 1933 1958 } 1934 1959 1935 /** 1936 * Filters the `loading` attribute value to add to an image. Default `lazy`. 1937 * 1938 * Returning `false` or an empty string will not add the attribute. 1939 * Returning `true` will add the default value. 1940 * 1941 * @since 5.5.0 1942 * 1943 * @param string|bool $value The `loading` attribute value. Returning a falsey value will result in 1944 * the attribute being omitted for the image. 1945 * @param string $image The HTML `img` tag to be filtered. 1946 * @param string $context Additional context about how the function was called or where the img tag is. 1947 */ 1948 $value = apply_filters( 'wp_img_tag_add_loading_attr', $value, $image, $context ); 1949 1950 if ( $value ) { 1951 if ( ! in_array( $value, array( 'lazy', 'eager' ), true ) ) { 1952 $value = 'lazy'; 1953 } 1954 1955 return str_replace( '<img', '<img loading="' . esc_attr( $value ) . '"', $image ); 1960 // Retained for backward compatibility. 1961 $loading_attrs_enabled = wp_lazy_loading_enabled( 'img', $context ); 1962 1963 if ( empty( $loading_val ) && $loading_attrs_enabled ) { 1964 /** 1965 * Filters the `loading` attribute value to add to an image. Default `lazy`. 1966 * This filter is added in for backward compatibility. 1967 * 1968 * Returning `false` or an empty string will not add the attribute. 1969 * Returning `true` will add the default value. 1970 * `true` and `false` usage supported for backward compatibility. 1971 * 1972 * @since 5.5.0 1973 * 1974 * @param string|bool $loading Current value for `loading` attribute for the image. 1975 * @param string $image The HTML `img` tag to be filtered. 1976 * @param string $context Additional context about how the function was called or where the img tag is. 1977 */ 1978 $filtered_loading_attr = apply_filters( 1979 'wp_img_tag_add_loading_attr', 1980 isset( $optimization_attrs['loading'] ) ? $optimization_attrs['loading'] : false, 1981 $image, 1982 $context 1983 ); 1984 1985 // Validate the values after filtering. 1986 if ( isset( $optimization_attrs['loading'] ) && ! $filtered_loading_attr ) { 1987 // Unset `loading` attributes if `$filtered_loading_attr` is set to `false`. 1988 unset( $optimization_attrs['loading'] ); 1989 } elseif ( in_array( $filtered_loading_attr, array( 'lazy', 'eager' ), true ) ) { 1990 /* 1991 * If the filter changed the loading attribute to "lazy" when a fetchpriority attribute 1992 * with value "high" is already present, trigger a warning since those two attribute 1993 * values should be mutually exclusive. 1994 * 1995 * The same warning is present in `wp_get_loading_optimization_attributes()`, and here it 1996 * is only intended for the specific scenario where the above filtered caused the problem. 1997 */ 1998 if ( isset( $optimization_attrs['fetchpriority'] ) && 'high' === $optimization_attrs['fetchpriority'] && 1999 ( isset( $optimization_attrs['loading'] ) ? $optimization_attrs['loading'] : false ) !== $filtered_loading_attr && 2000 'lazy' === $filtered_loading_attr 2001 ) { 2002 _doing_it_wrong( 2003 __FUNCTION__, 2004 __( 'An image should not be lazy-loaded and marked as high priority at the same time.' ), 2005 '6.3.0' 2006 ); 2007 } 2008 2009 // The filtered value will still be respected. 2010 $optimization_attrs['loading'] = $filtered_loading_attr; 2011 } 2012 2013 if ( ! empty( $optimization_attrs['loading'] ) ) { 2014 $image = str_replace( '<img', '<img loading="' . esc_attr( $optimization_attrs['loading'] ) . '"', $image ); 2015 } 2016 } 2017 2018 if ( empty( $fetchpriority_val ) && ! empty( $optimization_attrs['fetchpriority'] ) ) { 2019 $image = str_replace( '<img', '<img fetchpriority="' . esc_attr( $optimization_attrs['fetchpriority'] ) . '"', $image ); 1956 2020 } 1957 2021 … … 2104 2168 // Get loading attribute value to use. This must occur before the conditional check below so that even iframes that 2105 2169 // are ineligible for being lazy-loaded are considered. 2106 $value = wp_get_loading_attr_default( $context ); 2170 $optimization_attrs = wp_get_loading_optimization_attributes( 2171 'iframe', 2172 array( 2173 /* 2174 * The concrete values for width and height are not important here for now 2175 * since fetchpriority is not yet supported for iframes. 2176 * TODO: Use WP_HTML_Tag_Processor to extract actual values once support is 2177 * added. 2178 */ 2179 'width' => str_contains( $iframe, ' width="' ) ? 100 : null, 2180 'height' => str_contains( $iframe, ' height="' ) ? 100 : null, 2181 // This function is never called when a 'loading' attribute is already present. 2182 'loading' => null, 2183 ), 2184 $context 2185 ); 2107 2186 2108 2187 // Iframes should have source and dimension attributes for the `loading` attribute to be added. … … 2110 2189 return $iframe; 2111 2190 } 2191 2192 $value = isset( $optimization_attrs['loading'] ) ? $optimization_attrs['loading'] : false; 2112 2193 2113 2194 /** … … 5470 5551 5471 5552 /** 5472 * Gets the default value to use for a `loading` attribute on an element. 5473 * 5474 * This function should only be called for a tag and context if lazy-loading is generally enabled. 5475 * 5476 * The function usually returns 'lazy', but uses certain heuristics to guess whether the current element is likely to 5477 * appear above the fold, in which case it returns a boolean `false`, which will lead to the `loading` attribute being 5478 * omitted on the element. The purpose of this refinement is to avoid lazy-loading elements that are within the initial 5479 * viewport, which can have a negative performance impact. 5480 * 5481 * Under the hood, the function uses {@see wp_increase_content_media_count()} every time it is called for an element 5482 * within the main content. If the element is the very first content element, the `loading` attribute will be omitted. 5483 * This default threshold of 3 content elements to omit the `loading` attribute for can be customized using the 5484 * {@see 'wp_omit_loading_attr_threshold'} filter. 5485 * 5486 * @since 5.9.0 5553 * Gets loading optimization attributes. 5554 * 5555 * This function returns an array of attributes that should be merged into the given attributes array to optimize 5556 * loading performance. Potential attributes returned by this function are: 5557 * - `loading` attribute with a value of "lazy" 5558 * - `fetchpriority` attribute with a value of "high" 5559 * 5560 * If any of these attributes are already present in the given attributes, they will not be modified. Note that no 5561 * element should have both `loading="lazy"` and `fetchpriority="high"`, so the function will trigger a warning in case 5562 * both attributes are present with those values. 5563 * 5564 * @since 6.3.0 5487 5565 * 5488 5566 * @global WP_Query $wp_query WordPress Query object. 5489 5567 * 5490 * @param string $context Context for the element for which the `loading` attribute value is requested. 5491 * @return string|bool The default `loading` attribute value. Either 'lazy', 'eager', or a boolean `false`, to indicate 5492 * that the `loading` attribute should be skipped. 5493 */ 5494 function wp_get_loading_attr_default( $context ) { 5568 * @param string $tag_name The tag name. 5569 * @param array $attr Array of the attributes for the tag. 5570 * @param string $context Context for the element for which the loading optimization attribute is requested. 5571 * @return array Loading optimization attributes. 5572 */ 5573 function wp_get_loading_optimization_attributes( $tag_name, $attr, $context ) { 5495 5574 global $wp_query; 5496 5575 5497 // Skip lazy-loading for the overall block template, as it is handled more granularly. 5576 /* 5577 * Closure for postprocessing logic. 5578 * It is here to avoid duplicate logic in many places below, without having 5579 * to introduce a very specific private global function. 5580 */ 5581 $postprocess = static function( $loading_attributes, $with_fetchpriority = false ) use ( $tag_name, $attr, $context ) { 5582 // Potentially add `fetchpriority="high"`. 5583 if ( $with_fetchpriority ) { 5584 $loading_attributes = wp_maybe_add_fetchpriority_high_attr( $loading_attributes, $tag_name, $attr ); 5585 } 5586 // Potentially strip `loading="lazy"` if the feature is disabled. 5587 if ( isset( $loading_attributes['loading'] ) && ! wp_lazy_loading_enabled( $tag_name, $context ) ) { 5588 unset( $loading_attributes['loading'] ); 5589 } 5590 return $loading_attributes; 5591 }; 5592 5593 $loading_attrs = array(); 5594 5595 /* 5596 * Skip lazy-loading for the overall block template, as it is handled more granularly. 5597 * The skip is also applicable for `fetchpriority`. 5598 */ 5498 5599 if ( 'template' === $context ) { 5499 return false; 5500 } 5501 5502 // Do not lazy-load images in the header block template part, as they are likely above the fold. 5503 // For classic themes, this is handled in the condition below using the 'get_header' action. 5600 return $loading_attrs; 5601 } 5602 5603 // For now this function only supports images and iframes. 5604 if ( 'img' !== $tag_name && 'iframe' !== $tag_name ) { 5605 return $loading_attrs; 5606 } 5607 5608 // For any resources, width and height must be provided, to avoid layout shifts. 5609 if ( ! isset( $attr['width'], $attr['height'] ) ) { 5610 return $loading_attrs; 5611 } 5612 5613 if ( isset( $attr['loading'] ) ) { 5614 /* 5615 * While any `loading` value could be set in `$loading_attrs`, for 5616 * consistency we only do it for `loading="lazy"` since that is the 5617 * only possible value that WordPress core would apply on its own. 5618 */ 5619 if ( 'lazy' === $attr['loading'] ) { 5620 $loading_attrs['loading'] = 'lazy'; 5621 if ( isset( $attr['fetchpriority'] ) && 'high' === $attr['fetchpriority'] ) { 5622 _doing_it_wrong( 5623 __FUNCTION__, 5624 __( 'An image should not be lazy-loaded and marked as high priority at the same time.' ), 5625 '6.3.0' 5626 ); 5627 } 5628 } 5629 5630 return $postprocess( $loading_attrs, true ); 5631 } 5632 5633 // An image with `fetchpriority="high"` cannot be assigned `loading="lazy"` at the same time. 5634 if ( isset( $attr['fetchpriority'] ) && 'high' === $attr['fetchpriority'] ) { 5635 return $postprocess( $loading_attrs, true ); 5636 } 5637 5638 /* 5639 * Do not lazy-load images in the header block template part, as they are likely above the fold. 5640 * For classic themes, this is handled in the condition below using the 'get_header' action. 5641 */ 5504 5642 $header_area = WP_TEMPLATE_PART_AREA_HEADER; 5505 5643 if ( "template_part_{$header_area}" === $context ) { 5506 return false;5644 return $postprocess( $loading_attrs, true ); 5507 5645 } 5508 5646 5509 5647 // Special handling for programmatically created image tags. 5510 if ( ( 'the_post_thumbnail' === $context || 'wp_get_attachment_image' === $context )) {5648 if ( 'the_post_thumbnail' === $context || 'wp_get_attachment_image' === $context ) { 5511 5649 /* 5512 5650 * Skip programmatically created images within post content as they need to be handled together with the other … … 5516 5654 */ 5517 5655 if ( doing_filter( 'the_content' ) ) { 5518 return false;5656 return $postprocess( $loading_attrs, true ); 5519 5657 } 5520 5658 … … 5530 5668 && did_action( 'get_header' ) && ! did_action( 'get_footer' ) 5531 5669 ) { 5532 return false;5670 return $postprocess( $loading_attrs, true ); 5533 5671 } 5534 5672 } … … 5541 5679 // Only elements within the main query loop have special handling. 5542 5680 if ( is_admin() || ! in_the_loop() || ! is_main_query() ) { 5543 return 'lazy'; 5681 $loading_attrs['loading'] = 'lazy'; 5682 return $postprocess( $loading_attrs, false ); 5544 5683 } 5545 5684 … … 5547 5686 $content_media_count = wp_increase_content_media_count(); 5548 5687 5549 // If the count so far is below the threshold, return `false` so that the`loading` attribute is omitted.5688 // If the count so far is below the threshold, `loading` attribute is omitted. 5550 5689 if ( $content_media_count <= wp_omit_loading_attr_threshold() ) { 5551 return false; 5552 } 5553 5554 // For elements after the threshold, lazy-load them as usual. 5555 return 'lazy'; 5690 // The first largest image will still get `fetchpriority='high'`. 5691 return $postprocess( $loading_attrs, true ); 5692 } 5556 5693 } 5557 5694 5558 5695 // Lazy-load by default for any unknown context. 5559 return 'lazy'; 5696 $loading_attrs['loading'] = 'lazy'; 5697 return $postprocess( $loading_attrs, false ); 5560 5698 } 5561 5699 … … 5610 5748 return $content_media_count; 5611 5749 } 5750 5751 /** 5752 * Determines whether to add `fetchpriority='high'` to loading attributes. 5753 * 5754 * @since 6.3.0 5755 * @access private 5756 * 5757 * @param array $loading_attrs Array of the loading optimization attributes for the element. 5758 * @param string $tag_name The tag name. 5759 * @param array $attr Array of the attributes for the element. 5760 * @return array Updated loading optimization attributes for the element. 5761 */ 5762 function wp_maybe_add_fetchpriority_high_attr( $loading_attrs, $tag_name, $attr ) { 5763 // For now, adding `fetchpriority="high"` is only supported for images. 5764 if ( 'img' !== $tag_name ) { 5765 return $loading_attrs; 5766 } 5767 5768 if ( isset( $attr['fetchpriority'] ) ) { 5769 /* 5770 * While any `fetchpriority` value could be set in `$loading_attrs`, 5771 * for consistency we only do it for `fetchpriority="high"` since that 5772 * is the only possible value that WordPress core would apply on its 5773 * own. 5774 */ 5775 if ( 'high' === $attr['fetchpriority'] ) { 5776 $loading_attrs['fetchpriority'] = 'high'; 5777 wp_high_priority_element_flag( false ); 5778 } 5779 return $loading_attrs; 5780 } 5781 5782 // Lazy-loading and `fetchpriority="high"` are mutually exclusive. 5783 if ( isset( $loading_attrs['loading'] ) && 'lazy' === $loading_attrs['loading'] ) { 5784 return $loading_attrs; 5785 } 5786 5787 if ( ! wp_high_priority_element_flag() ) { 5788 return $loading_attrs; 5789 } 5790 5791 /** 5792 * Filters the minimum square-pixels threshold for an image to be eligible as the high-priority image. 5793 * 5794 * @since 6.3.0 5795 * 5796 * @param int $threshold Minimum square-pixels threshold. Default 50000. 5797 */ 5798 $wp_min_priority_img_pixels = apply_filters( 'wp_min_priority_img_pixels', 50000 ); 5799 if ( $wp_min_priority_img_pixels <= $attr['width'] * $attr['height'] ) { 5800 $loading_attrs['fetchpriority'] = 'high'; 5801 wp_high_priority_element_flag( false ); 5802 } 5803 return $loading_attrs; 5804 } 5805 5806 /** 5807 * Accesses a flag that indicates if an element is a possible candidate for `fetchpriority='high'`. 5808 * 5809 * @since 6.3.0 5810 * @access private 5811 * 5812 * @param bool $value Optional. Used to change the static variable. Default null. 5813 * @return bool Returns true if high-priority element was marked already, otherwise false. 5814 */ 5815 function wp_high_priority_element_flag( $value = null ) { 5816 static $high_priority_element = true; 5817 5818 if ( is_bool( $value ) ) { 5819 $high_priority_element = $value; 5820 } 5821 return $high_priority_element; 5822 } -
trunk/src/wp-includes/pluggable.php
r55990 r56037 2816 2816 'force_display' => false, 2817 2817 'loading' => null, 2818 'fetchpriority' => null, 2818 2819 'extra_attr' => '', 2819 2820 'decoding' => 'async', 2820 2821 ); 2821 2822 2822 if ( wp_lazy_loading_enabled( 'img', 'get_avatar' ) ) {2823 $defaults['loading'] = wp_get_loading_attr_default( 'get_avatar' );2824 }2825 2826 2823 if ( empty( $args ) ) { 2827 2824 $args = array(); … … 2840 2837 $args['width'] = $args['size']; 2841 2838 } 2839 2840 // Update args with loading optimized attributes. 2841 $loading_optimization_attr = wp_get_loading_optimization_attributes( 'img', $args, 'get_avatar' ); 2842 2843 $args = array_merge( $args, $loading_optimization_attr ); 2842 2844 2843 2845 if ( is_object( $id_or_email ) && isset( $id_or_email->comment_ID ) ) { … … 2893 2895 } 2894 2896 2895 // Add `loading` and `decoding` attributes.2897 // Add `loading`, `fetchpriority` and `decoding` attributes. 2896 2898 $extra_attr = $args['extra_attr']; 2897 2899 … … 2914 2916 2915 2917 $extra_attr .= "decoding='{$args['decoding']}'"; 2918 } 2919 2920 // Add support for `fetchpriority`. 2921 if ( in_array( $args['fetchpriority'], array( 'high', 'low', 'auto' ), true ) 2922 && ! preg_match( '/\bfetchpriority\s*=/', $extra_attr ) 2923 ) { 2924 if ( ! empty( $extra_attr ) ) { 2925 $extra_attr .= ' '; 2926 } 2927 2928 $extra_attr .= "fetchpriority='{$args['fetchpriority']}'"; 2916 2929 } 2917 2930 -
trunk/tests/phpunit/tests/media.php
r55956 r56037 77 77 78 78 /** 79 * Ensures that the static content media count and related filter are reset between tests.79 * Ensures that the static content media count, fetchpriority element flag and related filter are reset between tests. 80 80 */ 81 81 public function set_up() { … … 84 84 $this->reset_content_media_count(); 85 85 $this->reset_omit_loading_attr_filter(); 86 $this->reset_high_priority_element_flag(); 86 87 } 87 88 … … 2290 2291 public function test_wp_filter_content_tags_srcset_sizes_wrong() { 2291 2292 $img = get_image_tag( self::$large_id, '', '', '', 'medium' ); 2292 $img = wp_img_tag_add_loading_ attr( $img, 'test' );2293 $img = wp_img_tag_add_loading_optimization_attrs( $img, 'test' ); 2293 2294 $img = wp_img_tag_add_decoding_attr( $img, 'the_content' ); 2294 2295 … … 2305 2306 // Generate HTML and add a dummy srcset attribute. 2306 2307 $img = get_image_tag( self::$large_id, '', '', '', 'medium' ); 2307 $img = wp_img_tag_add_loading_ attr( $img, 'test' );2308 $img = wp_img_tag_add_loading_optimization_attrs( $img, 'test' ); 2308 2309 $img = wp_img_tag_add_decoding_attr( $img, 'the_content' ); 2309 2310 $img = preg_replace( '|<img ([^>]+) />|', '<img $1 ' . 'srcset="image2x.jpg 2x" />', $img ); … … 2450 2451 // Build HTML for the editor. 2451 2452 $img = get_image_tag( self::$large_id, '', '', '', 'medium' ); 2452 $img = wp_img_tag_add_loading_ attr( $img, 'test' );2453 $img = wp_img_tag_add_loading_optimization_attrs( $img, 'test' ); 2453 2454 $img_https = str_replace( 'http://', 'https://', $img ); 2454 2455 $img_relative = str_replace( 'http://', '//', $img ); … … 2991 2992 * @ticket 50367 2992 2993 * @ticket 50756 2994 * @ticket 58235 2993 2995 * @requires function imagejpeg 2994 2996 */ … … 3005 3007 $iframe_no_width_height = '<iframe src="https://www.example.com"></iframe>'; 3006 3008 3007 $lazy_img = wp_img_tag_add_loading_ attr( $img, 'test' );3008 $lazy_img_xhtml = wp_img_tag_add_loading_ attr( $img_xhtml, 'test' );3009 $lazy_img_html5 = wp_img_tag_add_loading_ attr( $img_html5, 'test' );3009 $lazy_img = wp_img_tag_add_loading_optimization_attrs( $img, 'test' ); 3010 $lazy_img_xhtml = wp_img_tag_add_loading_optimization_attrs( $img_xhtml, 'test' ); 3011 $lazy_img_html5 = wp_img_tag_add_loading_optimization_attrs( $img_html5, 'test' ); 3010 3012 $lazy_iframe = wp_iframe_tag_add_loading_attr( $iframe, 'test' ); 3011 3013 3012 3014 // The following should not be modified because there already is a 'loading' attribute. 3013 $img_eager = str_replace( ' />', ' loading="eager" />', $img );3015 $img_eager = str_replace( ' />', ' loading="eager" fetchpriority="high" />', $img ); 3014 3016 $iframe_eager = str_replace( '">', '" loading="eager">', $iframe ); 3015 3017 … … 3070 3072 * @ticket 44427 3071 3073 * @ticket 50756 3074 * @ticket 58235 3072 3075 */ 3073 3076 public function test_wp_filter_content_tags_loading_lazy_opted_in() { 3074 3077 $img = get_image_tag( self::$large_id, '', '', '', 'medium' ); 3075 $lazy_img = wp_img_tag_add_loading_ attr( $img, 'test' );3078 $lazy_img = wp_img_tag_add_loading_optimization_attrs( $img, 'test' ); 3076 3079 $lazy_img = wp_img_tag_add_decoding_attr( $lazy_img, 'the_content' ); 3077 3080 $iframe = '<iframe src="https://www.example.com" width="640" height="360"></iframe>'; … … 3128 3131 * @ticket 44427 3129 3132 * @ticket 50367 3133 * 3134 * @expectedDeprecated wp_img_tag_add_loading_attr 3135 * @expectedDeprecated wp_get_loading_attr_default 3130 3136 */ 3131 3137 public function test_wp_img_tag_add_loading_attr() { … … 3139 3145 * @ticket 44427 3140 3146 * @ticket 50367 3147 * 3148 * @expectedDeprecated wp_img_tag_add_loading_attr 3149 * @expectedDeprecated wp_get_loading_attr_default 3141 3150 */ 3142 3151 public function test_wp_img_tag_add_loading_attr_without_src() { … … 3150 3159 * @ticket 44427 3151 3160 * @ticket 50367 3161 * 3162 * @expectedDeprecated wp_img_tag_add_loading_attr 3163 * @expectedDeprecated wp_get_loading_attr_default 3152 3164 */ 3153 3165 public function test_wp_img_tag_add_loading_attr_with_single_quotes() { … … 3287 3299 // There should not be any loading attribute in this case. 3288 3300 $this->assertStringNotContainsString( ' loading=', $img ); 3301 } 3302 3303 /** 3304 * @ticket 58235 3305 * 3306 * @covers ::wp_get_attachment_image 3307 * @covers ::wp_get_loading_optimization_attributes 3308 */ 3309 public function test_wp_get_attachment_image_fetchpriority_not_present_by_default() { 3310 $img = wp_get_attachment_image( self::$large_id ); 3311 3312 $this->assertStringNotContainsString( ' fetchpriority="high"', $img ); 3313 } 3314 3315 /** 3316 * @ticket 58235 3317 * 3318 * @covers ::wp_get_attachment_image 3319 * @covers ::wp_get_loading_optimization_attributes 3320 */ 3321 public function test_wp_get_attachment_image_fetchpriority_high_when_not_lazy_loaded() { 3322 $img = wp_get_attachment_image( self::$large_id, 'large', false, array( 'loading' => false ) ); 3323 3324 $this->assertStringContainsString( ' fetchpriority="high"', $img ); 3325 } 3326 3327 /** 3328 * @ticket 58235 3329 * 3330 * @dataProvider data_provider_fetchpriority_values 3331 * 3332 * @covers ::wp_get_attachment_image 3333 * @covers ::wp_get_loading_optimization_attributes 3334 */ 3335 public function test_wp_get_attachment_image_fetchpriority_original_value_respected( $value ) { 3336 $img = wp_get_attachment_image( 3337 self::$large_id, 3338 'large', 3339 false, 3340 array( 3341 'loading' => false, 3342 'fetchpriority' => $value, 3343 ) 3344 ); 3345 3346 $this->assertStringContainsString( ' fetchpriority="' . $value . '"', $img ); 3347 } 3348 3349 /** 3350 * Data provider. 3351 * 3352 * @return array[] 3353 */ 3354 public function data_provider_fetchpriority_values() { 3355 return self::text_array_to_dataprovider( array( 'high', 'low', 'auto' ) ); 3356 } 3357 3358 /** 3359 * @ticket 58235 3360 * 3361 * @covers ::wp_get_attachment_image 3362 * @covers ::wp_get_loading_optimization_attributes 3363 */ 3364 public function test_wp_get_attachment_image_fetchpriority_stripped_when_false() { 3365 $img = wp_get_attachment_image( 3366 self::$large_id, 3367 'large', 3368 false, 3369 array( 3370 'loading' => false, 3371 'fetchpriority' => false, 3372 ) 3373 ); 3374 3375 $this->assertStringNotContainsString( ' fetchpriority=', $img ); 3376 } 3377 3378 /** 3379 * @ticket 58235 3380 * 3381 * @covers ::wp_get_attachment_image 3382 * @covers ::wp_get_loading_optimization_attributes 3383 */ 3384 public function test_wp_get_attachment_image_fetchpriority_high_prevents_lazy_loading() { 3385 $img = wp_get_attachment_image( self::$large_id, 'large', false, array( 'fetchpriority' => 'high' ) ); 3386 3387 $this->assertStringNotContainsString( ' loading="lazy"', $img ); 3289 3388 } 3290 3389 … … 3565 3664 * @covers ::wp_get_loading_attr_default 3566 3665 * 3666 * @expectedDeprecated wp_get_loading_attr_default 3667 * 3567 3668 * @dataProvider data_wp_get_loading_attr_default 3568 3669 * … … 3588 3689 $this->set_main_query( $query ); 3589 3690 3590 // For contexts other than for the main content, still return 'lazy' even in the loop 3591 // and in the main query, and do not increase the content media count. 3691 /* 3692 * For contexts other than for the main content, still return 'lazy' even in the loop 3693 * and in the main query, and do not increase the content media count. 3694 */ 3592 3695 $this->assertSame( 'lazy', wp_get_loading_attr_default( 'wp_get_attachment_image' ) ); 3593 3696 … … 3618 3721 /** 3619 3722 * @ticket 53675 3723 * @ticket 58235 3620 3724 */ 3621 3725 public function test_wp_omit_loading_attr_threshold_filter() { 3726 // Using a smaller image here. 3727 $attr = array( 3728 'width' => 100, 3729 'height' => 100, 3730 ); 3731 3622 3732 $query = $this->get_new_wp_query_for_published_post(); 3623 3733 $this->set_main_query( $query ); … … 3631 3741 // Due to the filter, now the first five elements should not be lazy-loaded, i.e. return `false`. 3632 3742 for ( $i = 0; $i < 5; $i++ ) { 3633 $this->assertFalse( wp_get_loading_attr_default( 'the_content' ) ); 3743 $this->assertEmpty( 3744 wp_get_loading_optimization_attributes( 'img', $attr, 'the_content' ), 3745 'Expected second image to not be lazy-loaded.' 3746 ); 3634 3747 } 3635 3748 3636 3749 // For following elements, lazy-load them again. 3637 $this->assertSame( 'lazy', wp_get_loading_attr_default( 'the_content' ) ); 3750 $this->assertSame( 3751 array( 'loading' => 'lazy' ), 3752 wp_get_loading_optimization_attributes( 'img', $attr, 'the_content' ) 3753 ); 3638 3754 } 3639 3755 } … … 3641 3757 /** 3642 3758 * @ticket 53675 3643 */ 3644 public function test_wp_filter_content_tags_with_wp_get_loading_attr_default() { 3759 * @ticket 58235 3760 * 3761 * @covers ::wp_filter_content_tags 3762 * @covers ::wp_img_tag_add_loading_optimization_attrs 3763 * @covers ::wp_get_loading_optimization_attributes 3764 */ 3765 public function test_wp_filter_content_tags_with_loading_optimization_attrs() { 3645 3766 $img1 = get_image_tag( self::$large_id, '', '', '', 'large' ); 3646 3767 $iframe1 = '<iframe src="https://www.example.com" width="640" height="360"></iframe>'; … … 3648 3769 $img3 = get_image_tag( self::$large_id, '', '', '', 'thumbnail' ); 3649 3770 $iframe2 = '<iframe src="https://wordpress.org" width="640" height="360"></iframe>'; 3650 $lazy_img2 = wp_img_tag_add_loading_attr( $img2, 'the_content' ); 3651 $lazy_img3 = wp_img_tag_add_loading_attr( $img3, 'the_content' ); 3771 $prio_img1 = str_replace( ' src=', ' fetchpriority="high" src=', $img1 ); 3772 $lazy_img2 = wp_img_tag_add_loading_optimization_attrs( $img2, 'the_content' ); 3773 $lazy_img3 = wp_img_tag_add_loading_optimization_attrs( $img3, 'the_content' ); 3652 3774 $lazy_iframe2 = wp_iframe_tag_add_loading_attr( $iframe2, 'the_content' ); 3653 3775 … … 3657 3779 // Following the threshold of 2, the first two content media elements should not be lazy-loaded. 3658 3780 $content_unfiltered = $img1 . $iframe1 . $img2 . $img3 . $iframe2; 3659 $content_expected = $ img1 . $iframe1 . $lazy_img2 . $lazy_img3 . $lazy_iframe2;3781 $content_expected = $prio_img1 . $iframe1 . $lazy_img2 . $lazy_img3 . $lazy_iframe2; 3660 3782 $content_expected = wp_img_tag_add_decoding_attr( $content_expected, 'the_content' ); 3661 3783 … … 3706 3828 * @dataProvider data_wp_get_loading_attr_default_before_and_no_loop 3707 3829 * 3830 * @expectedDeprecated wp_get_loading_attr_default 3831 * 3708 3832 * @param string $context Context for the element for which the `loading` attribute value is requested. 3709 3833 */ … … 3728 3852 * @dataProvider data_wp_get_loading_attr_default_before_and_no_loop 3729 3853 * 3854 * @expectedDeprecated wp_get_loading_attr_default 3855 * 3730 3856 * @param string $context Context for the element for which the `loading` attribute value is requested. 3731 3857 */ … … 3749 3875 * @dataProvider data_wp_get_loading_attr_default_before_and_no_loop 3750 3876 * 3877 * @expectedDeprecated wp_get_loading_attr_default 3878 * 3751 3879 * @param string $context Context for the element for which the `loading` attribute value is requested. 3752 3880 */ … … 3769 3897 * 3770 3898 * @dataProvider data_wp_get_loading_attr_default_before_and_no_loop 3899 * 3900 * @expectedDeprecated wp_get_loading_attr_default 3771 3901 * 3772 3902 * @param string $context Context for the element for which the `loading` attribute value is requested. … … 3795 3925 * @dataProvider data_wp_get_loading_attr_default_before_and_no_loop 3796 3926 * 3927 * @expectedDeprecated wp_get_loading_attr_default 3928 * 3797 3929 * @param string $context Context for the element for which the `loading` attribute value is requested. 3798 3930 */ … … 3829 3961 * @ticket 56930 3830 3962 * @ticket 58548 3963 * @ticket 58235 3831 3964 * 3832 3965 * @covers ::wp_filter_content_tags 3833 * @covers ::wp_get_loading_attr_default 3966 * @covers ::wp_img_tag_add_loading_optimization_attrs 3967 * @covers ::wp_get_loading_optimization_attributes 3834 3968 */ 3835 3969 public function test_wp_filter_content_tags_does_not_lazy_load_first_image_in_block_theme() { … … 3843 3977 $img1 = get_image_tag( self::$large_id, '', '', '', 'large' ); 3844 3978 $img2 = get_image_tag( self::$large_id, '', '', '', 'medium' ); 3845 $lazy_img2 = wp_img_tag_add_loading_attr( $img2, 'the_content' ); 3979 $prio_img1 = str_replace( ' src=', ' fetchpriority="high" src=', $img1 ); 3980 $lazy_img2 = wp_img_tag_add_loading_optimization_attrs( $img2, 'the_content' ); 3846 3981 3847 3982 // Only the second image should be lazy-loaded. 3848 3983 $post_content = $img1 . $img2; 3849 $expected_content = wpautop( $ img1 . $lazy_img2 );3984 $expected_content = wpautop( $prio_img1 . $lazy_img2 ); 3850 3985 3851 3986 // Update the post to test with so that it has the above post content. … … 3874 4009 * @ticket 56930 3875 4010 * @ticket 58548 4011 * @ticket 58235 3876 4012 * 3877 4013 * @covers ::wp_filter_content_tags 3878 * @covers ::wp_get_loading_attr_default 4014 * @covers ::wp_img_tag_add_loading_optimization_attrs 4015 * @covers ::wp_get_loading_optimization_attributes 3879 4016 */ 3880 4017 public function test_wp_filter_content_tags_does_not_lazy_load_first_featured_image_in_block_theme() { … … 3894 4031 3895 4032 $content_img = get_image_tag( self::$large_id, '', '', '', 'large' ); 3896 $lazy_content_img = wp_img_tag_add_loading_ attr( $content_img, 'the_content' );4033 $lazy_content_img = wp_img_tag_add_loading_optimization_attrs( $content_img, 'the_content' ); 3897 4034 3898 4035 // The featured image should not be lazy-loaded as it is the first image. 3899 4036 $featured_image_id = self::$large_id; 3900 4037 update_post_meta( self::$post_ids['publish'], '_thumbnail_id', $featured_image_id ); 3901 $expected_featured_image = '<figure class="wp-block-post-featured-image">' . get_the_post_thumbnail( self::$post_ids['publish'], 'post-thumbnail', array( 'loading' => false ) ) . '</figure>'; 4038 $expected_featured_image = '<figure class="wp-block-post-featured-image">' . get_the_post_thumbnail( 4039 self::$post_ids['publish'], 4040 'post-thumbnail', 4041 array( 4042 'loading' => false, 4043 'fetchpriority' => 'high', 4044 ) 4045 ) . '</figure>'; 4046 4047 // Reset high priority flag as the forced `fetchpriority="high"` above already modified it. 4048 $this->reset_high_priority_element_flag(); 3902 4049 3903 4050 // The post content image should be lazy-loaded since the featured image appears above. … … 3913 4060 ) 3914 4061 ); 3915 3916 4062 $wp_query = new WP_Query( array( 'p' => self::$post_ids['publish'] ) ); 3917 4063 $wp_the_query = $wp_query; … … 3929 4075 * 3930 4076 * @ticket 56930 4077 * @ticket 58235 3931 4078 * 3932 4079 * @covers ::wp_filter_content_tags 3933 * @covers ::wp_get_loading_attr_default 4080 * @covers ::wp_img_tag_add_loading_optimization_attrs 4081 * @covers ::wp_get_loading_optimization_attributes 3934 4082 */ 3935 4083 public function test_wp_filter_content_tags_does_not_lazy_load_images_in_header() { … … 3942 4090 // Use a single image for each header and footer template parts. 3943 4091 $header_img = get_image_tag( self::$large_id, '', '', '', 'large' ); 4092 // Since header_img is qualified candidate for LCP, fetchpriority high is applied to it. 4093 $header_img = str_replace( '<img', '<img fetchpriority="high"', $header_img ); 4094 3944 4095 $footer_img = get_image_tag( self::$large_id, '', '', '', 'medium' ); 3945 4096 … … 3970 4121 // Header image should not be lazy-loaded, footer image should be lazy-loaded. 3971 4122 $expected_template_content = '<header class="wp-block-template-part">' . $header_img . '</header>'; 3972 $expected_template_content .= '<footer class="wp-block-template-part">' . wp_img_tag_add_loading_ attr( $footer_img, 'force-lazy' ) . '</footer>';4123 $expected_template_content .= '<footer class="wp-block-template-part">' . wp_img_tag_add_loading_optimization_attrs( $footer_img, 'force-lazy' ) . '</footer>'; 3973 4124 3974 4125 $html = get_the_block_template_html(); … … 3978 4129 /** 3979 4130 * @ticket 58089 4131 * @ticket 58235 3980 4132 * 3981 4133 * @covers ::wp_filter_content_tags 3982 * @covers ::wp_get_loading_ attr_default4134 * @covers ::wp_get_loading_optimization_attributes 3983 4135 */ 3984 4136 public function test_wp_filter_content_tags_does_not_lazy_load_special_images_within_the_content() { … … 3986 4138 3987 4139 // Force no lazy-loading on the image tag expected in the content. 3988 $expected_content = wpautop( wp_get_attachment_image( self::$large_id, 'large', false, array( 'loading' => false ) ) ); 4140 $expected_content = wpautop( 4141 wp_get_attachment_image( 4142 self::$large_id, 4143 'large', 4144 false, 4145 array( 4146 'loading' => false, 4147 'fetchpriority' => 'high', 4148 ) 4149 ) 4150 ); 4151 4152 // Reset high priority flag as the forced `fetchpriority="high"` above already modified it. 4153 $this->reset_high_priority_element_flag(); 3989 4154 3990 4155 // Overwrite post content with an image. … … 4024 4189 * @covers ::wp_get_loading_attr_default 4025 4190 * 4191 * @expectedDeprecated wp_get_loading_attr_default 4192 * 4026 4193 * @dataProvider data_special_contexts_for_the_content 4027 4194 * … … 4038 4205 * 4039 4206 * @covers ::wp_get_loading_attr_default 4207 * 4208 * @expectedDeprecated wp_get_loading_attr_default 4040 4209 * 4041 4210 * @dataProvider data_special_contexts_for_the_content … … 4068 4237 'wp_get_attachment_image' => array( 'context' => 'wp_get_attachment_image' ), 4069 4238 ); 4239 } 4240 4241 /** 4242 * Tests that wp_get_loading_attr_default() returns the expected loading attribute value. 4243 * 4244 * @ticket 53675 4245 * @ticket 56930 4246 * @ticket 58235 4247 * 4248 * @covers ::wp_get_loading_optimization_attributes 4249 * 4250 * @dataProvider data_wp_get_loading_attr_default 4251 * 4252 * @param string $context 4253 */ 4254 public function test_wp_get_loading_optimization_attributes( $context ) { 4255 $attr = $this->get_width_height_for_high_priority(); 4256 4257 // Return 'lazy' by default. 4258 $this->assertSame( 4259 array( 'loading' => 'lazy' ), 4260 wp_get_loading_optimization_attributes( 'img', $attr, 'test' ) 4261 ); 4262 $this->assertSame( 4263 array( 'loading' => 'lazy' ), 4264 wp_get_loading_optimization_attributes( 'img', $attr, 'wp_get_attachment_image' ) 4265 ); 4266 4267 // Return 'lazy' if not in the loop or the main query. 4268 $this->assertSame( 4269 array( 'loading' => 'lazy' ), 4270 wp_get_loading_optimization_attributes( 'img', $attr, $context ) 4271 ); 4272 4273 $query = $this->get_new_wp_query_for_published_post(); 4274 4275 while ( have_posts() ) { 4276 the_post(); 4277 4278 // Return 'lazy' if in the loop but not in the main query. 4279 $this->assertSame( 4280 array( 'loading' => 'lazy' ), 4281 wp_get_loading_optimization_attributes( 'img', $attr, $context ) 4282 ); 4283 4284 // Set as main query. 4285 $this->set_main_query( $query ); 4286 4287 /* 4288 * For contexts other than for the main content, still return 'lazy' even in the loop 4289 * and in the main query, and do not increase the content media count. 4290 */ 4291 $this->assertSame( 4292 array( 'loading' => 'lazy' ), 4293 wp_get_loading_optimization_attributes( 'img', $attr, 'wp_get_attachment_image' ) 4294 ); 4295 4296 // First three element are not lazy loaded. However, first image is loaded with fetchpriority high. 4297 $this->assertSame( 4298 array( 'fetchpriority' => 'high' ), 4299 wp_get_loading_optimization_attributes( 'img', $attr, $context ), 4300 "Expected first image to not be lazy-loaded. First large image get's high fetchpriority." 4301 ); 4302 $this->assertEmpty( 4303 wp_get_loading_optimization_attributes( 'img', $attr, $context ), 4304 'Expected second image to not be lazy-loaded.' 4305 ); 4306 $this->assertEmpty( 4307 wp_get_loading_optimization_attributes( 'img', $attr, $context ), 4308 'Expected third image to not be lazy-loaded.' 4309 ); 4310 4311 // Return 'lazy' if in the loop and in the main query for any subsequent elements. 4312 $this->assertSame( 4313 array( 'loading' => 'lazy' ), 4314 wp_get_loading_optimization_attributes( 'img', $attr, $context ) 4315 ); 4316 4317 // Yes, for all subsequent elements. 4318 $this->assertSame( 4319 array( 'loading' => 'lazy' ), 4320 wp_get_loading_optimization_attributes( 'img', $attr, $context ) 4321 ); 4322 } 4323 } 4324 4325 /** 4326 * Tests that wp_get_loading_optimization_attributes() returns the expected loading attribute value before loop but after get_header if not main query. 4327 * 4328 * @ticket 58211 4329 * @ticket 58235 4330 * 4331 * @covers ::wp_get_loading_optimization_attributes 4332 * 4333 * @dataProvider data_wp_get_loading_attr_default_before_and_no_loop 4334 * 4335 * @param string $context Context for the element for which the `loading` attribute value is requested. 4336 */ 4337 public function test_wp_get_loading_optimization_attributes_before_loop_if_not_main_query( $context ) { 4338 global $wp_query; 4339 4340 $wp_query = $this->get_new_wp_query_for_published_post(); 4341 4342 do_action( 'get_header' ); 4343 4344 $attr = $this->get_width_height_for_high_priority(); 4345 4346 // Lazy if not main query. 4347 $this->assertSame( 4348 array( 'loading' => 'lazy' ), 4349 wp_get_loading_optimization_attributes( 'img', $attr, $context ) 4350 ); 4351 } 4352 4353 /** 4354 * Tests that wp_get_loading_optimization_attributes() returns the expected loading attribute value before loop but after get_header in main query but header was not called. 4355 * 4356 * @ticket 58211 4357 * @ticket 58235 4358 * 4359 * @covers ::wp_get_loading_optimization_attributes 4360 * 4361 * @dataProvider data_wp_get_loading_attr_default_before_and_no_loop 4362 * 4363 * @param string $context Context for the element for which the `loading` attribute value is requested. 4364 */ 4365 public function test_wp_get_loading_optimization_attributes_before_loop_in_main_query_but_header_not_called( $context ) { 4366 global $wp_query; 4367 4368 $wp_query = $this->get_new_wp_query_for_published_post(); 4369 $this->set_main_query( $wp_query ); 4370 4371 $attr = $this->get_width_height_for_high_priority(); 4372 4373 // Lazy if header not called. 4374 $this->assertSame( 4375 array( 'loading' => 'lazy' ), 4376 wp_get_loading_optimization_attributes( 'img', $attr, $context ) 4377 ); 4378 } 4379 4380 /** 4381 * Tests that wp_get_loading_optimization_attributes() returns the expected loading attribute value before loop but after get_header for main query. 4382 * 4383 * @ticket 58211 4384 * @ticket 58235 4385 * 4386 * @covers ::wp_get_loading_optimization_attributes 4387 * 4388 * @dataProvider data_wp_get_loading_attr_default_before_and_no_loop 4389 * 4390 * @param string $context Context for the element for which the `loading` attribute value is requested. 4391 */ 4392 public function test_wp_get_loading_optimization_attributes_before_loop_if_main_query( $context ) { 4393 global $wp_query; 4394 4395 $wp_query = $this->get_new_wp_query_for_published_post(); 4396 $this->set_main_query( $wp_query ); 4397 do_action( 'get_header' ); 4398 4399 $attr = $this->get_width_height_for_high_priority(); 4400 4401 // First image is loaded with high fetchpriority. 4402 $this->assertSame( 4403 array( 'fetchpriority' => 'high' ), 4404 wp_get_loading_optimization_attributes( 'img', $attr, $context ), 4405 'Expected first image to not be lazy-loaded. First large image is loaded with high fetchpriority.' 4406 ); 4407 } 4408 4409 /** 4410 * Tests that wp_get_loading_optimization_attributes() returns the expected loading attribute value after get_header and after loop. 4411 * 4412 * @ticket 58211 4413 * @ticket 58235 4414 * 4415 * @covers ::wp_get_loading_optimization_attributes 4416 * 4417 * @dataProvider data_wp_get_loading_attr_default_before_and_no_loop 4418 * 4419 * @param string $context Context for the element for which the `loading` attribute value is requested. 4420 */ 4421 public function test_wp_get_loading_optimization_attributes_after_loop( $context ) { 4422 global $wp_query; 4423 4424 $wp_query = $this->get_new_wp_query_for_published_post(); 4425 $this->set_main_query( $wp_query ); 4426 4427 do_action( 'get_header' ); 4428 4429 while ( have_posts() ) { 4430 the_post(); 4431 } 4432 4433 $attr = $this->get_width_height_for_high_priority(); 4434 $this->assertSame( 4435 array( 'loading' => 'lazy' ), 4436 wp_get_loading_optimization_attributes( 'img', $attr, $context ) 4437 ); 4438 } 4439 4440 /** 4441 * Tests that wp_get_loading_optimization_attributes() returns the expected loading attribute if no loop. 4442 * 4443 * @ticket 58211 4444 * @ticket 58235 4445 * 4446 * @covers ::wp_get_loading_optimization_attributes 4447 * 4448 * @dataProvider data_wp_get_loading_attr_default_before_and_no_loop 4449 * 4450 * @param string $context Context for the element for which the `loading` attribute value is requested. 4451 */ 4452 public function test_wp_get_loading_optimization_attributes_no_loop( $context ) { 4453 global $wp_query; 4454 4455 $wp_query = $this->get_new_wp_query_for_published_post(); 4456 $this->set_main_query( $wp_query ); 4457 4458 // Ensure header and footer is called. 4459 do_action( 'get_header' ); 4460 do_action( 'get_footer' ); 4461 4462 $attr = $this->get_width_height_for_high_priority(); 4463 4464 // Load lazy if the there is no loop and footer was called. 4465 $this->assertSame( 4466 array( 'loading' => 'lazy' ), 4467 wp_get_loading_optimization_attributes( 'img', $attr, $context ) 4468 ); 4469 } 4470 4471 /** 4472 * Tests that wp_get_loading_optimization_attributes() returns 'lazy' for special contexts when they're used outside of 'the_content' filter. 4473 * 4474 * @ticket 58089 4475 * @ticket 58235 4476 * 4477 * @covers ::wp_get_loading_optimization_attributes 4478 * 4479 * @dataProvider data_special_contexts_for_the_content 4480 * 4481 * @param string $context Context for the element for which the `loading` attribute value is requested. 4482 */ 4483 public function test_wp_get_loading_optimization_attributes_should_return_lazy_for_special_contexts_outside_of_the_content( $context ) { 4484 $attr = $this->get_width_height_for_high_priority(); 4485 $this->assertSame( 4486 array( 'loading' => 'lazy' ), 4487 wp_get_loading_optimization_attributes( 'img', $attr, $context ) 4488 ); 4489 } 4490 4491 /** 4492 * Tests that wp_get_loading_optimization_attributes() returns false for special contexts when they're used within 'the_content' filter. 4493 * 4494 * @ticket 58089 4495 * @ticket 58235 4496 * 4497 * @covers ::wp_get_loading_optimization_attributes 4498 * 4499 * @dataProvider data_special_contexts_for_the_content 4500 * 4501 * @param string $context Context for the element for which the `loading` attribute value is requested. 4502 */ 4503 public function test_wp_get_loading_optimization_attributes_should_return_false_for_special_contexts_within_the_content( $context ) { 4504 remove_all_filters( 'the_content' ); 4505 4506 $result = null; 4507 add_filter( 4508 'the_content', 4509 function( $content ) use ( &$result, $context ) { 4510 $attr = $this->get_width_height_for_high_priority(); 4511 $result = wp_get_loading_optimization_attributes( 'img', $attr, $context ); 4512 return $content; 4513 } 4514 ); 4515 apply_filters( 'the_content', '' ); 4516 4517 $this->assertSame( 4518 array( 'fetchpriority' => 'high' ), 4519 $result, 4520 'First large image is loaded with high fetchpriority.' 4521 ); 4522 } 4523 4524 /** 4525 * @ticket 44427 4526 * @ticket 50367 4527 * @ticket 58235 4528 */ 4529 public function test_wp_img_tag_add_loading_optimization_attrs() { 4530 $img = '<img src="example.png" alt=" width="300" height="225" />'; 4531 $img = wp_img_tag_add_loading_optimization_attrs( $img, 'test' ); 4532 4533 $this->assertStringContainsString( ' loading="lazy"', $img ); 4534 } 4535 4536 /** 4537 * @ticket 44427 4538 * @ticket 50367 4539 * @ticket 58235 4540 */ 4541 public function test_wp_img_tag_add_loading_optimization_attrs_without_src() { 4542 $img = '<img alt="" width="300" height="225" />'; 4543 $img = wp_img_tag_add_loading_optimization_attrs( $img, 'test' ); 4544 4545 $this->assertStringNotContainsString( ' loading=', $img ); 4070 4546 } 4071 4547 … … 4121 4597 * 4122 4598 * @ticket 56588 4599 * @ticket 58235 4123 4600 * 4124 4601 * @covers ::wp_trim_excerpt … … 4132 4609 */ 4133 4610 $this->force_omit_loading_attr_threshold( 2 ); 4611 4134 4612 $post_content = '<img src="example.jpg" width="800" height="600">'; 4135 4613 $post_content .= '<p>Some text.</p>'; … … 4145 4623 update_post_meta( $post_id, '_thumbnail_id', $featured_image_id ); 4146 4624 4147 $expected_image_tag = get_the_post_thumbnail( $post_id, 'post-thumbnail', array( 'loading' => false ) ); 4625 $expected_image_tag = get_the_post_thumbnail( 4626 $post_id, 4627 'post-thumbnail', 4628 array( 4629 'loading' => false, 4630 'fetchpriority' => 'high', 4631 ) 4632 ); 4633 4634 // Reset high priority flag as the forced `fetchpriority="high"` above already modified it. 4635 $this->reset_high_priority_element_flag(); 4148 4636 4149 4637 $wp_query = new WP_Query( array( 'post__in' => array( $post_id ) ) ); … … 4179 4667 // Clean up the above filter. 4180 4668 remove_filter( 'wp_omit_loading_attr_threshold', '__return_null', 100 ); 4669 } 4670 4671 private function reset_high_priority_element_flag() { 4672 wp_high_priority_element_flag( true ); 4181 4673 } 4182 4674 … … 4277 4769 * @ticket 58212 4278 4770 * 4279 * @covers ::wp_get_attachment_image ()4771 * @covers ::wp_get_attachment_image 4280 4772 */ 4281 4773 public function test_wp_get_attachment_image_context_filter_default() { … … 4292 4784 * @ticket 58212 4293 4785 * 4294 * @covers ::wp_get_attachment_image ()4786 * @covers ::wp_get_attachment_image 4295 4787 */ 4296 4788 public function test_wp_get_attachment_image_context_filter_value_is_passed_correctly() { … … 4308 4800 wp_get_attachment_image( self::$large_id ); 4309 4801 $this->assertSame( 'my_custom_context', $last_context ); 4802 } 4803 4804 /** 4805 * Tests tag restriction for `wp_get_loading_optimization_attributes()`. 4806 * 4807 * @ticket 58235 4808 * 4809 * @covers ::wp_get_loading_optimization_attributes 4810 * 4811 * @dataProvider data_wp_get_loading_optimization_attributes_min_required_attrs 4812 * 4813 * @param string $tag_name The tag name. 4814 * @param string $attr Element attributes. 4815 * @param array $expected Expected return value. 4816 * @param string $message Message to display if the test fails. 4817 */ 4818 public function test_wp_get_loading_optimization_attributes_min_required_attrs( $tag_name, $attr, $expected, $message ) { 4819 $context = 'the_post_thumbnail'; 4820 $this->assertSame( wp_get_loading_optimization_attributes( $tag_name, $attr, $context ), $expected, $message ); 4821 } 4822 4823 /** 4824 * Data provider. 4825 * 4826 * @return array[] 4827 */ 4828 public function data_wp_get_loading_optimization_attributes_min_required_attrs() { 4829 return array( 4830 'img_with_min_attrs' => array( 4831 'img', 4832 array( 4833 'width' => 100, 4834 'height' => 100, 4835 ), 4836 array( 'loading' => 'lazy' ), 4837 'Expected default `loading="lazy"`.', 4838 ), 4839 'img_without_height' => array( 4840 'img', 4841 array( 'width' => 100 ), 4842 array(), 4843 'Expected blank array as height is required.', 4844 ), 4845 'img_without_width' => array( 4846 'img', 4847 array( 'height' => 100 ), 4848 array(), 4849 'Expected blank array as width is required.', 4850 ), 4851 ); 4852 } 4853 4854 /** 4855 * Tests tag restriction for `wp_get_loading_optimization_attributes()`. 4856 * 4857 * @ticket 58235 4858 * 4859 * @covers ::wp_get_loading_optimization_attributes 4860 * 4861 * @dataProvider data_wp_get_loading_optimization_attributes_check_allowed_tags 4862 * 4863 * @param string $tag_name The tag name. 4864 * @param array $expected Expected return value. 4865 * @param string $message Message to display if the test fails. 4866 */ 4867 public function test_wp_get_loading_optimization_attributes_check_allowed_tags( $tag_name, $expected, $message ) { 4868 $attr = $this->get_width_height_for_high_priority(); 4869 $context = 'the_post_thumbnail'; 4870 $this->assertSame( wp_get_loading_optimization_attributes( $tag_name, $attr, $context ), $expected, $message ); 4871 } 4872 4873 /** 4874 * Data provider. 4875 * 4876 * @return array[] 4877 */ 4878 public function data_wp_get_loading_optimization_attributes_check_allowed_tags() { 4879 return array( 4880 'img' => array( 4881 'img', 4882 array( 'loading' => 'lazy' ), 4883 'Expected `loading="lazy"` for the img.', 4884 ), 4885 'iframe' => array( 4886 'iframe', 4887 array( 4888 'loading' => 'lazy', 4889 ), 4890 'Expected `loading="lazy"` for the iframe.', 4891 ), 4892 'video' => 4893 array( 4894 'video', 4895 array(), 4896 'Function should return empty array as video tag is not supported.', 4897 ), 4898 ); 4899 } 4900 4901 /** 4902 * @ticket 58235 4903 * 4904 * @covers ::wp_get_loading_optimization_attributes 4905 */ 4906 public function test_wp_get_loading_optimization_attributes_skip_for_block_template() { 4907 $attr = $this->get_width_height_for_high_priority(); 4908 4909 // Skip logic if context is `template`. 4910 $this->assertSame( 4911 array(), 4912 wp_get_loading_optimization_attributes( 'img', $attr, 'template' ), 4913 'Skip logic and return blank array for block template.' 4914 ); 4915 } 4916 4917 /** 4918 * @ticket 58235 4919 * 4920 * @covers ::wp_get_loading_optimization_attributes 4921 */ 4922 public function test_wp_get_loading_optimization_attributes_header_block_template() { 4923 $attr = $this->get_width_height_for_high_priority(); 4924 4925 // Skip logic if context is `template`. 4926 $this->assertSame( 4927 array( 'fetchpriority' => 'high' ), 4928 wp_get_loading_optimization_attributes( 'img', $attr, 'template_part_' . WP_TEMPLATE_PART_AREA_HEADER ), 4929 'Images in the header block template part should not be lazy-loaded and first large image is set high fetchpriority.' 4930 ); 4931 } 4932 4933 /** 4934 * @ticket 58235 4935 * 4936 * @covers ::wp_get_loading_optimization_attributes 4937 * @expectedIncorrectUsage wp_get_loading_optimization_attributes 4938 */ 4939 public function test_wp_get_loading_optimization_attributes_incorrect_loading_attrs() { 4940 $attr = $this->get_width_height_for_high_priority(); 4941 $attr['loading'] = 'lazy'; 4942 $attr['fetchpriority'] = 'high'; 4943 4944 $this->assertSame( 4945 array( 4946 'loading' => 'lazy', 4947 'fetchpriority' => 'high', 4948 ), 4949 wp_get_loading_optimization_attributes( 'img', $attr, 'test' ), 4950 'This should return both lazy-loading and high fetchpriority, but with doing_it_wrong message.' 4951 ); 4952 } 4953 4954 /** 4955 * @ticket 58235 4956 * 4957 * @covers ::wp_get_loading_optimization_attributes 4958 */ 4959 public function test_wp_get_loading_optimization_attributes_if_loading_attr_present() { 4960 $attr = $this->get_width_height_for_high_priority(); 4961 $attr['loading'] = 'eager'; 4962 4963 // Check fetchpriority high logic if loading attribute is present. 4964 $this->assertSame( 4965 array( 4966 'fetchpriority' => 'high', 4967 ), 4968 wp_get_loading_optimization_attributes( 'img', $attr, 'test' ), 4969 'fetchpriority should be set to high.' 4970 ); 4971 } 4972 4973 /** 4974 * @ticket 58235 4975 * 4976 * @covers ::wp_get_loading_optimization_attributes 4977 */ 4978 public function test_wp_get_loading_optimization_attributes_low_res_image() { 4979 $attr = array( 4980 'width' => 100, 4981 'height' => 100, 4982 'loading' => 'eager', 4983 ); 4984 4985 // fetchpriority not set as image is of lower resolution. 4986 $this->assertSame( 4987 array(), 4988 wp_get_loading_optimization_attributes( 'img', $attr, 'test' ), 4989 'loading optimization attr array should be empty.' 4990 ); 4991 } 4992 4993 /** 4994 * @ticket 58235 4995 * 4996 * @covers ::wp_maybe_add_fetchpriority_high_attr 4997 * 4998 * @dataProvider data_wp_maybe_add_fetchpriority_high_attr 4999 */ 5000 public function test_wp_maybe_add_fetchpriority_high_attr( $loading_attrs, $tag_name, $attr, $expected_fetchpriority ) { 5001 $loading_attrs = wp_maybe_add_fetchpriority_high_attr( $loading_attrs, $tag_name, $attr ); 5002 5003 if ( $expected_fetchpriority ) { 5004 $this->assertArrayHasKey( 'fetchpriority', $loading_attrs, 'fetchpriority attribute should be present' ); 5005 $this->assertSame( $expected_fetchpriority, $loading_attrs['fetchpriority'], 'fetchpriority attribute has incorrect value' ); 5006 } else { 5007 $this->assertArrayNotHasKey( 'fetchpriority', $loading_attrs, 'fetchpriority attribute should not be present' ); 5008 } 5009 } 5010 5011 /** 5012 * Data provider. 5013 * 5014 * @return array[] 5015 */ 5016 public function data_wp_maybe_add_fetchpriority_high_attr() { 5017 return array( 5018 'small image' => array( 5019 array(), 5020 'img', 5021 $this->get_insufficient_width_height_for_high_priority(), 5022 false, 5023 ), 5024 'large image' => array( 5025 array(), 5026 'img', 5027 $this->get_width_height_for_high_priority(), 5028 'high', 5029 ), 5030 'image with loading=lazy' => array( 5031 array( 'loading' => 'lazy' ), 5032 'img', 5033 $this->get_width_height_for_high_priority(), 5034 false, 5035 ), 5036 'image with loading=eager' => array( 5037 array( 'loading' => 'eager' ), 5038 'img', 5039 $this->get_width_height_for_high_priority(), 5040 'high', 5041 ), 5042 'image with fetchpriority=high' => array( 5043 array(), 5044 'img', 5045 array_merge( 5046 $this->get_insufficient_width_height_for_high_priority(), 5047 array( 'fetchpriority' => 'high' ) 5048 ), 5049 'high', 5050 ), 5051 'image with fetchpriority=low' => array( 5052 array(), 5053 'img', 5054 array_merge( 5055 $this->get_insufficient_width_height_for_high_priority(), 5056 array( 'fetchpriority' => 'low' ) 5057 ), 5058 false, 5059 ), 5060 'non-image element' => array( 5061 array(), 5062 'video', 5063 $this->get_width_height_for_high_priority(), 5064 false, 5065 ), 5066 ); 5067 } 5068 5069 /** 5070 * @ticket 58235 5071 * 5072 * @covers ::wp_maybe_add_fetchpriority_high_attr 5073 */ 5074 public function test_wp_maybe_add_fetchpriority_high_attr_min_priority_filter() { 5075 $attr = array( 5076 'width' => 50, 5077 'height' => 50, 5078 ); 5079 5080 add_filter( 5081 'wp_min_priority_img_pixels', 5082 static function( $res ) { 5083 return 2500; // 50*50=2500 5084 } 5085 ); 5086 5087 // fetchpriority set to high as resolution is equal to (or greater than) 2500. 5088 $this->assertSame( 5089 array( 5090 'fetchpriority' => 'high', 5091 ), 5092 wp_maybe_add_fetchpriority_high_attr( array(), 'img', $attr ) 5093 ); 4310 5094 } 4311 5095 … … 4408 5192 $wp_the_query = $query; 4409 5193 } 5194 5195 /** 5196 * Returns an array with dimension attribute values eligible for a high priority image. 5197 * 5198 * @return array Associative array with 'width' and 'height' keys. 5199 */ 5200 private function get_width_height_for_high_priority() { 5201 /* 5202 * The product of width * height must be >50000 to qualify for high priority image. 5203 * 300 * 200 = 60000 5204 */ 5205 return array( 5206 'width' => 300, 5207 'height' => 200, 5208 ); 5209 } 5210 5211 /** 5212 * Returns an array with dimension attribute values ineligible for a high priority image. 5213 * 5214 * @return array Associative array with 'width' and 'height' keys. 5215 */ 5216 private function get_insufficient_width_height_for_high_priority() { 5217 /* 5218 * The product of width * height must be >50000 to qualify for high priority image. 5219 * 200 * 100 = 20000 5220 */ 5221 return array( 5222 'width' => 200, 5223 'height' => 100, 5224 ); 5225 } 4410 5226 } 4411 5227
Note: See TracChangeset
for help on using the changeset viewer.