The Rewrite API for WordPress is one of the most overlooked features, yet it provides some unparalleled functionality that drastically improves user experience. This tutorial aims to help you understand how the WordPress URL Rewrite engine works and the different uses of this API.

Why use the Rewrite API? An Introduction to Smart Permalinks

That should be the first question. If you have installed previously and worked with WordPress on an Apache server, you have probably used the Rewrite API even though you didn’t have to deal with it directly.

By default, when WordPress is installed, all blog posts and pages URLs are written in this format

http://example.com/index.php?p=1

http://example.com/index.php?p=5&category=7&product=15

This is the URL for the first blog post on your freshly installed blog. This is the default way WordPress handles URLs and it works pretty much without any problems. There are a few issues with this format, though.

It’s barely readable. For the average Internet user, it looks cryptographic. It’s not SEO-friendly. Hardly memorable, and sometimes the URL is quite long for sharing.

Enough reasons to improve our URL format. Here is the right way of doing it:

http://example.com/first-blog-post

http://example.com/computers/laptops/hp

This format is a lot better. It’s more readable, SEO friendly, and short. If you don’t know about URL rewriting, it’s fair to ask how this can work. The path for the computers/laptops/hp does not actually exist on the server. This is why we call it URL rewriting; when the URL doesn’t exist as a physical path, we redirect it to another location but without changing the URL in the address bar. But how the URL is being rewritten in WordPress?

The .htaccess file

If you have setup WordPress on an Apache server with the mod_rewrite module, it’ll work out of the box for you. Check the .htaccess file on the WordPress install root directory and open it. You should find this.

< IfModule mod_rewrite.c > RewriteEngine On RewriteBase / RewriteRule ^index\.php$ - [L] RewriteCond %{REQUEST_FILENAME} !-f RewriteCond %{REQUEST_FILENAME} !-d RewriteRule . /index.php [L] < /IfModule >

Looks terrible, right? It’s not actually hard to understand. The file will apply a simple rule. It’ll redirect any URL request to index.php, but only if two conditions are valid: When the requested file name is either invalid or doesn’t exist. The conditions will prevent the redirection of valid URL, like an image URL.

For example, http://example.com/my-blog-post will be redirected to http://example.com/index.php; whereas http://example.com/image.png will still give the actual image file. It’s worth mentioning again that this is not a true redirect. The address bar will still display the the smart link. Wikipedia page has a concise article about URL rewriting.

WordPress permalinks settings

Enabling URL rewriting for WordPress is pretty straightforward, assuming you’d setup the redirection correctly (it’s done for you on Apache, just make sure you have the mod_rewrite module installed).

The Settings > Permalinks page is where you change the settings for URLs. I’m using a custom structure which renders URLs as http://example.com/post_name

This is good so far, but pretty limited. What if you want to shorten a blog post URL to make it even easier for sharing? The real blog post URL is http://example.com/2012_free_wordpress_plugins and you want to make it http://example.com/freemium to make sharing and remembering the URL easier.

The settings panel is limited, but WordPress is not. The rewrite API is open, and you can play with it and customize it. First, I’ll explain how the rewrite API actually works, and then I’ll show off an example. Don’t jump the rewrite API basics; it’s necessary to expand your knowledge beyond the trivial example.

How the Rewrite API works?

If you have tried messing up with the rewrite API before this tutorial, you might think it’s a complicated and sophisticated mechanism that WordPress runs. It’s not. It’s actually pretty simple.

