The WordPress Rewrite API
WordPress has a really useful API called “the rewrite API“. I guess that have already of “url rewriting”, this is the process that makes URLs more readable. For example a url written like this https://mysite.com/?page=12&category=12&author=47 isn’t that good looking. It’s hard to remember it, and search engines don’t like it that much. That’s why nearly every CMS has a builtin function that “rewrites” urls to make them look like this: https://mysite.com/category/business/finance.
The rewrite API and the WP_Rewrite class
Inside WordPress, this process is also known as the permalinks structure. When you switch from the default permalink structure to a custom structure you automatically activate the rewrite API. This is fully automatic. But sometimes you need to create your own custom rewrite rules.
In this post, we are going to create simple functions to create a simple custom rewrite rule. Let’s says we want to get a referrer value, sort of equivalent to a $_GET[‘referrer’].
If we have a look at the Codex, we can see on the rewrite API page that this API has 6 builtin functions. The most common use of the rewrite is to use these functions, there are plenty of tutorials about that, that’s why i’m going to use filters instead of functions. Because yes, the rewrite API can also be used with filters! Those filters are listed on the WP_Rewrite class Codex page.
Adding a new Query Var
To start, we need to create a function that will tell WordPress that a new rewrite rule is set. This is the job of the add_rewrite_rule() and add_rewrite_tag() functions, but you can also do it using the query_vars and rewrite_rules_array filters. To do so, we need to create two functions and two filters. The first function is going to simply add a new variable to the query_vars filter, and the second one is going to register this new variable into the global rewrite rules:
/*
|--------------------------------------------------------------------------
| Start Rewrite. Sample: http://mysite.com/referrer/remi
|--------------------------------------------------------------------------
*/
// Register a new var
function rc_add_query_vars( $vars) {
$vars[] = "referrer"; // name of the var as seen in the URL
return $vars;
}
// Hook our function into query_vars
add_filter('query_vars', 'rc_add_query_vars');
// Add the new rewrite rule to existings ones
function rc_add_rewrite_rules($rules) {
$new_rules = array('referrer/([^/]+)/?$' => 'index.php?referrer=$matches[1]');
$rules = $new_rules + $rules;
return $rules;
}
// Hook the function into rewrite_rules_array
add_filter('rewrite_rules_array', 'rc_add_rewrite_rules');
Once you add this code to any of your plugin file or your theme functions.php file, got to settings > Permalinks, and save the permalinks structure. This action is needed. You should now be able to access your site with this kind or url: https://mysite.com/referrer/your-name. If you want to be redirected on a specific page, change index.php?referrer=$matches[1] by index.php?pagename=my-page&referrer=$matches[1] where “my-page” is the page to be redirected to slug.
Retrieving the variable value
Now that your rewrite rule is set, you might want to access the variable value. But if you do a simple $_GET[‘referrer’], you won’t get any value. To retrieve the URL vars values, you need to hook a function to the “template_redirect” filter. Hooking to the “init” filter is too early. Then you can access the needed variables through the $wp_query object. Here is a quick sample of how to do it:
// Retrieve URL var
function rc_get_my_vars() {
global $wp_query;
if(isset($wp_query->query_vars['referrer'])) {
$referrer = get_query_var('referrer');
}
}
// Hook the function into template_redirect
add_action( 'template_redirect', 'rc_get_my_vars');
You can next echo the $referrer value or use it as would have done with a normal GET variable.
You can of course modify use more than one variable:
// in rc_add_query_vars()
$vars[] = "referrer";
$vars[] = "campaign";
// in rc_add_rewrite_rules()
$new_rules = array('referrer/([^/]+)/([^/]+)/?$' => 'index.php?pagename=my-page&referrer=$matches[1]&campaign=$matches[2]');
Don’t forget that you need PHP mod_rewrite module enable to use url rewriting.
Nice round up. Are you certain that you can use this in the functions.php file? I seem to recall having trouble doing that. I have only been using this in plugins. The other good thing about using it as a plugin is that you can flush the rewrite rules on activation of the plugin saving you a trip to the permalinks page.
Hi, if you’re using the template_redirect filter yes you can.
Hi Remi,
You write and explain this very well, I got everything I’m looking for, But have a bit issue
I’m using a Custom Post Type (Slug : sfp_forum)
Right Now I got this link structure :
But I need this one :
Hey there Pawan, I was actually looking for the same thing the other day and found a really great method…Check out my gist here – https://gist.github.com/wpexplorer/8244555 – from my testing it seems to work really well!
Hello Remi,
Thanks for the post.
I have followed your tutorial everythings working except i cannot able to get the get_query_var(‘referrer’) value. I copied exact code of yours and pasted in functions.php file but didn’t work, also tried pasting your code in sample plugin but that did not work as well. Please tell me what iam doing wrong?
P,S; I flushed my permalinks each time i made any changes to rewrite rules. And i’m on nginx tried with apache as well 🙁
Hi there,
I’m wondering if is possible to replace your custom post type slug by a taxonomy term slug. For example:
My current URL:
example.com/holiday/remote-brazil
holiday = CPT
remote-brazil = CPT item
I also have a custom taxonomy for that (holiday_category) and custom term (adventures).
My desired URL is:
example.com/adventures/remote-brazil
Any help?
So you want the term to become the slug? To be honest I’m not even sure where to start or if it’s even possible because essentially every post could have a different slug depending on what category it’s in. Im not sure if this post will help (I just did a quick Google Search for you) but it seems like it might be a good starting point – http://wordpress.stackexchange.com/questions/39500/how-to-create-a-permalink-structure-with-custom-taxonomies-and-custom-post-types
Hi,
It’s working but i want to use the page template property.php for the referrer /property/.
How would I achieve this?
Having the .php extension at the end of the URL is very old school and 100% unnecessary. If the reason behind it is because of old URL’s I would recommend just adding a tweak to your .htaccess file that redirects all .php to non .php URLs.
Thanks its great!!!
But I need help for generate the canonical URL in this moment
mySite/post/26156/myNewVar/
I like
mySite/post/theSlug/myNewVar/
any idea??
Thanks 🙂
Sorry not quite sure what you are asking…
Short article but it contains useful information about rewrite API. I used to use init hook for adding rewrite rules and rewrite tags, but now I have learned that I can use two more filters to add rewrite rules and query vars.
Thanks for this precise and nice article.