好的,今天咱们就来聊聊 WordPress 里那个神秘又强大的 add_rewrite_rule()
函数,看看它到底是怎么把你的自定义 URL 规则塞进 WordPress 的大脑里,让它乖乖听话的。
(清清嗓子,调整麦克风) 各位观众老爷,晚上好!
今天咱们要讲的这个 add_rewrite_rule()
,那可是 WordPress URL 重写机制中的一员大将。 你想让你的网站看起来更酷、更 SEO 友好,或者搞一些奇奇怪怪的自定义 URL,那就得靠它了。 但是,直接用它可能有点懵,因为它背后藏着不少细节。 所以,咱们就一层一层扒开它的源码,看看它到底是怎么运作的。
一、 add_rewrite_rule()
的基本用法
先来个热身,回顾一下 add_rewrite_rule()
最基本的用法:
add_action( 'init', 'my_custom_rewrite_rule' );
function my_custom_rewrite_rule() {
add_rewrite_rule(
'^products/([0-9]+)/?$', // 正则表达式,匹配 URL
'index.php?pagename=products&product_id=$matches[1]', // 替换成什么
'top' // 位置:'top' (默认), 'bottom'
);
flush_rewrite_rules(); // 刷新重写规则!非常重要!
}
这段代码的意思是:
add_action( 'init', 'my_custom_rewrite_rule' );
: 在 WordPress 初始化的时候,执行my_custom_rewrite_rule
函数。init
是个好时机,因为这个时候 WordPress 已经加载了大部分核心功能,包括重写规则。add_rewrite_rule()
: 核心函数,添加重写规则。'^products/([0-9]+)/?$'
: 这是一个正则表达式,用来匹配 URL。 比如products/123/
就会被匹配到。([0-9]+)
用来捕获数字,稍后可以通过$matches[1]
访问。'index.php?pagename=products&product_id=$matches[1]'
: 当 URL 匹配到上面的正则表达式时,就用这个字符串来替换它。 这里实际上是告诉 WordPress,把这个 URL 当作访问index.php
,并传递pagename
和product_id
这两个参数。'top'
: 可选参数,指定规则的位置。'top'
表示放在规则列表的顶部,'bottom'
表示放在底部。 默认是'top'
。 放在顶部意味着这条规则会优先被匹配。
flush_rewrite_rules()
: 非常重要! 每次添加或修改重写规则后,都必须刷新重写规则。 这个函数会重新生成.htaccess
文件(如果你的服务器支持),或者更新 WordPress 数据库中的重写规则。 不刷新,你的规则就不会生效!
二、深入 add_rewrite_rule()
的源码
现在,让我们深入 add_rewrite_rule()
的源码,看看它背后到底做了什么。 add_rewrite_rule()
函数位于 wp-includes/rewrite.php
文件中。 我们简化一下,只保留核心部分:
function add_rewrite_rule( $regex, $redirect, $priority = 'top' ) {
global $wp_rewrite;
$wp_rewrite->add_rule( $regex, $redirect, $priority );
}
看到没? add_rewrite_rule()
自己啥也没干,它只是调用了 $wp_rewrite
对象的 add_rule()
方法。 $wp_rewrite
是一个全局对象,它是 WP_Rewrite
类的一个实例。 WP_Rewrite
类负责管理所有的重写规则。
所以,真正的秘密都藏在 WP_Rewrite::add_rule()
方法里。
三、 WP_Rewrite::add_rule()
的秘密
让我们来看看 WP_Rewrite::add_rule()
的源码(简化版):
public function add_rule( $regex, $redirect, $priority = 'top' ) {
if ( 'bottom' == $priority ) {
$this->rules[$regex] = $redirect;
} else {
$this->rules = array( $regex => $redirect ) + $this->rules;
}
}
这段代码很简单,但是很重要:
$this->rules
: 这是WP_Rewrite
类的一个属性,它是一个数组,用来存储所有的重写规则。 数组的键是正则表达式,值是替换字符串。if ( 'bottom' == $priority )
: 判断规则的优先级。- 如果
$priority
是'bottom'
,就把新的规则添加到$this->rules
数组的末尾。 - 否则(默认情况下,
$priority
是'top'
),就把新的规则添加到$this->rules
数组的开头。array( $regex => $redirect ) + $this->rules
这种写法,会把新的规则放在数组的最前面。
- 如果
也就是说,WP_Rewrite::add_rule()
只是简单地把你的规则添加到了 $this->rules
数组里。 并没有做任何复杂的处理。 那么,这些规则是怎么生效的呢?
四、 WP_Rewrite::wp_rewrite_rules()
和 WP_Rewrite::generate_rewrite_rules()
关键在于 WP_Rewrite::wp_rewrite_rules()
和 WP_Rewrite::generate_rewrite_rules()
这两个方法。 这两个方法负责把 $this->rules
数组里的规则转换成 Apache 的 .htaccess
文件里的规则(或者 Nginx 的配置规则,或者数据库里的规则)。
WP_Rewrite::wp_rewrite_rules()
方法会调用 WP_Rewrite::generate_rewrite_rules()
方法来生成重写规则。 我们来看看 WP_Rewrite::generate_rewrite_rules()
的简化版:
public function generate_rewrite_rules( $rewritecode = '', $rewritereplace = '' ) {
$rules = array();
foreach ( (array) $this->rules as $match => $query ) {
// 一大堆复杂的逻辑,处理正则表达式,处理 query 参数,等等...
// 最终生成 Apache 的 RewriteRule 和 RewriteCond 规则
$rules[$rewritecode . $match] = $rewritereplace . $query;
}
return $rules;
}
这段代码做了很多事情,包括:
- 遍历
$this->rules
数组,取出每一条规则(正则表达式和替换字符串)。 - 对正则表达式进行处理,比如添加
^
和$
符号,确保正则表达式匹配整个 URL。 - 对替换字符串进行处理,比如把
$matches[1]
替换成实际的参数值。 - 生成 Apache 的
RewriteRule
和RewriteCond
规则。RewriteRule
负责匹配 URL,RewriteCond
负责添加条件。
最终,WP_Rewrite::generate_rewrite_rules()
方法会返回一个数组,这个数组包含了所有的 RewriteRule
和 RewriteCond
规则。
五、 flush_rewrite_rules()
的作用
现在,我们再回到 flush_rewrite_rules()
函数。 这个函数会做以下事情:
- 调用
WP_Rewrite::wp_rewrite_rules()
方法,生成所有的重写规则。 - 把这些重写规则写入
.htaccess
文件(或者更新数据库)。 - 清除 WordPress 的缓存,确保新的规则立即生效。
所以,flush_rewrite_rules()
函数是让你的自定义规则真正生效的关键。 如果你不刷新重写规则,WordPress 就不会知道你的新规则,你的 URL 就不会被正确地重写。
六、 总结
让我们来总结一下 add_rewrite_rule()
的工作流程:
- 你调用
add_rewrite_rule()
函数,添加一条自定义的重写规则。 add_rewrite_rule()
函数把你的规则添加到$wp_rewrite
对象的$this->rules
数组里。- 你调用
flush_rewrite_rules()
函数,刷新重写规则。 flush_rewrite_rules()
函数会:- 调用
WP_Rewrite::wp_rewrite_rules()
方法,生成所有的重写规则。 - 把这些重写规则写入
.htaccess
文件(或者更新数据库)。 - 清除 WordPress 的缓存。
- 调用
- 当用户访问你的网站时,Apache(或者 Nginx)会根据
.htaccess
文件里的规则,对 URL 进行重写。 - WordPress 会根据重写后的 URL,找到对应的页面或文章。
七、一些高级技巧和注意事项
- 正则表达式要写对。 正则表达式是 URL 重写的灵魂。 如果你写错了正则表达式,你的规则就永远不会生效。 可以使用在线正则表达式测试工具来验证你的正则表达式。
- 注意优先级。 如果你的规则和其他规则冲突,可以通过调整优先级来解决。
'top'
表示优先级最高,'bottom'
表示优先级最低。 - 小心缓存。 WordPress 会缓存重写规则,所以有时候即使你刷新了重写规则,新的规则也不会立即生效。 可以尝试清除 WordPress 的缓存,或者禁用缓存插件。
- 不要过度使用重写规则。 过多的重写规则会影响网站的性能。 尽量使用 WordPress 提供的 API 来实现你的需求。
- 了解
.htaccess
文件。.htaccess
文件是 Apache 的配置文件,它控制着网站的很多行为,包括 URL 重写。 了解.htaccess
文件的语法和用法,可以帮助你更好地理解 URL 重写机制。 - Nginx 的配置和 Apache 不同 如果你用的是Nginx,刷新重写规则并不会自动修改Nginx的配置文件。你需要手动修改Nginx配置文件,然后重启Nginx服务。
八、代码示例:更复杂的重写规则
假设你想创建一个自定义的 "书籍" 分类,URL 结构如下:
/books/
: 显示所有书籍。/books/genre/{genre_slug}/
: 显示特定类型的所有书籍。/books/{book_slug}/
: 显示特定书籍的详情。
可以这样实现:
add_action( 'init', 'my_custom_book_rewrite_rules' );
function my_custom_book_rewrite_rules() {
// 1. 显示所有书籍
add_rewrite_rule(
'^books/?$',
'index.php?post_type=book',
'top'
);
// 2. 显示特定类型的所有书籍
add_rewrite_rule(
'^books/genre/([^/]+)/?$',
'index.php?post_type=book&genre=$matches[1]',
'top'
);
// 3. 显示特定书籍的详情
add_rewrite_rule(
'^books/([^/]+)/?$',
'index.php?book=$matches[1]', // 注意这里假设你用的是自定义的 "book" post type 并且 slug 就是 book
'top'
);
flush_rewrite_rules();
}
// 注册自定义查询变量
add_filter( 'query_vars', 'my_custom_book_query_vars' );
function my_custom_book_query_vars( $query_vars ) {
$query_vars[] = 'genre'; // 添加 genre 查询变量
$query_vars[] = 'book'; // 添加 book 查询变量
return $query_vars;
}
// 确保 book post type 注册了
add_action( 'init', 'register_book_post_type' );
function register_book_post_type() {
register_post_type( 'book', array(
'labels' => array(
'name' => __('Books'),
'singular_name' => __('Book')
),
'public' => true,
'has_archive' => true,
'rewrite' => array('slug' => 'books'),
'supports' => array( 'title', 'editor', 'custom-fields' ),
));
//注册自定义分类
register_taxonomy(
'genre',
'book',
array(
'label' => __( 'Genre' ),
'rewrite' => array( 'slug' => 'genre' ),
'hierarchical' => true,
)
);
}
这个例子展示了如何使用 add_rewrite_rule()
创建更复杂的 URL 结构。 关键点:
- 正则表达式要精确。 确保正则表达式能够正确匹配你想要的 URL。
- 添加自定义查询变量。 使用
add_filter( 'query_vars', ... )
添加自定义查询变量,这样 WordPress 才能识别你的 URL 参数。 - 注册自定义文章类型和分类法。 确保你已经注册了自定义文章类型和分类法,这样 WordPress 才能正确处理你的内容。
九、表格总结
函数/方法 | 作用 | 位于哪个文件? | 关键点 |
---|---|---|---|
add_rewrite_rule() |
添加一条自定义的重写规则到 $wp_rewrite 对象。 |
wp-includes/rewrite.php |
只是简单地调用 $wp_rewrite->add_rule() 。 |
WP_Rewrite::add_rule() |
将规则添加到 $this->rules 数组中,根据优先级决定添加的位置。 |
wp-includes/rewrite.php |
$this->rules 是存储所有重写规则的数组。 |
WP_Rewrite::generate_rewrite_rules() |
根据 $this->rules 数组生成 Apache 的 RewriteRule 和 RewriteCond 规则。 |
wp-includes/rewrite.php |
复杂的逻辑,处理正则表达式,处理 query 参数。 |
flush_rewrite_rules() |
刷新重写规则,将生成的规则写入 .htaccess 文件(或更新数据库),并清除缓存。 |
wp-includes/rewrite.php |
让你的自定义规则真正生效的关键。 必须调用! |
add_filter( 'query_vars', ... ) |
添加自定义查询变量,让 WordPress 能够识别 URL 参数。 | functions.php 或插件文件中 |
确保 WordPress 能够识别你的自定义 URL 参数。 |
十、最后的忠告
URL 重写是一个强大的工具,但也是一个容易出错的地方。 在使用 add_rewrite_rule()
时,一定要小心谨慎,多做测试,确保你的规则能够正常工作。 如果你遇到了问题,可以查阅 WordPress 官方文档,或者在 Stack Overflow 上提问。
好了,今天的讲座就到这里。 希望大家能够掌握 add_rewrite_rule()
的用法,创造出更酷、更 SEO 友好的 WordPress 网站! 谢谢大家!
(鞠躬,下台)