好吧,各位观众老爷们,今天咱们聊聊 WordPress 里一个有点神秘,但其实挺好玩的功能:add_rewrite_rule()
,也就是自定义 URL 重写规则。这玩意儿就像给你的网站地址做了个整容手术,让它变得更漂亮、更易于理解,而且对 SEO 也很有帮助。
开场白:URL 重写的必要性
想象一下,你开了一家小卖部,如果顾客想买东西,只能通过货架编号来查找,那得多麻烦?URL 重写就相当于给货架贴上了标签,顾客可以直接根据标签找到自己想要的东西。
WordPress 默认的 URL 结构有时候并不友好,比如 /?p=123
这种,鬼知道 123 代表啥?通过 URL 重写,我们可以把它变成 /product/my-awesome-product/
,是不是瞬间高大上了?
第一幕:add_rewrite_rule()
登场
add_rewrite_rule()
函数是 WordPress 提供的一个用于添加自定义重写规则的利器。它的基本语法如下:
add_rewrite_rule( $regex, $redirect, $priority );
$regex
(string): 这是一个正则表达式,用于匹配传入的 URL。$redirect
(string): 这是重定向的目标 URL,也就是匹配到的 URL 应该被转换成什么。$priority
(string, optional): 重写规则的优先级。默认是'bottom'
,意思是放在规则列表的底部。'top'
优先级最高。
第二幕:一个简单的例子:把 go/xxx
重定向到特定页面
假设我们想把所有 go/xxx
形式的 URL 重定向到 /?special_link=xxx
。 我们可以这样写:
add_action( 'init', 'my_custom_rewrite_rule' );
function my_custom_rewrite_rule() {
add_rewrite_rule(
'^go/([^/]*)/?',
'index.php?special_link=$matches[1]',
'top'
);
}
代码解释:
-
add_action( 'init', 'my_custom_rewrite_rule' );
: 这行代码告诉 WordPress,在init
钩子(也就是 WordPress 初始化的时候)执行my_custom_rewrite_rule
函数。 -
*`^go/([^/])/?`**: 这是正则表达式。
^
:表示从字符串的开头开始匹配。go/
:匹配字面字符串 "go/"。([^/]*)
:这是一个捕获组。(...)
:表示一个捕获组,会将匹配到的内容保存起来,方便后面使用。[^/]
:表示匹配除了斜杠/
以外的任何字符。*
:表示匹配零个或多个前面的字符(这里是除了斜杠以外的字符)。- 所以,
([^/]*)
匹配 "go/" 之后的所有字符,直到遇到下一个斜杠为止(或者字符串结束)。
/
:匹配一个斜杠/
。?
:表示前面的斜杠/
是可选的,也就是说,URL 可以以 "go/xxx/" 结尾,也可以以 "go/xxx" 结尾。$
:表示字符串的结尾。
-
index.php?special_link=$matches[1]
: 这是重定向的目标 URL。index.php
:表示 WordPress 的入口文件。?special_link=
:表示一个 URL 参数。$matches[1]
:这是正则表达式中第一个捕获组的内容,也就是go/
后面的字符串。$matches
是一个数组,保存了正则表达式匹配到的所有内容。$matches[0]
保存的是整个匹配到的字符串,$matches[1]
保存的是第一个捕获组的内容,以此类推。
重要提示:别忘了刷新固定链接!
添加或修改重写规则后,一定要去 WordPress 后台的 "设置 -> 固定链接" 页面,点击 "保存更改" 按钮。 这样做会刷新 WordPress 的重写规则,让新的规则生效。 否则,你会发现你的规则根本不起作用。 这就像你贴了新的货架标签,但没告诉顾客,他们还是只能靠货架编号找东西。
第三幕:深入正则表达式的海洋
正则表达式是 URL 重写的灵魂。 掌握了正则表达式,你就能驾驭各种复杂的 URL 结构。 下面是一些常用的正则表达式符号:
符号 | 含义 | 例子 |
---|---|---|
. |
匹配任意单个字符(除了换行符) | a.c 可以匹配 "abc", "acc", "adc" 等 |
* |
匹配前面的字符零次或多次 | ab*c 可以匹配 "ac", "abc", "abbc" 等 |
+ |
匹配前面的字符一次或多次 | ab+c 可以匹配 "abc", "abbc" 等,但不能匹配 "ac" |
? |
匹配前面的字符零次或一次 | ab?c 可以匹配 "ac", "abc" |
[] |
匹配方括号中的任意一个字符 | [abc] 可以匹配 "a", "b", "c" |
[^] |
匹配不在方括号中的任意一个字符 | [^abc] 可以匹配 "d", "e", "f" |
() |
捕获组,用于提取匹配到的内容 | (ab)c 可以匹配 "abc",并将 "ab" 捕获 |
^ |
匹配字符串的开头 | ^abc 只能匹配以 "abc" 开头的字符串 |
$ |
匹配字符串的结尾 | abc$ 只能匹配以 "abc" 结尾的字符串 |
| |
或,匹配 | 前后任意一个表达式 |
a|b 可以匹配 "a" 或 "b" |
d |
匹配一个数字字符 | d+ 可以匹配 "123", "456" |
w |
匹配一个单词字符(字母、数字、下划线) | w+ 可以匹配 "abc", "123", "a_b" |
s |
匹配一个空白字符(空格、制表符、换行符等) | s+ 可以匹配一个或多个空白字符 |
第四幕:一个更复杂的例子:自定义文章类型和分类的 URL
假设我们有一个自定义文章类型 product
和一个自定义分类 product_category
。 我们想让 product
的 URL 结构是 /products/category/product-name/
。
首先,我们需要注册自定义文章类型和分类:
add_action( 'init', 'register_product_post_type' );
function register_product_post_type() {
$args = array(
'public' => true,
'label' => 'Products',
'rewrite' => array( 'slug' => 'products' ), // 基本的 slug
'supports' => array( 'title', 'editor', 'thumbnail', 'custom-fields' ),
'taxonomies' => array( 'product_category' ) // 关联分类
);
register_post_type( 'product', $args );
$category_args = array(
'hierarchical' => true,
'label' => 'Product Categories',
'rewrite' => array( 'slug' => 'products/category' ) // 分类的 slug
);
register_taxonomy( 'product_category', 'product', $category_args );
}
这段代码注册了一个名为 product
的自定义文章类型,并指定了它的 slug 为 products
。 同时,它也注册了一个名为 product_category
的自定义分类,并指定了它的 slug 为 products/category
。
接下来,我们需要添加重写规则来处理 product
的 URL:
add_filter( 'post_type_link', 'product_permalink', 1, 3 );
function product_permalink( $permalink, $post, $leavename ) {
if ( 'product' != $post->post_type ) {
return $permalink;
}
// 获取分类
$terms = get_the_terms( $post->ID, 'product_category' );
if ( ! $terms ) {
return str_replace( '%product_category%', 'uncategorized', $permalink ); // 如果没有分类,使用 uncategorized
}
$category = $terms[0]->slug; // 获取第一个分类的 slug
$permalink = str_replace( '%product_category%', $category, $permalink );
return $permalink;
}
add_filter( 'rewrite_rules_array', 'product_rewrite_rules' );
function product_rewrite_rules( $rules ) {
$new_rules = array();
$new_rules['products/category/(.+?)/([^/]+)/?$'] = 'index.php?product=$matches[2]';
return $new_rules + $rules;
}
add_action( 'init', 'flush_rewrite_rules_on_product_register' );
function flush_rewrite_rules_on_product_register() {
if ( get_option( 'product_rewrite_rules_flushed' ) ) {
return;
}
register_product_post_type(); // 确保文章类型已注册
flush_rewrite_rules();
update_option( 'product_rewrite_rules_flushed', 1 );
}
代码解释:
-
product_permalink
函数: 这个函数用于修改product
的固定链接。它首先检查当前文章是否是product
类型。如果是,则获取文章的第一个product_category
分类的 slug,然后将固定链接中的%product_category%
替换为分类的 slug。 如果文章没有分类,则将%product_category%
替换为uncategorized
。 -
product_rewrite_rules
函数: 这个函数用于添加自定义的重写规则。它添加了一个新的重写规则products/category/(.+?)/([^/]+)/?$
,将匹配到的 URL 重定向到index.php?product=$matches[2]
。-
products/category/(.+?)/([^/]+)/?$
这个正则表达式的含义是:products/category/
: 匹配字面字符串 "products/category/"。(.+?)
: 匹配任意字符(除了换行符)一次或多次,非贪婪模式。 非贪婪模式意味着它会尽可能少地匹配字符。 这个捕获组用于匹配分类的 slug。/
: 匹配一个斜杠/
。([^/]+)
: 匹配除了斜杠/
以外的任意字符一次或多次。 这个捕获组用于匹配文章的 slug。/?
: 匹配一个可选的斜杠/
。$
:匹配字符串的结尾
-
index.php?product=$matches[2]
:将匹配到的 URL 重定向到 WordPress 的入口文件,并设置product
参数为第二个捕获组的内容,也就是文章的 slug。
-
-
flush_rewrite_rules_on_product_register
函数: 这个函数用于在注册product
文章类型后刷新重写规则。 它使用flush_rewrite_rules()
函数来刷新重写规则,并使用update_option()
函数来设置一个选项,防止重复刷新重写规则。 频繁刷新重写规则会影响网站性能,所以只在文章类型注册后刷新一次即可。
重要提示:使用 flush_rewrite_rules()
的注意事项
flush_rewrite_rules()
函数会重新生成 WordPress 的 .htaccess
文件(如果你的服务器使用 Apache),或者更新 Nginx 的配置。 这个操作比较耗时,所以不应该频繁调用。 最好只在插件激活或主题切换时调用一次。 上面的代码使用了一个选项 product_rewrite_rules_flushed
来确保只在 product
文章类型注册后刷新一次重写规则。
第五幕:调试 URL 重写规则
URL 重写规则有时候会让人头疼,因为它们可能与其他规则冲突,或者正则表达式写错了。 下面是一些调试 URL 重写规则的技巧:
-
使用
var_dump()
或print_r()
打印$wp_rewrite->rules
数组:$wp_rewrite->rules
数组包含了 WordPress 所有的重写规则。 你可以使用var_dump()
或print_r()
函数来打印这个数组,查看你的规则是否被正确添加。add_action( 'init', 'debug_rewrite_rules' ); function debug_rewrite_rules() { global $wp_rewrite; echo '<pre>'; print_r( $wp_rewrite->rules ); echo '</pre>'; }
-
使用
rewrite_rules_array
过滤器:rewrite_rules_array
过滤器允许你修改 WordPress 的重写规则。 你可以使用这个过滤器来添加调试信息,例如打印当前的 URL。add_filter( 'rewrite_rules_array', 'debug_rewrite_rules_array' ); function debug_rewrite_rules_array( $rules ) { echo '<pre>'; print_r( $_SERVER['REQUEST_URI'] ); // 打印当前的 URL print_r( $rules ); // 打印所有的重写规则 echo '</pre>'; return $rules; }
-
使用 Query Monitor 插件: Query Monitor 是一个强大的 WordPress 调试插件。 它可以显示当前的查询、模板、钩子、语言文件等信息。 它还可以显示当前的重写规则,以及匹配到的规则。
-
使用在线正则表达式测试工具: 像 regex101.com 这样的工具可以让你测试你的正则表达式,查看它是否能正确匹配你想要匹配的 URL。
第六幕:一些常见的坑
-
重写规则的顺序: WordPress 从上到下依次匹配重写规则。 如果你的规则顺序不对,可能会导致某些规则永远无法被匹配到。 通常情况下,应该把最具体的规则放在最前面,最通用的规则放在最后面。
-
正则表达式的转义: 在正则表达式中,某些字符具有特殊含义,例如
.
、*
、?
等。 如果想匹配这些字符本身,需要使用反斜杠进行转义。 例如,如果想匹配
example.com
,需要写成example.com
。 -
忘记刷新固定链接: 这是最常见的错误。 添加或修改重写规则后,一定要刷新固定链接,否则新的规则不会生效。
-
与其他插件冲突: 某些插件可能会修改 WordPress 的重写规则,导致你的规则无法正常工作。 可以尝试禁用其他插件,看看是否能解决问题。
总结:URL 重写的艺术
add_rewrite_rule()
函数是 WordPress 提供的一个强大工具,可以让你自定义 URL 结构,让你的网站更易于理解和 SEO 友好。 但是,URL 重写也需要谨慎使用,因为它可能会影响网站的性能和稳定性。 掌握了正则表达式和调试技巧,你就能驾驭 URL 重写的艺术,让你的网站焕发新的光彩。
最后的忠告:
不要过度使用 URL 重写。 复杂的 URL 结构可能会让你的网站更难维护。 尽量保持 URL 结构简洁明了。
好了,今天的讲座就到这里。 感谢大家的观看,希望对你们有所帮助! 如果有什么问题,欢迎在评论区留言。