
Changing WordPress URL structures is covered in many places with just the basics, but you don’t really get the behind the scenes. The common tutorials and discussion is on how to create a pretty permalink structure that will increase your site’s SEO. That is changing the default permalink structure from http://www.yoursite.com/?p=1 to http://www.yoursite.com/hello-world. But as you start to develop plugins or even advanced themes, a deeper understanding how WordPress using the URL of any page to display the correct content will allow you to create your own URL structures. This all leads to the WordPress rewrite rules.
This tutorial will focus on creating a class to add rewrite rules to WordPress. We will do this by first going into the basic ideas of the WordPress Query class. Then learning: how to display the rewrite rules that already exist, how to add rules, and how to flush rules.
What You Will Need To Know Before Moving On
- Some idea of Regular Expressions
- The Basics of the WordPress Permalinks
- Object Oriented PHP
WordPress Rewrite Rules Basics and The WordPress Query class
When you visit any page on a WordPress site, there is a process for finding and displaying the content the visitor is requesting. This is done by parsing the URL of the request page and page here is any page on the site i.e. post, page, category and etc. To get a deeper understanding the process, you can read the page Query Overview in the WordPress Codex.
The part we are most interested in is the parsing of the URL. This is done by taking the URL string and trying to find a match from a predesignated array of rules. The predesignated array of rules are set of regular expressions as the keys and the query strings as the values, which will identify the type of content being requested.
The benefits of using this structure is WordPress can quickly identify what content is being request. Other methods could involve pulling data from the database its actually wrong and then going back and forth to the database to find the correct match. The WordPress’ method of using rewrite rules prevents this and essentially saves several database requests before finding the correct content.
The parsing of the URL by WordPress first determines all the conditional tags like is_home(), is_page() and so forth. Then the database query is created. The query is then preformed and the content is finally displayed. That is the whole thing in a nut shell. You will see through this post that we use the $wp_rewrite global in all our class methods. This is the class WordPress uses to parse the URL and create the query string.
Creating Our Rewrite Rules Class
Before we start, we will want a class that is reusable and will give us the ability to pass options directly into our class. That means will have a constructor method that accepts an options array and initialization method that will set options that we pass to the class and assigns them to class variables.
class Refactord_add_rewrite_rules {
var $rules = array(); //an array of the rules will be adding
var $show_rules = FALSE; //use to debug and show rules in the wp_footer hook
function __construct($options = NULL){
if(!is_null($options)){
$this->init($options);
}
}
function init($options){
foreach($options as $key => $value){
$this->$key = $value;
}
}
}
Also, we will be putting all our hooks in the init function. You will see I created to class variables. The first is called $rules and it will contain an array of the rules we want to add. The second is $show_rules, which is a boolean that we will use in the upcoming method.
Lets Just Display the WordPress Rewrite Rules
When you begin adding rewrite rules to WordPress you will be debugging to get your rules right. And unless you display the rules there is no way to even to know if your rule was added or where your error could be. That means that we are going to create a method in our class to display the current rewrite rules at the bottom of the page. We are adding a check in our init function to see if the $display_rules is TRUE and if it is, call the hook and method to display the rules. First here is our new method to display the rules:
function show_rules(){
global $wp_rewrite;
echo "<pre>";
print_r($wp_rewrite->rules);
echo "</pre>";
}
You will see that we first call in the global of $wp_rewrite. It contains the rules stored in the class variable “rules”. This is the preexisting array of rewrite rules.
And here is the new init function:
function init($options){
foreach($options as $key => $value){
$this->$key = $value;
}
if($this->show_rules){
add_action('wp_footer', array(&$this, 'show_rules'), 1);
}
}
If you look at the preexisting rules you will see that it is an array. Its keys are regular expressions with values that are query strings that WordPress will preform. This important to note as we will need to create similar patterns to have our rules work.
Here is a show of the existing rules on my localhost:

