add_rewrite_rule()
云策文档标注
概述
add_rewrite_rule() 是 WordPress 中用于添加自定义重写规则的函数,它将 URL 结构转换为查询变量。通常与 add_rewrite_tag() 结合使用,以支持自定义查询参数。
关键要点
- 函数参数:$regex(正则表达式,必需)、$query(查询字符串或数组,必需)、$after(优先级,可选,默认为 'bottom',非 'bottom' 值将规则置于顶部)
- 使用场景:常用于创建自定义 URL 规则,如将 /nutrition/milkshake/strawberry/ 映射到 index.php?page_id=12&food=milkshake&variety=strawberry
- 注意事项:添加规则后必须刷新固定链接(在设置 > 固定链接中保存),否则规则不会生效;规则按添加顺序应用,需注意优先级冲突
- 版本变化:从 4.4.0 开始,$query 参数支持数组类型
代码示例
add_action( 'init', function() {
add_rewrite_rule( 'myparamname/([a-z0-9-]+)[/]?$', 'index.php?myparamname=$matches[1]', 'top' );
} );
add_filter( 'query_vars', function( $query_vars ) {
$query_vars[] = 'myparamname';
return $query_vars;
} );
add_filter( 'template_include', function( $template ) {
if ( get_query_var( 'myparamname' ) == false || get_query_var( 'myparamname' ) == '' ) {
return $template;
}
return get_template_directory() . '/template-name.php';
} );注意事项
- 使用 $matches[] 时,捕获组索引从 1 开始,而非 0
- 规则添加代码必须在后台(如固定链接设置页面)可用,否则可能无法注册
- 对于非英语字符的 post_name,建议使用 rawurldecode() 处理以避免 404 错误
- 当重定向到自定义 PHP 脚本(非 index.php)时,查询变量应使用 $1 而非 $matches[1]
原文内容
Adds a rewrite rule that transforms a URL structure to a set of query vars.
Description
Any value in the $after parameter that isn’t ‘bottom’ will result in the rule being placed at the top of the rewrite rules.
Parameters
$regexstringrequired-
Regular expression to match request against.
$querystring|arrayrequired-
The corresponding query vars for this rewrite rule.
$afterstringoptional-
Priority of the new rule. Accepts
'top'or'bottom'. Default'bottom'.
Source
function add_rewrite_rule( $regex, $query, $after = 'bottom' ) {
global $wp_rewrite;
$wp_rewrite->add_rule( $regex, $query, $after );
}
Skip to note 12 content
Anthony Eden
Here is a simple example of how to register a new rewrite rule, and pass it off to a PHP file for rendering:
1. Setup a rule:
add_action( 'init', function() { add_rewrite_rule( 'myparamname/([a-z0-9-]+)[/]?$', 'index.php?myparamname=$matches[1]', 'top' ); } );2. Flush permalinks. Go to WP Admin > Settings > Permalinks > Save. This doesn’t happen automatically after you add this code
3. Whitelist the query param:
add_filter( 'query_vars', function( $query_vars ) { $query_vars[] = 'myparamname'; return $query_vars; } );4. Add a handler to send it off to a template file:
add_filter( 'template_include', function( $template ) { if ( get_query_var( 'myparamname' ) == false || get_query_var( 'myparamname' ) == '' ) { return $template; } return get_template_directory() . '/template-name.php'; } );add_action( ‘template_include’, function( $template ) { if ( get_query_var( ‘myparamname’ ) == false || get_query_var( ‘myparamname’ ) == ” ) { return $template; } if ( is_404() ) { status_header( 404 ); get_template_part( 404 ); exit(); } return get_template_directory() . ‘/template-name.php’; } );
index.php?myparamname=$matches[1]toindex.php?myparamname=$1, otherwise it was not working properly.Skip to note 13 content
tomasdev
Things that were in WP Codex site and did not get migrated for whatever reason.
NOTE: When using $matches[] to retrieve the values of a matched URL, capture group data starts at 1, not 0.
IMPORTANT: Do not forget to flush and regenerate the rewrite rules database after modifying rules. From WordPress Administration Screens, Select Settings -> Permalinks and just click Save Changes without any changes.
add_rewrite_rule('^animals/(.*)', 'index.php?pagename=display-animal&animal=matches[1]', 'top'); add_rewrite_rule('^animals/mammals/(.*)', 'index.php?pagename=display-mammal&mammal-name=matches[1]', 'top');The second rule will never match, because the first rule always matches before the second one is processed.
Skip to note 14 content
Ismail
A quick example: processing rules to make a subscribers page, hoping it helps.
add_action('init', function() { $page_id = 2; // update 2 (sample page) to your custom page ID where you can get the subscriber(s) data later $page_data = get_post( $page_id ); if( ! is_object($page_data) ) { // post not there return; } add_rewrite_rule( $page_data->post_name . '/subscriber/([^/]+)/?$', 'index.php?pagename=' . $page_data->post_name . '&my;_subscribers=1&my;_subscriber=$matches[1]', 'top' ); });Now in your page template ( if you have one, or while filtering this custom page’s content ), you can get the displayed subscriber slug by calling
get_query_var('my_subscriber'), but first, pass'my_subscriber'to the query variables:add_filter('query_vars', function($vars) { $vars[] = "my_subscriber"; return $vars; });->post_namecolumn. I recommend that anyone who will try to use the code above, make sure to wrappost_namewithrawurldecode()insideregexargument. For example:add_rewrite_rule(rawurldecode($page_data->post_name), 'bla', 'top');. In many case if yourpost_nameor known as URL slug is in English using pattern withoutrawurldecode()works fine. But whenever yourpost_nameis in some other language like Thai, the character ค will be %E0%B8%84 when user type from address bar but inside WordPress DB it is %e0%b8%84. It is different case, yes! but that may lead you to 404 page while you are still confuse that all the characters you type is correct. Wrappost_namewithrawurldecode()will be fine and works well.Skip to note 15 content
Akira Tachibana
(From Codex)
Using Custom Templates with custom querystring
Let’s assume you are creating a “Nutrition” page for showing nutritional information. This page uses a custom template and takes two variables, food and variety. Create a file named my-custom-template.php in your themes root directory as following:
/** * Template Name: Nutritional Information */ get_header(); global $wp_query; echo 'Food : ' . $wp_query->query_vars['food']; echo '<br />'; echo 'Variety : ' . $wp_query->query_vars['variety']; // ... more ... get_footer();Using this template, create a page. In Add New of Pages screen, select “Nutritional Information” from Template dropdown box. You may leave blank for title or contents. Click Publish to publish the page. Write down the ID of created page from All Pages screen. Move a mouse cursor on the page title to show the link information in status bar of Web browser. You will see the ID after the POST= in URL. In this example, assume the ID is 12.
Use add_rewrite_tag() to make WordPress aware of custom querystring variables food and variety. Add the following code to the functions.php file,
function custom_rewrite_tag() { add_rewrite_tag('%food%', '([^&]+)'); add_rewrite_tag('%variety%', '([^&]+)'); } add_action('init', 'custom_rewrite_tag', 10, 0);You can call the page as following:
http://example.com/index.php?page_id=12&food;=milkshake&variety;=strawberry
The page will show two values passed by querystring variables.
Now, instead of passing ugly querystring variables to the page, you can set up a rewrite rule to create some custom pretty URLs. Add the following rule to the functions.php file and replace the page ID 12 by the ID that you investigated in above step. Don’t forget to click Save Changes in Permalinks Settings. (refer above IMPORTANT)
function custom_rewrite_rule() { add_rewrite_rule('^nutrition/([^/]*)/([^/]*)/?','index.php?page_id=12&food;=$matches[1]&variety;=$matches[2]','top'); } add_action('init', 'custom_rewrite_rule', 10, 0);User can access the same page with following URL:
http://example.com/nutrition/milkshakes/strawberry/
Skip to note 16 content
iqbalbary
Example to add rewrite rule query as optional,hope it helps.
function custom_rewrite_rule() { add_rewrite_rule('^nutrition/?([^/]*)/?','index.php?page_id=12&food;=$matches[1]','top'); } add_action('init', 'custom_rewrite_rule', 10, 0);The main things here is to add ? in the start of your regex. Like
?([^/]*)Now, you can set default value for optional query where you will use the query.
$food = $wp_query->get( 'food' ); if( isset($food) && !empty($food) ) { $nutrition = $food; }else{ $nutrition = 'strawberry'; //default value }Now you will get the same result for
http://example.com/nutrition/strawberryorhttp://example.com/nutrition/Skip to note 17 content
Akira Tachibana
(From Codex)
Using rewrite rules to redirect to scripts other than index.php
The $redirect argument works slightly differently when redirecting to a custom PHP script because WordPress delegates these redirects to .htaccess instead of processing them itself. For this reason, querystring variables should be written like $1 instead of $matches[1]. Given we’re redirecting to a custom PHP script, adding the same rewrite rule from our previous example would look like this:
function custom_rewrite_rule() { add_rewrite_rule('^nutrition/([^/]*)/([^/]*)/?','url/to/my/script.php?food=$1&variety;=$2','top'); } add_action('init', 'custom_rewrite_rule', 10, 0);Skip to note 18 content
Md Aminur Islam
Rewrite rules with optional parameters.
// siteurl.com/wpdocs-product-category/edit-product-category/43 for edit product category add_rewrite_rule( '^wpdocs-product-category/([^/]*)/([^/]*)/?', 'index.php?pagename=wpdocs-product-category&wpdocs-pro-category-action;=$matches[1]&wpdocs-product-cat-id;=$matches[2]', 'top' ); // Product Category Add Page // siteurl.com/wpdocs-product-category/add-product-category for add product category add_rewrite_rule( '^wpdocs-product-category/([^/]*)/?', 'index.php?pagename=wpdocs-product-category&wpdocs-pro-category-action;=$matches[1]', 'top' );Filters the query variables allowed before processing.
add_filter( 'query_vars', function( $vars ) { $vars[] = 'wpdocs-pro-category-action'; $vars[] = 'wpdocs-product-cat-id'; $vars[] = 'wpdocs-category-action'; return $vars; } );Retrieve query parameters values
$pro_category_action = get_query_var( 'wpdocs-pro-category-action' ); $product_cat_id = get_query_var( 'wpdocs-product-cat-id' );Skip to note 19 content
Akira Tachibana
(From Codex)
Basic Usage
You can retrieve any page by specifying ID in URL as following:
http://example.com/?p=95
If you add the following rule to the functions.php file, you can provide custom formed URL to access.
function custom_rewrite_basic() { add_rewrite_rule('^leaf/([0-9]+)/?', 'index.php?page_id=$matches[1]', 'top'); } add_action('init', 'custom_rewrite_basic');NOTE: When using $matches[] to retrieve the values of a matched URL, capture group data starts at 1, not 0.
IMPORTANT: Do not forget to flush and regenerate the rewrite rules database after modifying rules. From WordPress Administration Screens, Select Settings -> Permalinks and just click Save Changes without any changes.
Now, you can access the same page as
http://example.com/leaf/95
Skip to note 20 content
Andre Gagnon
If you are distributing this in a plugin or theme, you may want to build in flushing rewrite rules. You can actually check to see if it has been set before you
flush_rewrite_rules();using therewrite_rulesoption.This option is autoloaded, so there is no extra database call.
Here’s a snippet:
add_action( 'init', function() { // get registered rewrite rules. $rules = get_option( 'rewrite_rules', array() ); // set the regex. $regex = 'wpdocsparam/([a-z0-9-]+)[/]?$'; // add the rewrite rule. add_rewrite_rule( $regex, 'index.php?wpdocsparam=$matches[1]', 'top' ); // maybe flush rewrite rules if it was not previously in the option. if ( ! isset( $rules[ $regex ] ) ) { flush_rewrite_rules(); } } );Skip to note 21 content
Pektsekye
IMPORTANT NOTE:
Your code with the add_rewrite_rule() function should be available for the (Settings / Permalinks) back-end page.
I have spend much time to find out why my rewrite rule is not registered.
The problem was that my code with the add_rewrite_rule() was available only for the front-end pages. So it could not be executed when I tried to flush the permalink settings in the back-end.
Skip to note 22 content
Khoi Pro
If you need to keep custom taxonomy and post type using same slug, there is a way to use add_rewrite_rule for doing that. A simple case:
Example:
function wpdocs_add_course_category_rewrites() { $rules = array(); $tax = 'course_category'; $post_type = 'course'; $terms = get_terms( array( 'taxonomy' => $tax, 'hide_empty' => false, ) ); foreach ( $terms as $term ) { add_rewrite_rule( '^course/(' . $term->slug . ')[/]?$', 'index.php?post_type=' . $post_type . '&' . $tax . '=$matches[1]', 'top' ); } } add_action( 'init', 'wpdocs_add_course_category_rewrites' );Remember to flush permalinks (Settings / Permalinks) once to apply changes.