-
Notifications
You must be signed in to change notification settings - Fork 3.6k
Provide mechanism for host to change default Speculative Loading eagerness and mode #12514
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
Changes from all commits
cf8200e
50289aa
90f2ab5
652ba8f
28304ef
da32ce6
522aa2b
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 |
|---|---|---|
|
|
@@ -11,9 +11,17 @@ | |
| * Returns the speculation rules configuration. | ||
| * | ||
| * @since 6.8.0 | ||
| * @since 7.1.0 The `WP_SPECULATIVE_LOADING_DEFAULT_MODE` and `WP_SPECULATIVE_LOADING_DEFAULT_EAGERNESS` constants and | ||
| * environment variables can now specify the default mode and eagerness, respectively. | ||
| * | ||
| * @see wp_get_speculation_rules_default_configuration() | ||
| * | ||
| * @return array<string, string>|null Associative array with 'mode' and 'eagerness' keys, or null if speculative | ||
| * loading is disabled. | ||
| * @phpstan-return array{ | ||
| * mode: 'prefetch'|'prerender', | ||
| * eagerness: 'conservative'|'moderate'|'eager', | ||
| * }|null | ||
| */ | ||
| function wp_get_speculation_rules_configuration(): ?array { | ||
| // By default, speculative loading is only enabled for sites with pretty permalinks when no user is logged in. | ||
|
|
@@ -59,8 +67,10 @@ function wp_get_speculation_rules_configuration(): ?array { | |
| } | ||
|
|
||
| // Sanitize the configuration and replace 'auto' with current defaults. | ||
| $default_mode = 'prefetch'; | ||
| $default_eagerness = 'conservative'; | ||
| $defaults = wp_get_speculation_rules_default_configuration(); | ||
| $default_mode = $defaults['mode']; | ||
| $default_eagerness = $defaults['eagerness']; | ||
|
|
||
| if ( ! is_array( $config ) ) { | ||
| return array( | ||
| 'mode' => $default_mode, | ||
|
|
@@ -90,6 +100,83 @@ function wp_get_speculation_rules_configuration(): ?array { | |
| ); | ||
| } | ||
|
|
||
| /** | ||
| * Returns the default speculation rules configuration that the value 'auto' resolves to. | ||
| * | ||
| * WordPress Core defaults to a mode of 'prefetch' and an eagerness of 'conservative'. Hosting providers can override | ||
| * either default by way of the `WP_SPECULATIVE_LOADING_DEFAULT_MODE` and `WP_SPECULATIVE_LOADING_DEFAULT_EAGERNESS` | ||
| * constants or environment variables. This only changes what the 'auto' value resolves to, so a plugin which supplies | ||
| * an explicit mode or eagerness via the {@see 'wp_speculation_rules_configuration'} filter continues to take | ||
| * precedence. | ||
| * | ||
| * Note that an eagerness of 'immediate' is not permitted as a default, since WordPress does not allow it for the | ||
| * document-level rules that it generates. | ||
| * | ||
| * @since 7.1.0 | ||
| * @access private | ||
| * | ||
| * @return array<string, string> Associative array with 'mode' and 'eagerness' keys. | ||
| * @phpstan-return array{ | ||
| * mode: 'prefetch'|'prerender', | ||
| * eagerness: 'conservative'|'moderate'|'eager', | ||
| * } | ||
| */ | ||
| function wp_get_speculation_rules_default_configuration(): array { | ||
| $default_mode = 'prefetch'; | ||
| $mode = wp_get_speculative_loading_override( 'WP_SPECULATIVE_LOADING_DEFAULT_MODE' ); | ||
| if ( WP_Speculation_Rules::is_valid_mode( $mode ) ) { | ||
| $default_mode = $mode; | ||
| } | ||
|
|
||
| $default_eagerness = 'conservative'; | ||
| $eagerness = wp_get_speculative_loading_override( 'WP_SPECULATIVE_LOADING_DEFAULT_EAGERNESS' ); | ||
| if ( | ||
| WP_Speculation_Rules::is_valid_eagerness( $eagerness ) && | ||
| // 'immediate' is a valid eagerness, but for safety WordPress does not allow it for document-level rules. | ||
| 'immediate' !== $eagerness | ||
| ) { | ||
| $default_eagerness = $eagerness; | ||
| } | ||
|
|
||
| return array( | ||
| 'mode' => $default_mode, | ||
| 'eagerness' => $default_eagerness, | ||
| ); | ||
| } | ||
|
|
||
| /** | ||
| * Returns the value of a speculative loading override, as supplied by a constant or an environment variable. | ||
| * | ||
| * The constant takes precedence over the environment variable, consistent with {@see wp_get_environment_type()}. | ||
| * | ||
| * @since 7.1.0 | ||
| * @access private | ||
| * | ||
| * @param string $name Name of the constant and environment variable to look up. | ||
| * @return string|null The override value, or null if neither is set. | ||
| */ | ||
| function wp_get_speculative_loading_override( string $name ): ?string { | ||
| $value = null; | ||
|
|
||
| // Check if the environment variable has been set, if `getenv` is available on the system. | ||
| if ( function_exists( 'getenv' ) ) { | ||
| $has_env = getenv( $name ); | ||
| if ( false !== $has_env ) { | ||
| $value = $has_env; | ||
| } | ||
| } | ||
|
|
||
| // Fetch the value from a constant, which overrides the environment variable. | ||
| if ( defined( $name ) ) { | ||
| $has_constant = constant( $name ); | ||
| if ( is_string( $has_constant ) ) { | ||
| $value = $has_constant; | ||
| } | ||
| } | ||
|
Comment on lines
+169
to
+175
Member
Author
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. I'm not sure about this.
Member
Author
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. I'd keep the In practice these constants are always strings, and the only path this affects is a host misconfiguring the type — which the downstream Reply drafted by Claude Code on behalf of @westonruter. |
||
|
|
||
| return $value; | ||
| } | ||
|
|
||
| /** | ||
| * Returns the full speculation rules data based on the configuration. | ||
| * | ||
|
|
@@ -152,6 +239,7 @@ function wp_get_speculation_rules(): ?WP_Speculation_Rules { | |
| * @param string $mode Mode used to apply speculative loading. Either 'prefetch' or 'prerender'. | ||
| */ | ||
| $href_exclude_paths = (array) apply_filters( 'wp_speculation_rules_href_exclude_paths', array(), $mode ); | ||
| $href_exclude_paths = array_filter( $href_exclude_paths, 'is_string' ); | ||
|
|
||
| // Ensure that: | ||
| // 1. There are no duplicates. | ||
|
|
||
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.
is
getenvsometimes not available?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.
That's right. Some hosts prevent the function from being available, apparently.
You can see this same logic is being used in
wp_get_environment_type():wordpress-develop/src/wp-includes/load.php
Lines 280 to 286 in 5bb714a
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 noticed that and I also noticed multiple instances where we use getenv without the check so I wondered if that was just old code. I still wonder how/why it would be undefined.
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.
Oh yeah, I see that:
wordpress-develop/src/wp-includes/connectors.php
Lines 444 to 451 in 5bb714a
It may be a situation similar to Core-65423, then. In any case, I think safer to include it here since it would be in the critical path for all frontend page views, whereas the Connectors may only run when on the Connectors 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'm fine being very defensive here and it is possible to disable this function, it just seems.... highly unlikely.
But it doesn't hurt to have the check, so fine to leave it. I was mostly curious why it was there if there was some reason hosts might disable it in a shared environment for security reasons etc, but I guess thats unlikely really and much more likely plugins use it without checking it exists since its been part of php for a long while.