Flushing Rules
To add your own rules you must first flush the rewrite rules. The rewrite rules are stored in the option database and are not regenerated unless told to. If you try to add rules without flushing the existing rules, the rules will not be added. There are two methods of having the rewrite rules regenerated. The first is the click the save but in the permalink settings in the admin. The other method is to request the rules to be regenerate manually in our class.
Flushing the rewrite rules is something that is not recommend to do unless necessary. It creates a drain and will slow down WordPress. You should only flush rules if needed as in the case of adding new rules. If you are not adding new rules or taking rules away, you shouldn’t be flushing the rules.
That means we will need two new methods in our class. The first is to test to see if our added rules already exists. This method will return TRUE or FALSE if the rules we are adding already exist. The next method will flush the rules.
The first method is called rules_exist() and takes the rules we are adding, which are in the form of an array. And tests each of the keys and or values against the existing key and values. If it finds that neither the key or value in the array of existing rules then it returns FALSE meaning the rules must be flushed.
function rules_exist(){
global $wp_rewrite;
foreach($this->rules as $key => $rule){
if(!in_array($rule, $wp_rewrite->rules) || !key_exists($key, $wp_rewrite->rules)){
return FALSE;
}
}
return TRUE;
}
Again we call in the global for the $wp_rewrite class and use that to get the current rules that exist.
The other method is just a couple lines. First calling the $wp_rewrite global and then if the rules don’t exist rules (found by calling the previous method), lets flushed the rules.
function flush_rules(){
global $wp_rewrite;
if(!$this->rules_exist()){
$wp_rewrite->flush_rules();
}
}
With that done we have completed methods to flush and to test if rules exist. We can then go back to our init method and edit it. Here is the complete init function:
function init($options){
foreach($options as $key => $value){
$this->$key = $value;
}
if(!empty($this->rules)){
add_action('wp_head', array(&$this, 'flush_rules'));
}
if($this->show_rules){
add_action('wp_footer', array(&$this, 'show_rules'), 1);
}
}
You see that we don’t call the functions to flush rules if we aren’t even trying to add any rules (represent by testing to see if the class variable $rules is empty).
Finally Adding the rules
The adding of the rules is simple enough and here is our method:
function add_rules(){
global $wp_rewrite;
$wp_rewrite->rules = $this->rules + $wp_rewrite->rules;
}
It simply takes our rules and the preexisting rules, merges them, and sets the new $wp_write class variable rules equal to this new combo. The last thing to do is to add this method to a hook and we will again to it in the init function. Here is the init function again:
function init($options){
foreach($options as $key => $value){
$this->$key = $value;
}
if(!empty($this->rules)){
add_action('wp_head', array(&$this, 'flush_rules'));
add_action('generate_rewrite_rules', array(&$this, 'add_rules'));
}
if($this->show_rules){
add_action('wp_footer', array(&$this, 'show_rules'), 1);
}
}
We just added the action hook call on ‘generate_rewrite_rules’. We again only call this if the rules don’t already exist.
Advanced Notes
I tried to incorporate the rules_exist method in the init method; adding to the line where we see if the rules we want to add are not empty. But what I found that in the process is WordPress has not yet got the rules in stored in the $wp_rewrite->rules, so it comes back NULL. You need to incorporate the rules_exist method directly in the flushing method to make it work.
Finally adding rules
To finish I am going to leave you with a call I used to create a plugin that display authors and categories together on the same page. The URL structure I wanted to create was:
http://www.yoursite.com/author/author-slug/category/category-slug/
Here is the rules that I created and called into the class.
$options = array(
'rules' => array(
'category/([^/]+)/author/([^/]+)/?$' => 'index.php?category_name=$matches[1]&author_name=$matches[2]',
'category/([^/]+)/author/([^/]+)/page/?([0-9]{1,})/?$' => 'index.php?category_name=$matches[1]&author_name=$matches[2]&paged=$matches[3]',
'author/([^/]+)/category/([^/]+)/?$' => 'index.php?author_name=$matches[1]&category_name=$matches[2]',
'author/([^/]+)/category/([^/]+)/page/?([0-9]{1,})/?$' => 'index.php?author_name=$matches[1]&category_name=$matches[2]&paged=$matches[3]'
),
);
$add_rewrite_rules = new Refactord_add_rewrite_rules($options);
If you notice that key to our rules array is a regular expression with the value of the query string WordPress will preform. You should know that the matches in the query string are the regular expressions in the parenthesis. Looking at the third rule I created, the first match is ([^/]+) expression after category/ and the second match is ([^/]+) after /author/. These matches get replaced in the query string.
Knowing this and using the URL structure from above of http://www.yoursite.com/author/author-slug/category/category-slug/; the query string would become index.php?category_name=category-slug&author_name=author-slug. This will work check it out.
2 Responses to “Adding Rewrite Rules to WordPress”
Tahir Yasin • June 13th, 2011 at 10:24 pm
Plz guide me how can I use this class to write a rule to work with my following URL
http://www.mysite.com/news/newstitle
I am using separate plugin for news management.
Thank you.
Kyle G • June 14th, 2011 at 8:39 pm
To just look at what you are trying to create it seems that adding a custom post type would be better. This would create the same idea and would add the permalink structure you are looking for.