add_rewrite_rule()
Adds a new URL rewrite rule (pretty permalink) to the WordPress rules structure.
If a new query parameter is added to the pretty permalink rule, in order to retrieve it using get_query_var(), this new parameter must be whitelisted using the function add_rewrite_tag(), which "tells" WordPress that new query parameters have appeared. WP has a whitelist of query parameters to prevent users from adding any variables to the parameters simply by writing them in the URL.
Alternatively, you can use the query_vars filter. Unlike add_rewrite_tag(), in this case, rewrite tags are not added to the global object $wp_rewrite:
add_filter( 'query_vars', function( $vars ){
$vars[] = 'my_var';
return $vars;
} );
The function should be called during or before the init event.
When adding multiple rules, note that (starting from version 4.9.8) rules are applied in the order they are added, regardless of whether they are at the top or bottom. For example:
add_rewrite_rule( '^book/(.*)', 'index.php?pagename=foo&book=$matches[1]', 'top' ); add_rewrite_rule( '^book/mammals/(.*)', 'index.php?pagename=foo&bookmam=$matches[1]', 'top' );
The second rule will never trigger because the first rule will always trigger before the second is processed.
See the list of occupied names for query variables.
Rewrite Rules Inspector — a small plugin for viewing all existing pretty permalink rules.
No Hooks.
Returns
null. Does not return anything.
Usage
add_rewrite_rule( $regex, $query, $after );
- $regex(string) (required)
- A regular expression that the link (URL) must match. You can use one or more groups (
()) in the regex. - $query(string/array) (required)
- The query parameters corresponding to the regex. You can use the array
$matches[]to get the values of the regex groups.
Supported as an array since version 4.4. - $after(string)
- Priority of the check. Can be
topandbottom. top means this rule will be checked first.
Default: 'bottom'
Examples
#1 User-friendly URLs for pages
We create a "nutrition" page (nutrition, ID=12) to display various nutrition information on it. Then, this page uses a separate template. The request variables food and variety are passed to the page.
Let's replace the ugly URL: /nutrition?food=mush&variety=semolina with the pretty ones: /nutrition/mush/semolina
add_action( 'init', 'do_rewrite' );
function do_rewrite(){
add_rewrite_rule( '^(nutrition)/([^/]*)/([^/]*)/?', 'index.php?pagename=$matches[1]&food=$matches[2]&variety=$matches[3]', 'top' );
// you need to specify ?p=123 if such a rule is created for post 123
// the first parameter for posts: p or name, for pages: page_id or pagename
// tell WP that there are new query parameters
add_filter( 'query_vars', function( $vars ){
$vars[] = 'food';
$vars[] = 'variety';
return $vars;
} );
}
When using $matches[], the array keys start with 1, not 0.
Now you need to update the rewrite rules, to do this, just visit the Settings > Permalinks page - the rules will update in the WP options.
You can get the parameters in the page code through the get_query_var() function. For example, link: /nutrition/mush/semolina
echo get_query_var('food'); // mush
echo get_query_var('variety'); // semolina
By default, WordPress does not recognize new query variables used for rewrite. You need to register them with add_rewrite_tag() or through the filter query_vars, if not done, the rewrite rule will not work.
To make a rule work, you must update (reset) the rules in the database. To do this, call function flush_rules(). Or just go to Settings -> Permalinks where flush_rules() will automatically triggered.
#2 Friendly URL for the page (example 2)
Another example of creating an Friendly URL for a static page. First the code:
// rewrite rule for the sitemap page
add_action( 'init', 'rewrite_rule_my' );
function rewrite_rule_my(){
add_rewrite_rule( '^(sitemap)/([^/]*)/?', 'index.php?pagename=$matches[1]&pagetype=$matches[2]', 'top' );
add_rewrite_tag( '%pagetype%', '([^&]+)' );
}
Here we created the Friendly URL for the permanent page /sitemap?pagename=value (pagename is a query variable). After placing this code in theme functions.php, the Friendly URL of the following form will start working: /sitemap/value and in PHP on this page, you can use the variable $wp_query->query_vars['pagetype'], which will contain the value value. Or you can get the value like this: get_query_var('pagetype').
#3 Friendly URL for a child page
In the parameter pagename we need to pass the whole link, not just the page slug. Suppose the URL of our child page is /parent/slug, then:
add_rewrite_rule( '^(parent/slug)/([^/]*)', 'index.php?pagename=$matches[1]&foo=$matches[2]', 'top' );
That is, in the regular expression you should write (parent/slug) instead of parent/(slug).
WP will now begin to understand URLs of the form /parent/slug/value, where value will be available through get_query_var('foo').
#4 Redirect to scripts other than index.php
Using rewrite rules to redirect to scripts other than index.php.
The $redirect argument works differently when redirecting to a non index.php PHP script. In this case, WordPress passes these redirects to .htaccess instead of handling them itself.
For this reason, variables should be written as $1 instead of $matches[1].
add_action( 'init', 'custom_rewrite_rule', 10, 0 );
function custom_rewrite_rule() {
add_rewrite_rule( 'nutrition/([^/]*)/([^/]*)/?', 'path/to/script.php?food=&variety=', 'top' );
}
When adding such a rule -- see WP_Rewrite::add_rule() -- WP checks if there is a index.php file in the $redirect parameter -- see property WP_Rewrite::$index -- if it is not there, control is given to WP_Rewrite::add_external_rule() method.
It adds the rewrite rule to a separate non_wp_rules array: see WP_Rewrite::$non_wp_rules. Later data from this array will go directly to .htaccess.
That is, after installing the code above and updating rewrite rules, you will have a new rule (line 7) in .htaccess:
# BEGIN WordPress
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]
RewriteBase /
RewriteRule ^index\.php$ - [L]
RewriteRule ^nutrition/([^/]*)/([^/]*)/? /path/to/script.php?food=&variety= [QSA,L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.php [L]
</IfModule>
# END WordPressAnother example: Friendly login link
This is just an example with no practical use. WordPress since version 3.0 automatically redirects to /wp-login.php if we try to go to /login.
If we type http://example.com/login into the browser line, we open the login page http://example.com/wp-login.php (the URL will not change - there will be no redirect):
// Let's make http://site.com/login count as a request for http://site.com/wp-login.php
add_action( 'init', 'wp_pretty_login' );
function wp_pretty_login() {
add_rewrite_rule( 'login$', 'wp-login.php', 'top' );
}
Get in .htaccess:
# BEGIN WordPress
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]
RewriteBase /
RewriteRule ^index\.php$ - [L]
RewriteRule ^login$ /wp-login.php [QSA,L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.php [L]
</IfModule>
# END WordPress #5 How to register a new rewrite rule
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_action( 'template_include', function( $template ) {
if ( get_query_var( 'myparamname' ) ) {
return get_template_directory() . '/template-name.php';
}
return $template;
} );
Notes
- Global. WP_Rewrite.
$wp_rewriteWordPress rewrite component.
Changelog
| Since 2.1.0 | Introduced. |
| Since 4.4.0 | Array support was added to the $query parameter. |
add_rewrite_rule() add rewrite rule code WP 7.0
function add_rewrite_rule( $regex, $query, $after = 'bottom' ) {
global $wp_rewrite;
$wp_rewrite->add_rule( $regex, $query, $after );
}