You request a URL. (like http://example.com/blog-post) If the resource exists (like an image or a font), the resource is returned. If the resource doesn’t exist, the request is redirected to index.php. WordPress displays the page accordingly.

It’s that simple. Now you might think that if WordPress displayed the page correctly, it has some schema that defines every URL and the end point or the results to display. It certainly doesn’t guess which page it will be.

Where WordPress hides this schema?

You are certainly curious to see how this schema looks. Okay, I have put down this bit of code. It’s a small WordPress plug-in that will print the schema object (from now on, we’ll be calling it $wp_rewrite). Create a new file, put this bit of code in it, save it in your plugins directory and load your WordPress blog (any page)

1 2 3 4 5 6 7 8 9 10 11 12 <?php /* Plugin Name: URL Rewrite Description: Testing the WordPress Rewrite API Author: Abid Omar */ add_action ( 'template_redirect' , 'ao_dump_rewrite' ) ; function ao_dump_rewrite ( ) { global $wp_rewrite ; var_dump ( $wp_rewrite ) ; } ?> <?php /* Plugin Name: URL Rewrite Description: Testing the WordPress Rewrite API Author: Abid Omar */ add_action('template_redirect', 'ao_dump_rewrite'); function ao_dump_rewrite() { global $wp_rewrite; var_dump($wp_rewrite); } ?>

The $wp_rewrite object

Depending on your WordPress blog configuration (and what plug-ins, custom taxonomies and other things you setup there), your $wp_rewrite object will vary in size. But if you look carefully (and you have x_debug which will beautify this bunch of text), the object structure is the following:

WP_Rewrite Object ( public 'permalink_structure' => string '/%postname%/' (length=12) public 'use_trailing_slashes' => boolean true public 'author_base' => string 'author' (length=6)... [rules] = > Array ( [category/(.+?)/?$] = > index.php?category_name=$matches[1] [tag/([^/]+)/page/?([0-9]{1,})/?$] = > index.php?tag=$matches[1] & paged=$matches[2] [tag/([^/]+)/?$] = > index.php?tag=$matches[1] [(.+?)/trackback/?$] = > index.php?pagename=$matches[1] & tb=1 ... ) [rewritecode] = > Array () ... )

That was, certainly, a small part of my $wp_rewrite object. I wanted to emphasize on this snippet the rules array. This is actually the real schema. It’s like a map. It links every URL structure to, well, another URL structure. Do you remember what our URLs looked like before changing them from the permalinks panel?

http://example.com/index.php?p=1

That’s actually how WordPress loads every page: by reading the URL parameters. Now that we changed our URL structure to something smarter like:

http://example.com/blog_post

It looks like the old format was removed and WordPress is using a new one. It’s actually not true. WordPress is always using the same old-fashioned structure, but now it has a map between the smart URLs and the old URLs. It uses the map to link between them.

So for http://example.com/blog_post WordPress will actually call http://example.com/index.php?p=1 and will use the $wp_rewrite object to figure out the destination URL. Let’s take a look at how one rewrite rule looks.

'page/?([0-9]{1,})/?$' => string 'index.php?&paged=$matches[1]' (length=28)

The array key is our smart URL or how it should look like. It is obvious here that it’s a regular expression. The matched pattern is ‘page/{{some_digit}}’, and the end point is ‘index.php?&paged={{some_digit}}’.

This means that WordPress will match any http://example.com/page/2 (or any other number instead of 2) and redirects it to http://example.com/index.php?&paged=2

Shortening a blog post URL

Now we are going to put this knowledge into some real life stuff. The application is pretty simple and straightforward. We are going to shorten a long blog post URL to a tiny one. One may wonders why go this route since we can simply do it in the WordPress edit blog post page. Well, there are a couple of reasons for that.

First, this is aimed to teach how to work with the Rewrite API and to start with something simple. Second, this can be applied to pretty much any URL in WordPress, not just a blog post URL.

So let’s start. First, create a blog post with the name “2012 Free WordPress Plugins“. If you have the permalink structure set to %postname%, your URL will look something like this: http://example.com/2012-free-wordpress-plugins/

Not bad, but you are looking to share this on viral networking sites like Twitter. You don’t want your URL to be too long because these sites put restrictions on how much characters you can use. You want it to be http://example.com/freemium

Do you still remember the rules array in the $wp_rewrite object? That one magical map that WordPress uses to relay between smart URLs and classic URLs. If we hack this schema, we can probably get WordPress to redirect our http://example.com/freemium to the desired blog post. Fine. How to start then?

Define your target. The target is the array key. It’s the Smart URL format. We said earlier that it’s a regular expression format. Regex are easy to use but don’t worry we are not going to use them since our pattern is easy. Our pattern is ‘freemium’. That’s what we want to match. Define your destination. Your destination is the blog post. But that destination should be written in the old classic URL format. That is ‘index.php?p=post_number’. To find the post number, click the “Get Shortlink” button when editing your post. If you don’t find that button, revert to the old permalink style and you’ll find the post number.

That’s it. Now, let’s edit the $wp_rewrite object. Remember our old plug-in? Well, replace the PHP code with the following

1 2 3 4 5 6 7 8 9 10 11 12 13 <?php /* Plugin Name: URL Rewrite Description: Testing the WordPress Rewrite API Author: Abid Omar */ add_action ( 'init' , 'ao_add_rewrite_rule' ) ; function ao_add_rewrite_rule ( ) { add_rewrite_rule ( 'freemium' , 'index.php?&p=15' , 'top' ) ; flush_rewrite_rules ( ) ; } ?> <?php /* Plugin Name: URL Rewrite Description: Testing the WordPress Rewrite API Author: Abid Omar */ add_action( 'init', 'ao_add_rewrite_rule'); function ao_add_rewrite_rule() { add_rewrite_rule( 'freemium', 'index.php?&p=15', 'top'); flush_rewrite_rules(); } ?>

Who said it is hard? You may wonder about a couple things

The add_rewrite_rule() function will add a new rule to the $wp_rewrite object. The flush_rewrite_rules() function will order WordPress to rebuild the $wp_rewrite object. This is required since we changed our object. It’s a bad practice, however, to call this function everytime the page is loaded since it’s an unnecessary overhead. Place this function on the activation and deactivation actions of your plug-in to make it execute only once. I have used the init hook only for demonstrative purposes.

You can use the first snippet of code to print your $wp_rewrite object. You’ will find your newly added rule in the rules array.

Moving forward

This was an introduction to the rewrite API. In this tutorial, I wanted to show the ABC of URL rewriting in WordPress. It’s worth mentioning that this is just a small bit of it. It helps you grasp the basics of fundamentals. In the next tutorial, we are going to delve deeper on how WordPress actually does the URL redirect and make more practical examples with it.