各位观众老爷,晚上好!今天咱们来聊聊 WordPress 的 URL 重写机制,深入研究一下 WP_Rewrite
这个类,看看它如何通过 $rules
数组来管理 URL 重写规则,以及这些规则在数据库里是怎么藏猫猫的。
咱们的讲座主要分以下几个部分:
WP_Rewrite
类:概览与初始化$rules
数组:URL 重写规则的核心- 规则的生成:从结构到正则
- 规则的存储:数据库中的秘密
- 规则的应用:URL 匹配与查询
- 自定义规则:让你的网站更个性
- 常见问题与调试技巧
准备好了吗?那咱们开始吧!
1. WP_Rewrite
类:概览与初始化
WP_Rewrite
类是 WordPress 负责 URL 重写的核心类。它负责生成、存储和应用 URL 重写规则,让你的 WordPress 网站的 URL 看起来更漂亮、更友好(也更容易被搜索引擎抓取)。
首先,我们来看看 WP_Rewrite
类的初始化过程。通常情况下,你不需要手动实例化这个类,WordPress 会在引导过程中自动帮你搞定。在 wp-includes/class-wp-rewrite.php
文件中,你会找到这个类的定义。
class WP_Rewrite {
/**
* Permalink structure.
*
* @since 2.0.0
* @var string
*/
public $permalink_structure;
/**
* Whether permalinks are enabled.
*
* @since 3.0.0
* @var bool
*/
public $using_permalinks;
/**
* Whether mod_rewrite is being used.
*
* @since 2.0.0
* @var bool
*/
public $mod_rewrite;
/**
* Whether .htaccess exists.
*
* @since 2.0.0
* @var bool
*/
public $use_trailing_slashes;
/**
* Whether the rewrite module is enabled.
*
* @since 2.0.0
* @var bool
*/
public $rewrite_base;
/**
* The rewrite rules.
*
* @since 2.0.0
* @var array
*/
public $rules = array();
// ... 其他属性和方法
}
注意看,这里有个 $rules
属性,类型是数组。这货就是咱们今天的主角!所有的 URL 重写规则都存储在这个数组里。
在 WordPress 初始化时,WP_Rewrite
类的实例会被创建,并且会调用 WP_Rewrite::wp_rewrite_rules()
方法来填充 $rules
数组。这个过程会读取 WordPress 默认的重写规则,以及你在主题或插件中自定义的规则。
2. $rules
数组:URL 重写规则的核心
$rules
数组是一个关联数组,它的键是正则表达式,值是对应的查询字符串。
$this->rules = array(
'index.php$' => 'index.php',
'author/([^/]+)/?$' => 'index.php?author_name=$matches[1]',
'category/([^/]+)/?$' => 'index.php?category_name=$matches[1]',
// ... 更多规则
);
- 键 (正则表达式):用于匹配请求的 URL。如果 URL 匹配了这个正则表达式,那么对应的查询字符串就会被使用。
- 值 (查询字符串):定义了如何处理匹配到的 URL。它通常包含
index.php
以及一些 GET 参数,这些参数会被 WordPress 用来确定要显示的内容。
举个例子:
假设你的网站的 URL 是 http://example.com/category/news/
,而 $rules
数组中包含以下规则:
'category/([^/]+)/?$' => 'index.php?category_name=$matches[1]'
当 WordPress 收到这个 URL 请求时,它会遍历 $rules
数组,找到匹配的规则。在这个例子中,正则表达式 category/([^/]+)/?$
匹配了 http://example.com/category/news/
。
$matches[1]
表示正则表达式中第一个捕获组的内容,也就是 news
。因此,WordPress 会将 URL 重写为 index.php?category_name=news
,然后将这个查询字符串传递给 WordPress 的查询系统,最终显示 news
分类下的文章。
3. 规则的生成:从结构到正则
WordPress 并不是凭空生成这些规则的。它会根据你的 Permalink 设置、分类结构、文章结构等信息,动态生成这些规则。
WP_Rewrite
类提供了一些方法来生成规则,例如:
generate_rewrite_rules()
:用于生成文章、页面、分类、标签等类型的重写规则。generate_date_rewrite_rules()
:用于生成日期归档的重写规则。generate_category_rewrite_rules()
:用于生成分类的重写规则。
这些方法会根据你的 Permalink 设置,生成不同的正则表达式和查询字符串。例如,如果你选择了 "朴素" Permalink 结构(/?p=%post_id%
),那么生成的规则可能如下:
'index.php?p=([0-9]+)$' => 'index.php?p=$matches[1]'
如果你选择了 "文章名" Permalink 结构(/sample-post/
),那么生成的规则可能如下:
'sample-post/?$' => 'index.php?name=sample-post'
更复杂的例子,比如分类目录:
如果你的分类目录结构是 /category/
,而你有一个名为 news
的分类,那么 WordPress 可能会生成如下规则:
'category/news/?$' => 'index.php?category_name=news'
如果你的分类目录结构是 /topics/
,那么对应的规则会变成:
'topics/news/?$' => 'index.php?category_name=news'
关键在于 WP_Rewrite
类会根据你的设置,动态调整生成的正则表达式和查询字符串,以适应你的网站结构。
4. 规则的存储:数据库中的秘密
生成了这些规则之后,WP_Rewrite
类会将它们存储到数据库中。存储的位置是 wp_options
表,对应的 option_name
是 rewrite_rules
。
SELECT * FROM wp_options WHERE option_name = 'rewrite_rules';
这个 option_value
字段存储的是一个序列化的 PHP 数组,也就是 $rules
数组。当你修改 Permalink 设置或者添加自定义规则时,WordPress 会更新这个 option_value
字段。
为什么要序列化?因为数据库字段通常只能存储字符串或数字等简单类型,而 $rules
数组是一个复杂的关联数组,包含正则表达式和查询字符串。通过序列化,可以将这个数组转换为一个字符串,方便存储到数据库中。
当你需要使用这些规则时,WordPress 会从数据库中读取这个序列化的字符串,然后反序列化,重新得到 $rules
数组。
$rewrite_rules = get_option( 'rewrite_rules' );
if ( ! is_array( $rewrite_rules ) ) {
$rewrite_rules = array();
}
5. 规则的应用:URL 匹配与查询
当 WordPress 收到一个 URL 请求时,它会遍历 $rules
数组,尝试找到匹配的规则。这个过程发生在 WP::parse_request()
方法中。
public function parse_request( $query_vars = array() ) {
global $wp_rewrite;
// Process PATH_INFO, REQUEST_URI, and argv.
$this->query_vars = apply_filters( 'request', $this->query_vars );
// Parse current request.
$rewrite = $wp_rewrite->wp_rewrite_rules(); // 获取重写规则
if ( ! empty( $rewrite ) ) {
$this->matched_rule = $wp_rewrite->wp_find_matching_rewrite_rule( $this->request_uri, $rewrite ); // 查找匹配的规则
if ( $this->matched_rule ) {
$this->matched_query = $rewrite[ $this->matched_rule ];
parse_str( $this->matched_query, $qv );
$_GET = array_merge( $_GET, $qv );
$_REQUEST = array_merge( $_REQUEST, $qv );
}
}
// ... 其他代码
}
WP_Rewrite::wp_rewrite_rules()
方法会从数据库中读取并反序列化 rewrite_rules
option,得到 $rules
数组。然后,WP_Rewrite::wp_find_matching_rewrite_rule()
方法会遍历 $rules
数组,找到第一个匹配当前 URL 的规则。
如果找到了匹配的规则,WordPress 会将对应的查询字符串解析成 GET 参数,然后将这些参数合并到 $_GET
和 $_REQUEST
数组中。
最后,WordPress 会根据这些 GET 参数,确定要显示的内容。例如,如果 category_name
参数是 news
,那么 WordPress 就会显示 news
分类下的文章。
6. 自定义规则:让你的网站更个性
除了 WordPress 默认的重写规则,你还可以自定义规则,让你的网站的 URL 更加个性化。
有两种主要的方式来添加自定义规则:
- 通过
add_rewrite_rule()
函数:这是一种比较简单的方式,可以直接在你的主题或插件中使用。 - 通过
add_rewrite_tag()
和add_rewrite_endpoint()
函数:这是一种更灵活的方式,可以定义自定义的查询变量和端点。
6.1 add_rewrite_rule()
add_rewrite_rule()
函数可以让你添加一条自定义的重写规则。
add_rewrite_rule( string $regex, string $redirect, string $priority = 'top' )
$regex
:用于匹配 URL 的正则表达式。$redirect
:对应的查询字符串。$priority
:规则的优先级,可以是top
或bottom
。
例如,你想创建一个规则,将 http://example.com/books/([0-9]+)/
重写为 index.php?book_id=$matches[1]
,你可以这样写:
add_action( 'init', 'my_custom_rewrite_rules' );
function my_custom_rewrite_rules() {
add_rewrite_rule(
'books/([0-9]+)/?',
'index.php?book_id=$matches[1]',
'top'
);
flush_rewrite_rules(); // Important!
}
注意: 在添加或修改重写规则后,一定要调用 flush_rewrite_rules()
函数,否则规则不会生效。这个函数会清空并重建 WordPress 的重写规则,更新数据库中的 rewrite_rules
option。
6.2 add_rewrite_tag()
和 add_rewrite_endpoint()
add_rewrite_tag()
函数可以让你定义自定义的查询变量。
add_rewrite_tag( string $tag, string $regex, string $query = '' )
$tag
:查询变量的名称,例如%book_id%
。$regex
:用于匹配查询变量值的正则表达式,例如([0-9]+)
。$query
:可选的查询字符串,用于覆盖默认的查询字符串。
add_rewrite_endpoint()
函数可以让你创建一个自定义的端点。
add_rewrite_endpoint( string $endpoint, int $places )
$endpoint
:端点的名称,例如book
。$places
:端点的位置,可以是EP_PERMALINK
、EP_PAGES
、EP_CATEGORIES
等。
例如,你想创建一个 book
端点,用于显示书籍的信息,你可以这样写:
add_action( 'init', 'my_custom_rewrite_endpoint' );
function my_custom_rewrite_endpoint() {
add_rewrite_endpoint( 'book', EP_PERMALINK );
flush_rewrite_rules(); // Important!
}
add_filter( 'template_include', 'my_custom_template_include' );
function my_custom_template_include( $template ) {
if ( get_query_var( 'book' ) ) {
return locate_template( 'single-book.php' ); // 自定义模板
}
return $template;
}
这样,你就可以通过 http://example.com/sample-post/book/
访问 sample-post
这篇文章的 book
端点。
7. 常见问题与调试技巧
- 规则不生效: 确保在添加或修改重写规则后调用了
flush_rewrite_rules()
函数。 - 冲突: 如果多个规则匹配同一个 URL,WordPress 会使用第一个匹配的规则。检查你的规则的优先级,确保优先级高的规则排在前面。
- 调试: 可以使用
global $wp_rewrite; var_dump( $wp_rewrite->rules );
来查看当前的重写规则,或者使用WP_Query
对象的request
属性来查看 WordPress 最终生成的 SQL 查询语句。 .htaccess
文件: 如果你的网站使用 Apache 服务器,WordPress 会尝试更新.htaccess
文件,以实现 URL 重写。确保你的.htaccess
文件可写,或者手动更新.htaccess
文件。- Nginx 服务器: 如果你的网站使用 Nginx 服务器,你需要手动配置 Nginx 的重写规则。WordPress 不会自动更新 Nginx 的配置文件。
表格总结
函数/方法 | 作用 |
---|---|
WP_Rewrite 类 |
负责 URL 重写的核心类 |
$rules 数组 |
存储 URL 重写规则 |
add_rewrite_rule() |
添加一条自定义的重写规则 |
add_rewrite_tag() |
定义自定义的查询变量 |
add_rewrite_endpoint() |
创建一个自定义的端点 |
flush_rewrite_rules() |
清空并重建 WordPress 的重写规则,更新数据库 |
get_option('rewrite_rules') |
从数据库获取重写规则 |
好啦,今天的讲座就到这里。希望大家对 WordPress 的 URL 重写机制有了更深入的了解。记住,理解这些底层机制,能让你更好地控制你的 WordPress 网站,让它更强大、更灵活。 如果有问题,欢迎随时提问! 咱们下次再见!