Make WordPress Core


Ignore:
Timestamp:
07/15/2026 07:22:36 AM (2 months ago)
Author:
westonruter
Message:

General: Allow configuration of speculative loading defaults via env variables and constants.

Introduce two overrides that let a site or hosting provider change the default speculative loading configuration that the auto value resolves to, without having to ship an mu-plugin:

  • WP_SPECULATIVE_LOADING_DEFAULT_MODE (prefetch or prerender)
  • WP_SPECULATIVE_LOADING_DEFAULT_EAGERNESS (conservative, moderate, or eager).

Each may be supplied as an environment variable, read via getenv(), or as a constant of the same name that takes precedence over it, mirroring how wp_get_environment_type() resolves WP_ENVIRONMENT_TYPE. An unrecognized value falls back to the core default.

These overrides only change what auto resolves to, so an explicit mode or eagerness supplied through the wp_speculation_rules_configuration filter still wins. An eagerness of immediate is rejected because WordPress does not permit it for the document-level rules it generates; accepting it would cause WP_Speculation_Rules::add_rule() to reject the rule and leave the page with no speculation rules at all.

Also relax WP_Speculation_Rules::is_valid_mode() and WP_Speculation_Rules::is_valid_eagerness() to accept mixed, so an arbitrary value from the filter is validated and rejected rather than raising a TypeError.

Fix PHPStan errors in speculative loading functions resulting from insufficient typing.

Developed in https://github.com/WordPress/wordpress-develop/pull/12514.
Follow-up to r59837.

Props westonruter, mukesh27, adamsilverstein, swissspidy.
See #64066, #62503, #64896, #64898.
Fixes #65624.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/wp-includes/speculative-loading.php

    r60681 r62752  
    1212 *
    1313 * @since 6.8.0
     14 * @since 7.1.0 The `WP_SPECULATIVE_LOADING_DEFAULT_MODE` and `WP_SPECULATIVE_LOADING_DEFAULT_EAGERNESS` constants and
     15 *              environment variables can now specify the default mode and eagerness, respectively.
     16 *
     17 * @see wp_get_speculation_rules_default_configuration()
    1418 *
    1519 * @return array<string, string>|null Associative array with 'mode' and 'eagerness' keys, or null if speculative
    1620 *                                    loading is disabled.
     21 * @phpstan-return array{
     22 *     mode: 'prefetch'|'prerender',
     23 *     eagerness: 'conservative'|'moderate'|'eager',
     24 * }|null
    1725 */
    1826function wp_get_speculation_rules_configuration(): ?array {
     
    6068
    6169        // Sanitize the configuration and replace 'auto' with current defaults.
    62         $default_mode      = 'prefetch';
    63         $default_eagerness = 'conservative';
     70        $defaults          = wp_get_speculation_rules_default_configuration();
     71        $default_mode      = $defaults['mode'];
     72        $default_eagerness = $defaults['eagerness'];
     73
    6474        if ( ! is_array( $config ) ) {
    6575                return array(
     
    8999                'eagerness' => $config['eagerness'],
    90100        );
     101}
     102
     103/**
     104 * Returns the default speculation rules configuration that the value 'auto' resolves to.
     105 *
     106 * WordPress Core defaults to a mode of 'prefetch' and an eagerness of 'conservative'. Hosting providers can override
     107 * either default by way of the `WP_SPECULATIVE_LOADING_DEFAULT_MODE` and `WP_SPECULATIVE_LOADING_DEFAULT_EAGERNESS`
     108 * constants or environment variables. This only changes what the 'auto' value resolves to, so a plugin which supplies
     109 * an explicit mode or eagerness via the {@see 'wp_speculation_rules_configuration'} filter continues to take
     110 * precedence.
     111 *
     112 * Note that an eagerness of 'immediate' is not permitted as a default, since WordPress does not allow it for the
     113 * document-level rules that it generates.
     114 *
     115 * @since 7.1.0
     116 * @access private
     117 *
     118 * @return array<string, string> Associative array with 'mode' and 'eagerness' keys.
     119 * @phpstan-return array{
     120 *     mode: 'prefetch'|'prerender',
     121 *     eagerness: 'conservative'|'moderate'|'eager',
     122 * }
     123 */
     124function wp_get_speculation_rules_default_configuration(): array {
     125        $default_mode = 'prefetch';
     126        $mode         = wp_get_speculative_loading_override( 'WP_SPECULATIVE_LOADING_DEFAULT_MODE' );
     127        if ( WP_Speculation_Rules::is_valid_mode( $mode ) ) {
     128                $default_mode = $mode;
     129        }
     130
     131        $default_eagerness = 'conservative';
     132        $eagerness         = wp_get_speculative_loading_override( 'WP_SPECULATIVE_LOADING_DEFAULT_EAGERNESS' );
     133        if (
     134                WP_Speculation_Rules::is_valid_eagerness( $eagerness ) &&
     135                // 'immediate' is a valid eagerness, but for safety WordPress does not allow it for document-level rules.
     136                'immediate' !== $eagerness
     137        ) {
     138                $default_eagerness = $eagerness;
     139        }
     140
     141        return array(
     142                'mode'      => $default_mode,
     143                'eagerness' => $default_eagerness,
     144        );
     145}
     146
     147/**
     148 * Returns the value of a speculative loading override, as supplied by a constant or an environment variable.
     149 *
     150 * The constant takes precedence over the environment variable, consistent with {@see wp_get_environment_type()}.
     151 *
     152 * @since 7.1.0
     153 * @access private
     154 *
     155 * @param string $name Name of the constant and environment variable to look up.
     156 * @return string|null The override value, or null if neither is set.
     157 */
     158function wp_get_speculative_loading_override( string $name ): ?string {
     159        $value = null;
     160
     161        // Check if the environment variable has been set, if `getenv` is available on the system.
     162        if ( function_exists( 'getenv' ) ) {
     163                $has_env = getenv( $name );
     164                if ( false !== $has_env ) {
     165                        $value = $has_env;
     166                }
     167        }
     168
     169        // Fetch the value from a constant, which overrides the environment variable.
     170        if ( defined( $name ) ) {
     171                $has_constant = constant( $name );
     172                if ( is_string( $has_constant ) ) {
     173                        $value = $has_constant;
     174                }
     175        }
     176
     177        return $value;
    91178}
    92179
     
    153240         */
    154241        $href_exclude_paths = (array) apply_filters( 'wp_speculation_rules_href_exclude_paths', array(), $mode );
     242        $href_exclude_paths = array_filter( $href_exclude_paths, 'is_string' );
    155243
    156244        // Ensure that:
Note: See TracChangeset for help on using the changeset viewer.