Repository navigation
Script Loader: Drop obsolete pr attribute and build resource hint and preload tags with the HTML API #15331
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: trunk
Are you sure you want to change the base?
Script Loader: Drop obsolete pr attribute and build resource hint and preload tags with the HTML API #15331
Changes from all commits
e7764ce
c413f61
dc433d7
db9db3f
79b7c15
33ea505
2addb9a
4d1a8dd
016be5f
2743a24
6111cec
0ef0d79
dde14f8
8c189b8
3ece593
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -3945,6 +3945,29 @@ function wp_resource_hints() { | |
| 'prerender' => array(), | ||
| ); | ||
|
|
||
| /* | ||
| * Attributes allowed on a resource hint. Any attribute not listed as a key is | ||
| * dropped. A value of `true` means the attribute may also be printed as a | ||
| * boolean (valueless) attribute, when it is supplied as `true` or as a list | ||
| * item. Attributes with a value of `false` are printed only with a value. | ||
| * | ||
| * Other attributes of the link element are omitted because the HTML spec only | ||
| * allows them with other link types: blocking, color, disabled, imagesizes, | ||
| * imagesrcset, integrity, and sizes. | ||
| */ | ||
| $allowed_attributes = array( | ||
| 'as' => false, | ||
|
sirreal marked this conversation as resolved.
Resolved
|
||
| 'crossorigin' => true, | ||
| 'fetchpriority' => false, | ||
| 'href' => false, | ||
| 'hreflang' => false, | ||
| 'media' => false, | ||
| 'referrerpolicy' => false, | ||
| 'rel' => false, | ||
| 'title' => false, | ||
| 'type' => false, | ||
| ); | ||
|
|
||
| foreach ( $hints as $relation_type => $urls ) { | ||
| $unique_urls = array(); | ||
|
|
||
|
|
@@ -3954,19 +3977,32 @@ function wp_resource_hints() { | |
| * @since 4.6.0 | ||
| * @since 4.7.0 The `$urls` parameter accepts arrays of specific HTML attributes | ||
| * as its child elements. | ||
| * @since 7.3.0 The obsolete `pr` attribute is no longer printed. The `crossorigin` | ||
|
sirreal marked this conversation as resolved.
Resolved
|
||
| * attribute may be `true` to print it without a value. List items | ||
| * other than `crossorigin` are no longer printed. Added the | ||
| * `fetchpriority`, `hreflang`, `media`, `referrerpolicy`, and `title` | ||
| * attributes. | ||
| * | ||
| * @param array $urls { | ||
| * Array of resources and their attributes, or URLs to print for resource hints. | ||
| * | ||
| * @type array|string ...$0 { | ||
| * Array of resource attributes, or a URL string. | ||
| * Array of resource attributes, or a URL string. A valueless attribute | ||
| * may also be supplied as a list item, as in `array( 'crossorigin' )`. | ||
| * | ||
| * @type string $href URL to include in resource hints. Required. | ||
| * @type string $as How the browser should treat the resource | ||
| * (`script`, `style`, `image`, `document`, etc). | ||
| * @type string $crossorigin Indicates the CORS policy of the specified resource. | ||
| * @type float $pr Expected probability that the resource hint will be used. | ||
| * @type string $type Type of the resource (`text/html`, `text/css`, etc). | ||
| * @type string $href URL to include in resource hints. Required. | ||
| * @type string $as How the browser should treat the resource | ||
| * (`script`, `style`, `image`, `document`, etc). | ||
| * @type string|bool $crossorigin Indicates the CORS policy of the specified resource. | ||
| * When `true`, it is printed without a value, which | ||
| * is equivalent to `anonymous`. | ||
| * @type string $fetchpriority Priority of the fetch relative to other resources | ||
| * (`high`, `low`, or `auto`). | ||
| * @type string $hreflang Language of the resource. | ||
| * @type string $media Media query the resource applies to. | ||
| * @type string $referrerpolicy Referrer policy for the fetch. | ||
| * @type string $title Title of the resource hint. | ||
| * @type string $type Type of the resource (`text/html`, `text/css`, etc). | ||
| * } | ||
| * } | ||
| * @param string $relation_type The relation type the URLs are printed for. One of | ||
|
|
@@ -4018,28 +4054,41 @@ function wp_resource_hints() { | |
| } | ||
|
|
||
| foreach ( $unique_urls as $atts ) { | ||
| $html = ''; | ||
| $processor = new WP_HTML_Tag_Processor( '<link>' ); | ||
| $processor->next_tag(); | ||
|
|
||
| foreach ( $atts as $attr => $value ) { | ||
| if ( ! is_scalar( $value ) | ||
| || ( ! in_array( $attr, array( 'as', 'crossorigin', 'href', 'pr', 'rel', 'type' ), true ) && ! is_numeric( $attr ) ) | ||
| ) { | ||
| // A list item supplies a valueless attribute, as in `array( 'crossorigin', 'href' => … )`. | ||
| if ( is_int( $attr ) ) { | ||
| if ( ! is_string( $value ) ) { | ||
| continue; | ||
| } | ||
| $attr = $value; | ||
| $value = true; | ||
| } | ||
|
|
||
| /* | ||
| * An attribute may be supplied twice, as a list item and as a key. As in HTML, | ||
| * the first one wins, since the HTML API would otherwise apply the last one. | ||
| */ | ||
| if ( ! isset( $allowed_attributes[ $attr ] ) || null !== $processor->get_attribute( $attr ) ) { | ||
| continue; | ||
| } | ||
|
|
||
| $value = ( 'href' === $attr ) ? esc_url( $value ) : esc_attr( $value ); | ||
|
|
||
| if ( ! is_string( $attr ) ) { | ||
| $html .= " $value"; | ||
| if ( is_bool( $value ) ) { | ||
| if ( ! $allowed_attributes[ $attr ] ) { | ||
| continue; | ||
| } | ||
| } elseif ( is_scalar( $value ) ) { | ||
| $value = (string) $value; | ||
| } else { | ||
| $html .= " $attr='$value'"; | ||
| continue; | ||
| } | ||
| } | ||
|
|
||
| $html = trim( $html ); | ||
| $processor->set_attribute( $attr, $value ); | ||
|
sirreal marked this conversation as resolved.
Resolved
|
||
| } | ||
|
|
||
| echo "<link $html />\n"; | ||
| echo $processor->get_updated_html() . "\n"; | ||
| } | ||
| } | ||
| } | ||
|
|
@@ -4066,23 +4115,28 @@ function wp_preload_resources() { | |
| * | ||
| * @since 6.1.0 | ||
| * @since 6.6.0 Added the `$fetchpriority` attribute. | ||
| * @since 7.3.0 The `crossorigin` attribute may be `true` to print it without a value. | ||
| * List items other than `crossorigin` are no longer printed. | ||
| * | ||
| * @param array $preload_resources { | ||
| * Array of resources and their attributes, or URLs to print for resource preloads. | ||
| * | ||
| * @type array ...$0 { | ||
| * Array of resource attributes. | ||
| * | ||
| * @type string $href URL to include in resource preloads. May be omitted | ||
| * for an image preloaded by its `$imagesrcset`. | ||
| * @type string $as How the browser should treat the resource | ||
| * (`script`, `style`, `image`, `document`, etc). | ||
| * @type string $crossorigin Indicates the CORS policy of the specified resource. | ||
| * @type string $type Type of the resource (`text/html`, `text/css`, etc). | ||
| * @type string $media Accepts media types or media queries. Allows responsive preloading. | ||
| * @type string $imagesizes Responsive source size to the source Set. | ||
| * @type string $imagesrcset Responsive image sources to the source set. | ||
| * @type string $fetchpriority Fetchpriority value for the resource. | ||
| * Array of resource attributes. A valueless attribute may also be supplied | ||
| * as a list item, as in `array( 'crossorigin' )`. | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. do these live in between associative arrays? I find the "list item" language unclear. * Array of resource attributes. Valueless attributes may be passed with
* `true` as their value, or as the string name of the attribute in lieu
* of a full type.
*
* Example:
*
* array( 'href' => 'https://example.com', 'crossorigin', 'as' => 'style' );and I guess this is where I get confused, because this syntax doesn’t work. we’d have to do something awkward like Maybe the legitimate cases doing this are like the following? $attributes = array(
'href' => 'https://example.com',
'as' => 'style',
);
$attributes[] = 'crossorigin';though this still seems a bit out of place in WordPress code. with the few guiding words we have to share in the docs, what are we trying to suggest people write when receiving and sending these values? |
||
| * | ||
| * @type string $href URL to include in resource preloads. May be omitted | ||
| * for an image preloaded by its `$imagesrcset`. | ||
| * @type string $as How the browser should treat the resource | ||
| * (`script`, `style`, `image`, `document`, etc). | ||
| * @type string|bool $crossorigin Indicates the CORS policy of the specified resource. | ||
| * When `true`, it is printed without a value, which | ||
| * is equivalent to `anonymous`. | ||
| * @type string $type Type of the resource (`text/html`, `text/css`, etc). | ||
| * @type string $media Accepts media types or media queries. Allows responsive preloading. | ||
| * @type string $imagesizes Responsive source size to the source Set. | ||
| * @type string $imagesrcset Responsive image sources to the source set. | ||
| * @type string $fetchpriority Fetchpriority value for the resource. | ||
| * } | ||
| * } | ||
| */ | ||
|
|
@@ -4101,35 +4155,83 @@ function wp_preload_resources() { | |
| } | ||
|
|
||
| $attributes = $resource; | ||
| if ( isset( $resource['href'] ) ) { | ||
| $href = $resource['href']; | ||
|
|
||
| // An href which is not a string or which uses a disallowed protocol is unusable. | ||
| $href = ''; | ||
| if ( isset( $resource['href'] ) && is_string( $resource['href'] ) ) { | ||
| $href = sanitize_url( $resource['href'], array( 'http', 'https' ) ); | ||
| } | ||
|
|
||
| if ( '' !== $href ) { | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. might be worth checking additionally if sanitization changed the URL, as the - if ( '' !== $href ) {
+ if ( $resource['href'] !== $href ) { |
||
| if ( isset( $unique_resources[ $href ] ) ) { | ||
| continue; | ||
| } | ||
| $attributes['href'] = $href; | ||
| $unique_resources[ $href ] = $attributes; | ||
| // Media can use imagesrcset and not href. | ||
| } elseif ( isset( $resource['as'], $resource['imagesrcset'] ) && 'image' === $resource['as'] ) { | ||
| } elseif ( | ||
| isset( $resource['as'], $resource['imagesrcset'] ) && | ||
| 'image' === $resource['as'] && | ||
| is_string( $resource['imagesrcset'] ) | ||
| ) { | ||
| if ( isset( $unique_resources[ $resource['imagesrcset'] ] ) ) { | ||
| continue; | ||
| } | ||
| unset( $attributes['href'] ); | ||
| $unique_resources[ $resource['imagesrcset'] ] = $attributes; | ||
| } else { | ||
| continue; | ||
| } | ||
| } | ||
|
|
||
| /* | ||
| * Attributes allowed on a preload. Any attribute not listed as a key is | ||
| * dropped. A value of `true` means the attribute may also be printed as a | ||
| * boolean (valueless) attribute, when it is supplied as `true` or as a list | ||
| * item. Attributes with a value of `false` are printed only with a value. | ||
| */ | ||
| $allowed_attributes = array( | ||
| 'as' => false, | ||
|
sirreal marked this conversation as resolved.
Resolved
|
||
| 'crossorigin' => true, | ||
| 'fetchpriority' => false, | ||
| 'href' => false, | ||
| 'imagesizes' => false, | ||
| 'imagesrcset' => false, | ||
| 'media' => false, | ||
| 'type' => false, | ||
| ); | ||
|
|
||
| // Build and output the HTML for each unique resource. | ||
| foreach ( $unique_resources as $unique_resource ) { | ||
| $html = ''; | ||
| $processor = new WP_HTML_Tag_Processor( '<link rel="preload">' ); | ||
| $processor->next_tag(); | ||
|
|
||
| foreach ( $unique_resource as $resource_key => $resource_value ) { | ||
| if ( ! is_scalar( $resource_value ) ) { | ||
| // A list item supplies a valueless attribute, as in `array( 'crossorigin', 'href' => … )`. | ||
| if ( is_int( $resource_key ) ) { | ||
| if ( ! is_string( $resource_value ) ) { | ||
| continue; | ||
| } | ||
| $resource_key = $resource_value; | ||
| $resource_value = true; | ||
| } | ||
|
|
||
| /* | ||
| * Ignore non-supported attributes. An attribute may also be supplied twice, as a list | ||
| * item and as a key. As in HTML, the first one wins, since the HTML API would | ||
| * otherwise apply the last one. | ||
| */ | ||
| if ( ! isset( $allowed_attributes[ $resource_key ] ) || null !== $processor->get_attribute( $resource_key ) ) { | ||
| continue; | ||
| } | ||
|
|
||
| // Ignore non-supported attributes. | ||
| $non_supported_attributes = array( 'as', 'crossorigin', 'href', 'imagesrcset', 'imagesizes', 'type', 'media', 'fetchpriority' ); | ||
| if ( ! in_array( $resource_key, $non_supported_attributes, true ) && ! is_numeric( $resource_key ) ) { | ||
| if ( is_bool( $resource_value ) ) { | ||
| if ( ! $allowed_attributes[ $resource_key ] ) { | ||
| continue; | ||
| } | ||
| } elseif ( is_scalar( $resource_value ) ) { | ||
| $resource_value = (string) $resource_value; | ||
| } else { | ||
| continue; | ||
| } | ||
|
|
||
|
|
@@ -4145,17 +4247,10 @@ function wp_preload_resources() { | |
| continue; | ||
| } | ||
|
|
||
| $resource_value = ( 'href' === $resource_key ) ? esc_url( $resource_value, array( 'http', 'https' ) ) : esc_attr( $resource_value ); | ||
|
|
||
| if ( ! is_string( $resource_key ) ) { | ||
| $html .= " $resource_value"; | ||
| } else { | ||
| $html .= " $resource_key='$resource_value'"; | ||
| } | ||
| $processor->set_attribute( $resource_key, $resource_value ); | ||
|
sirreal marked this conversation as resolved.
Resolved
|
||
| } | ||
| $html = trim( $html ); | ||
|
|
||
| printf( "<link rel='preload' %s />\n", $html ); | ||
| echo $processor->get_updated_html() . "\n"; | ||
| } | ||
| } | ||
|
|
||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this is internal-only, so not exposing a private method, but I find the
false are printed only with a valueconfusing, and possibly easy to mess up later on.this is not a blocker