各位观众老爷,晚上好! 欢迎来到今晚的 “WordPress 源码解剖大会” 。我是你们的导游兼主刀医生,今天咱们要解剖的是 WordPress 的 rewrite 规则,重点是 add_rewrite_rule()
和 flush_rewrite_rules()
这两个家伙。
别害怕,虽然是源码,但保证不血腥,只会让你感觉“哦,原来是这样啊!”。 准备好了吗? Let’s dive in!
Rewrite 规则是个啥?
在开始之前,咱们先明确一下 rewrite 规则是干嘛的。简单来说,rewrite 规则就是告诉 Web 服务器(通常是 Apache 或 Nginx),当用户访问某个 URL 时,实际上应该访问哪个文件或执行哪个 PHP 脚本。
举个例子,假设你有一个文章,它的实际 URL 可能是 index.php?p=123
,但你想让用户通过 blog/my-awesome-article
这样的 URL 访问它。 这就是 rewrite 规则的用武之地了。它会把 blog/my-awesome-article
"翻译" 成 index.php?p=123
,用户看到的还是友好的 URL,但服务器知道该怎么处理。
add_rewrite_rule()
:规则制造者
顾名思义,add_rewrite_rule()
的作用就是添加一条新的 rewrite 规则。 它的原型是这样的:
function add_rewrite_rule( $regex, $redirect, $priority = 'bottom' ) {
global $wp_rewrite;
$wp_rewrite->add_rule( $regex, $redirect, $priority );
}
看起来很简单,对吧?它实际上只是调用了 $wp_rewrite
对象的 add_rule()
方法。$wp_rewrite
是一个全局对象,负责管理所有的 rewrite 规则。
咱们来看看 $wp_rewrite->add_rule()
做了什么:
function add_rule( $regex, $redirect, $priority = 'bottom' ) {
if ( 'top' === $priority ) {
$this->rules = array_merge( array( $regex => $redirect ), $this->rules );
} else {
$this->rules[ $regex ] = $redirect;
}
}
这段代码也很简单。它把新的规则添加到 $this->rules
数组中。 $this->rules
是 $wp_rewrite
对象的一个属性,它存储了所有的 rewrite 规则。
$regex
:这是一个正则表达式,用于匹配 URL。$redirect
:这是实际要访问的 URL(通常包含index.php
和一些参数)。$priority
:指定规则的优先级。'top'
表示优先匹配,'bottom'
表示最后匹配。
例子:添加一个简单的 rewrite 规则
假设我们要创建一个规则,把 books/([0-9]+)
重写成 index.php?book_id=$matches[1]
。 这段代码可以这么写:
add_action( 'init', 'my_custom_rewrite_rule' );
function my_custom_rewrite_rule() {
add_rewrite_rule(
'books/([0-9]+)/?', // Regex to match
'index.php?book_id=$matches[1]', // Redirect to
'top' // Priority
);
}
注意几点:
- 我们把
add_rewrite_rule()
放在init
钩子中执行。 这是因为 rewrite 规则需要在 WordPress 初始化之后才能添加。 - 正则表达式
books/([0-9]+)/?
匹配以books/
开头,后面跟着一个或多个数字,最后可以有一个斜杠的 URL。 $matches[1]
是正则表达式中第一个括号捕获的内容,也就是书的 ID。
flush_rewrite_rules()
:规则的刷新者
添加了 rewrite 规则之后,并不会立即生效。 你需要调用 flush_rewrite_rules()
函数来刷新 rewrite 规则。 这个函数会更新 .htaccess
文件(如果是 Apache 服务器)或者其他服务器配置文件,让服务器知道新的规则。
flush_rewrite_rules()
的原型是这样的:
function flush_rewrite_rules( $hard = true ) {
global $wp_rewrite;
$wp_rewrite->flush_rules( $hard );
}
同样,它也是调用了 $wp_rewrite
对象的 flush_rules()
方法。
$wp_rewrite->flush_rules()
的实现比较复杂,咱们一点点来分析:
function flush_rules( $hard = true ) {
global $wp_filesystem;
// Check if the rules need to be flushed.
$rules = $this->wp_rewrite_rules();
if ( false === $rules ) {
return false;
}
if ( $hard ) {
$this->rewrite_rules();
}
if ( is_multisite() ) {
delete_transient( 'rewrite_rules' );
return true;
}
// If using mod_rewrite, update the .htaccess file.
if ( $this->using_mod_rewrite_permalinks() ) {
if ( ! $wp_filesystem ) {
require_once ABSPATH . 'wp-admin/includes/file.php';
WP_Filesystem();
}
$home_path = get_home_path();
$htaccess_file = $home_path . '.htaccess';
// ... (读取 .htaccess 文件,更新规则) ...
if ( $wp_filesystem->is_writable( $htaccess_file ) ) {
$wp_filesystem->put_contents( $htaccess_file, $rules, FS_CHMOD_FILE );
} else {
// ... (提示用户手动更新 .htaccess 文件) ...
}
} else {
// ... (如果不是 mod_rewrite,则更新 web.config 文件) ...
}
delete_transient( 'rewrite_rules' );
return true;
}
这段代码做了以下几件事:
-
检查是否需要刷新规则: 通过调用
$this->wp_rewrite_rules()
方法获取当前的 rewrite 规则。 如果返回false
,则表示不需要刷新。 -
生成新的 rewrite 规则: 如果
$hard
参数为true
,则调用$this->rewrite_rules()
方法重新生成所有的 rewrite 规则。 这个方法会将所有的规则组合成一个字符串,用于更新.htaccess
文件。 -
多站点处理: 如果是 WordPress 多站点,则删除
rewrite_rules
缓存。 -
更新
.htaccess
文件: 如果使用了 mod_rewrite (Apache 服务器),则读取.htaccess
文件,将新的 rewrite 规则写入该文件。 如果.htaccess
文件不可写,则提示用户手动更新。 -
更新 web.config 文件: 如果没有使用 mod_rewrite (例如 Nginx 服务器),则更新
web.config
文件(如果存在)。 -
删除缓存: 删除
rewrite_rules
缓存。
$this->wp_rewrite_rules()
:规则获取器
这个方法负责生成最终的 rewrite 规则字符串,用于更新 .htaccess
文件。 它的代码比较长,咱们只看关键部分:
function wp_rewrite_rules() {
$rewrite_rules = apply_filters( 'rewrite_rules_array', $this->rules );
if ( empty( $rewrite_rules ) ) {
return false;
}
$lines = array();
foreach ( (array) $rewrite_rules as $match => $query ) {
$match = preg_replace( '#^/#', '', $match );
$match = str_replace( array( "rn", "n" ), "n", $match );
$query = str_replace( array( "rn", "n" ), "n", $query );
$lines[] = 'RewriteRule ^' . $match . ' ' . $query . ' [QSA,L]';
}
$rules = "n# BEGIN WordPressn<IfModule mod_rewrite.c>nRewriteEngine OnnRewriteBase " . trailingslashit( $this->rewrite_base ) . "nRewriteRule ^index.php$ - [L]n" . implode( "n", $lines ) . "n</IfModule>n# END WordPressn";
return $rules;
}
这段代码做了以下几件事:
-
应用过滤器: 通过
apply_filters( 'rewrite_rules_array', $this->rules )
应用rewrite_rules_array
过滤器。 允许插件修改 rewrite 规则。 -
遍历规则: 遍历
$this->rules
数组,将每一条规则转换成 Apache rewrite 规则的格式。 例如,将'books/([0-9]+)/?' => 'index.php?book_id=$matches[1]'
转换成RewriteRule ^books/([0-9]+)/? index.php?book_id=$matches[1] [QSA,L]
。 -
生成规则字符串: 将所有的规则组合成一个字符串,包括
RewriteEngine On
、RewriteBase
等指令。
$this->using_mod_rewrite_permalinks()
:判断是否使用 mod_rewrite
这个方法用于判断是否使用了 mod_rewrite (Apache 服务器)。 它的实现很简单:
function using_mod_rewrite_permalinks() {
if ( isset( $_SERVER['SERVER_SOFTWARE'] ) && strpos( $_SERVER['SERVER_SOFTWARE'], 'Apache' ) !== false && $this->using_permalinks() ) {
return true;
}
return false;
}
它检查 $_SERVER['SERVER_SOFTWARE']
变量是否包含 Apache
字符串,并且 using_permalinks()
方法返回 true
。using_permalinks()
方法检查是否设置了固定的永久链接格式。
重点总结
函数/方法 | 作用 | 参数 | 返回值 |
---|---|---|---|
add_rewrite_rule() |
添加一条新的 rewrite 规则。 | $regex (正则表达式), $redirect (重定向 URL), $priority (优先级) |
无 |
flush_rewrite_rules() |
刷新 rewrite 规则,更新 .htaccess 或其他服务器配置文件。 |
$hard (是否强制刷新,默认为 true ) |
true (成功) 或 false (失败) |
$wp_rewrite->add_rule() |
实际上执行添加 rewrite 规则的操作。 | $regex (正则表达式), $redirect (重定向 URL), $priority (优先级) |
无 |
$wp_rewrite->flush_rules() |
实际上执行刷新 rewrite 规则的操作。 | $hard (是否强制刷新,默认为 true ) |
true (成功) 或 false (失败) |
$wp_rewrite->wp_rewrite_rules() |
生成用于更新 .htaccess 文件的 rewrite 规则字符串。 |
无 | 包含 rewrite 规则的字符串 |
$wp_rewrite->using_mod_rewrite_permalinks() |
判断是否使用了 mod_rewrite (Apache 服务器)。 | 无 | true (使用了 mod_rewrite) 或 false (未使用 mod_rewrite) |
注意事项
- 性能问题: 频繁调用
flush_rewrite_rules()
会导致性能问题,因为它会更新.htaccess
文件。 应该尽量避免在每次页面加载时都调用它。 建议只在添加或修改 rewrite 规则时调用。 .htaccess
文件权限: 确保.htaccess
文件可写,否则 WordPress 无法自动更新 rewrite 规则。- 正则表达式: 正确编写正则表达式非常重要。 如果正则表达式写错了,可能会导致 rewrite 规则无法生效。
- 优先级: 规则的优先级也很重要。 如果有多个规则匹配同一个 URL,那么优先级最高的规则会生效。
总结
add_rewrite_rule()
和 flush_rewrite_rules()
是 WordPress 中用于管理 rewrite 规则的两个核心函数。 理解它们的底层实现可以帮助你更好地控制 WordPress 的 URL 结构,创建更友好的 URL,并提高网站的 SEO。
希望今天的解剖对大家有所帮助。 记住,源码并不可怕,只要你敢于探索,就能发现其中的奥秘。
下次再见!