wp_get_speculation_rules()
云策文档标注
概述
wp_get_speculation_rules() 函数基于配置返回完整的推测规则数据,用于控制 WordPress 前端页面的预取或预渲染行为。它通过 WP_Speculation_Rules 对象管理规则,并支持通过过滤器和动作钩子进行自定义。
关键要点
- 函数返回 WP_Speculation_Rules 对象或 null(如果推测加载在当前上下文中被禁用)。
- 默认排除特定路径(如 /wp-admin/*),并支持通过 'wp_speculation_rules_href_exclude_paths' 过滤器添加自定义排除路径。
- 使用 'wp_load_speculation_rules' 动作钩子可以修改或添加额外的推测规则。
- 规则条件包括 href_matches 和 selector_matches,用于匹配 URL 和 CSS 选择器。
- 函数内部处理路径前缀、重复项和顺序,确保规则列表有效。
代码示例
function wp_get_speculation_rules(): ?WP_Speculation_Rules {
$configuration = wp_get_speculation_rules_configuration();
if ( null === $configuration ) {
return null;
}
$mode = $configuration['mode'];
$eagerness = $configuration['eagerness'];
$prefixer = new WP_URL_Pattern_Prefixer();
$base_href_exclude_paths = array(
$prefixer->prefix_path_pattern( '/wp-*.php', 'site' ),
$prefixer->prefix_path_pattern( '/wp-admin/*', 'site' ),
$prefixer->prefix_path_pattern( '/*', 'uploads' ),
$prefixer->prefix_path_pattern( '/*', 'content' ),
$prefixer->prefix_path_pattern( '/*', 'plugins' ),
$prefixer->prefix_path_pattern( '/*', 'template' ),
$prefixer->prefix_path_pattern( '/*', 'stylesheet' ),
);
if ( get_option( 'permalink_structure' ) ) {
$base_href_exclude_paths[] = $prefixer->prefix_path_pattern( '/*?(.+)', 'home' );
} else {
$base_href_exclude_paths[] = $prefixer->prefix_path_pattern( '/*?*(^|&)*nonce*=*', 'home' );
}
$href_exclude_paths = (array) apply_filters( 'wp_speculation_rules_href_exclude_paths', array(), $mode );
$href_exclude_paths = array_values(
array_unique(
array_merge(
$base_href_exclude_paths,
array_map(
static function ( string $href_exclude_path ) use ( $prefixer ): string {
return $prefixer->prefix_path_pattern( $href_exclude_path );
},
$href_exclude_paths
)
)
)
);
$speculation_rules = new WP_Speculation_Rules();
$main_rule_conditions = array(
array(
'href_matches' => $prefixer->prefix_path_pattern( '/*' ),
),
array(
'not' => array(
'href_matches' => $href_exclude_paths,
),
),
array(
'not' => array(
'selector_matches' => 'a[rel~="nofollow"]',
),
),
array(
'not' => array(
'selector_matches' => ".no-{$mode}, .no-{$mode} a",
),
),
);
if ( 'prerender' === $mode ) {
$main_rule_conditions[] = array(
'not' => array(
'selector_matches' => '.no-prefetch, .no-prefetch a',
),
);
}
$speculation_rules->add_rule(
$mode,
'main',
array(
'source' => 'document',
'where' => array(
'and' => $main_rule_conditions,
),
'eagerness' => $eagerness,
)
);
do_action( 'wp_load_speculation_rules', $speculation_rules );
return $speculation_rules;
}注意事项
- 路径排除规则基于 WordPress 根目录,使用斜杠开头,支持通配符 *。
- 某些核心路径(如 /wp-login.php)始终被排除,无法通过过滤器修改。
- 在 'prerender' 模式下,会自动排除 'prefetch' 的退出选择器。
- 函数自 WordPress 6.8.0 版本引入。
原文内容
Returns the full speculation rules data based on the configuration.
Description
Plugins with features that rely on frontend URLs to exclude from prefetching or prerendering should use the ‘wp_speculation_rules_href_exclude_paths’ filter to ensure those URL patterns are excluded.
Additional speculation rules other than the default rule from WordPress Core can be provided by using the ‘wp_load_speculation_rules’ action and amending the passed WP_Speculation_Rules object.
Source
function wp_get_speculation_rules(): ?WP_Speculation_Rules {
$configuration = wp_get_speculation_rules_configuration();
if ( null === $configuration ) {
return null;
}
$mode = $configuration['mode'];
$eagerness = $configuration['eagerness'];
$prefixer = new WP_URL_Pattern_Prefixer();
$base_href_exclude_paths = array(
$prefixer->prefix_path_pattern( '/wp-*.php', 'site' ),
$prefixer->prefix_path_pattern( '/wp-admin/*', 'site' ),
$prefixer->prefix_path_pattern( '/*', 'uploads' ),
$prefixer->prefix_path_pattern( '/*', 'content' ),
$prefixer->prefix_path_pattern( '/*', 'plugins' ),
$prefixer->prefix_path_pattern( '/*', 'template' ),
$prefixer->prefix_path_pattern( '/*', 'stylesheet' ),
);
/*
* If pretty permalinks are enabled, exclude any URLs with query parameters.
* Otherwise, exclude specifically the URLs with a `_wpnonce` query parameter or any other query parameter
* containing the word `nonce`.
*/
if ( get_option( 'permalink_structure' ) ) {
$base_href_exclude_paths[] = $prefixer->prefix_path_pattern( '/*\?(.+)', 'home' );
} else {
$base_href_exclude_paths[] = $prefixer->prefix_path_pattern( '/*\?*(^|&)*nonce*=*', 'home' );
}
/**
* Filters the paths for which speculative loading should be disabled.
*
* All paths should start in a forward slash, relative to the root document. The `*` can be used as a wildcard.
* If the WordPress site is in a subdirectory, the exclude paths will automatically be prefixed as necessary.
*
* Note that WordPress always excludes certain path patterns such as `/wp-login.php` and `/wp-admin/*`, and those
* cannot be modified using the filter.
*
* @since 6.8.0
*
* @param string[] $href_exclude_paths Additional path patterns to disable speculative loading for.
* @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 );
// Ensure that:
// 1. There are no duplicates.
// 2. The base paths cannot be removed.
// 3. The array has sequential keys (i.e. array_is_list()).
$href_exclude_paths = array_values(
array_unique(
array_merge(
$base_href_exclude_paths,
array_map(
static function ( string $href_exclude_path ) use ( $prefixer ): string {
return $prefixer->prefix_path_pattern( $href_exclude_path );
},
$href_exclude_paths
)
)
)
);
$speculation_rules = new WP_Speculation_Rules();
$main_rule_conditions = array(
// Include any URLs within the same site.
array(
'href_matches' => $prefixer->prefix_path_pattern( '/*' ),
),
// Except for excluded paths.
array(
'not' => array(
'href_matches' => $href_exclude_paths,
),
),
// Also exclude rel=nofollow links, as certain plugins use that on their links that perform an action.
array(
'not' => array(
'selector_matches' => 'a[rel~="nofollow"]',
),
),
// Also exclude links that are explicitly marked to opt out, either directly or via a parent element.
array(
'not' => array(
'selector_matches' => ".no-{$mode}, .no-{$mode} a",
),
),
);
// If using 'prerender', also exclude links that opt out of 'prefetch' because it's part of 'prerender'.
if ( 'prerender' === $mode ) {
$main_rule_conditions[] = array(
'not' => array(
'selector_matches' => '.no-prefetch, .no-prefetch a',
),
);
}
$speculation_rules->add_rule(
$mode,
'main',
array(
'source' => 'document',
'where' => array(
'and' => $main_rule_conditions,
),
'eagerness' => $eagerness,
)
);
/**
* Fires when speculation rules data is loaded, allowing to amend the rules.
*
* @since 6.8.0
*
* @param WP_Speculation_Rules $speculation_rules Object representing the speculation rules to use.
*/
do_action( 'wp_load_speculation_rules', $speculation_rules );
return $speculation_rules;
}
Hooks
- do_action( ‘wp_load_speculation_rules’, WP_Speculation_Rules $speculation_rules )
-
Fires when speculation rules data is loaded, allowing to amend the rules.
- apply_filters( ‘wp_speculation_rules_href_exclude_paths’, string[] $href_exclude_paths, string $mode )
-
Filters the paths for which speculative loading should be disabled.
Changelog
| Version | Description |
|---|---|
| 6.8.0 | Introduced. |