htaccess workshop

I need to make a workshop about htaccess and explain whan we know about this great file and when we use it ?


The WordPress .htaccess File Explained


As of WordPress 3.0 to create pretty permalinks you need to use the following .htaccess file:

1 # BEGIN WordPress
2 <IfModule mod_rewrite.c>
3 RewriteEngine On
4 RewriteBase /
6 RewriteRule ^index\.php$ - [L]
7 RewriteCond %{REQUEST_FILENAME} !-f
8 RewriteCond %{REQUEST_FILENAME} !-d
9 RewriteRule . /index.php [L]
10 </IfModule>
11 # END WordPress

It’s easy to cargo cult this change, and simply paste the code into your own .htaccess file. And I want to make it easy for you to paste that code into your .htaccess. The goal of this post is to examine what the .htaccess rules are doing, and why they’re doing it. With information like that, you can make better decisions around your site. So let’s break this down line by line.

Line 1:

# BEGIN WordPress

It’s a comment. Easy.

And that wraps up this post. Thanks everyone, click the links below to see Part 2, 3, 4, 5, 6 of the series so that we can get more page views and sell more ads!

No wait, that would be a dumb thing to do… so let’s continue instead.

Line 2:

<IfModule mod_rewrite.c>

IfModule is a test that occurs within Apache, and it tests whether the mod_rewrite.c module is included in Apache. If mod_rewrite.c is included the code between <IfModule> and </IfModule> is run. If mod_rewrite.c isn’t included the code within the if statements doesn’t get run.

Line 3:

RewriteEngine On

RewriteEngine On tells Apache to turn on its Rewrite Rules. That’s all there is to this rule. Also, if you want to turn off all of your rules at once set the value to off.

Line 4:

RewriteBase /

RewriteBase is a bit trickier because it affects how your other rules work, and it’s not immediately intuitive how it works.

When a url comes into Apache it looks something like this:

Before the url hits the rewrite rules, the domain name, and leading slash are stripped from the url:

At this point, the url is run through all of the rewrite rules that you’ve specified, and changed accordingly.

Once those steps have been completed, the RewriteBase rule is applied. In the case of WordPress that line is RewriteBase /, so the leading slash is added to the url:

Because the WordPress RewriteBase uses just a forward slash, it doesn’t look like RewriteBasedoes a whole lot. So let’s expand with an example. Here’s an .htaccess file that has had it’sRewriteBase changed:

<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /blog
RewriteRule ^blog/wordpress-htaccess-explained$ post-12.html

Now if you were to access the url randomtype.ca/blog/wordpress-htaccess-explained, Apache would perform the following steps:

  1. Strip the domain, and leading slash and pass the following path to the rewrite rules:blog/wordpress-htaccess-explained
  2. Apply the rewrite rules
    • In the example, the single rule matches, and the path becomes post-12.html
  3. Apply the RewriteBase rule to the path to create a path of: /blog/post-12.html
    • Apache adds in the forward slash between blog and post-12.html
    • Alternatively, you could write RewriteBase /blog as RewriteBase /blog/ which would accomplish the same thing.
  4. Apache then looks for the content at /blog/post-12.html on the file system.
  5. Assuming the content is found the url randomtype.ca/blog/wordpress-htaccess-explainedserves up the physical file from /blog/post-12.html

It took me awhile to get my head around how RewriteBase works, especially because the apache documentation isn’t crystal clear on that point. You’ll not use it very frequently, but at least now you have an idea of what it does.

Line 5:

Empty – it does nothing – So easy!

Line 6:

RewriteRule ^index\.php$ - [L]

Now we can get to the meat of the .htaccess file – the RewriteRules. This particular rule is easy to understand: if the path is index.php then perform no replacement (that’s what the dash means), and exit out of the apache rewrite loop.

The final part of the rule [L] tells Apache to stop processing any remaining rules.

While this rule may seem silly, hang on to it in the back of your mind, because we’ll come back around to it.

Line 7:

RewriteCond %{REQUEST_FILENAME} !-f

This rewrite conditional uses a couple of special values, %{REQUEST_FILENAME} is a variable based upon the url you request, and !-f is an apache specific extension added to the regular expression language.

Let’s use an example for what the output of %{REQUEST_FILENAME} might look like. Let’s hit the webpage randomtype.ca/test_page.html. Within apache the value of %{REQUEST_FILENAME} gets set to reflect the physical filepath for our request. When I tested this on our servers the value came out like this: /mnt/stor0-wc0-dfw0/123456/randomtype.ca/test_page.html.

The second part of the RewriteCond would typically be a regular expression, however Apache provides some extensions that are being used. The first character – the exclamation mark (!) – is a negation. The second part -f asks whether the test string (in this case %{REQUEST_FILENAME}) exists or not on the file system.

Taken together this RewriteCond makes the following check:

If a file, taken from the variable %{REQUEST_FILENAME} does not exist on the file system, then return true.

Now RewriteCond is a cumulative rule. That is, you can’t just have a RewriteCond, you also have to have a RewriteRule. In this case the next line (Line 8) is another RewriteCond, so what happens then?

What happens is that the two conditions are combined together with a logical AND, and then theRewriteRule is applied when the two conditions are met.

Line 8:

RewriteCond %{REQUEST_FILENAME} !-d

Line 8 is almost identical to Line 7. But instead uses the -d special case, instead of the -f. The -dasks whether the path it is given is a directory or not.

So in plain english:

If a directory, taken from the variable %{REQUEST_FILENAME} does not exist on the file system, then return true.

Line 9:

RewriteRule . /index.php [L]

This rewrite rule says that every request that goes to your website should be rewritten to instead go to/index.php. A little bit greedy huh!? Now of course Line 7 and Line 8 come into play here, and if the conditions aren’t met, then /index.php isn’t used.

Overall, the 3 lines combine to make the plain english statement:

If the variable %{REQUEST_FILENAME} does not exist as a file on the file system and
if the variable %{REQUEST_FILENAME} does not exist as a directory on the file system,
then send the request to /index.php

So what happens if %{REQUEST_FILENAME} exists on the file system as a directory or file? Well then this rule isn’t applied, and the file is served.

For example when you make a request to the RANDOMTYPE website, the html also tells you to download our favicon with the path: http://randomtype.ca/cms/img/rti-favicon.png. If those two conditionals didn’t exist, then the request would instead be sent to /index.php and you wouldn’t get our favicon.

The cool thing about the WordPress /index.php file is that it picks up what the original url was, and displays a dynamic page for your website. Which is why pretty permalinks work in the first place.

Once again the [L] rule tells apache to stop processing rules.

Now let’s back up the boat a little bit and return to Line 6. What’s the point in having a such a simple rule. Well it turns out that [L] does not stop rule processing, instead Apache skips the remaining rules on its current pass. Then Apache starts another pass from the top of the .htaccess file, and starts reapplying rules. Line 6 exists to pop apache out of that loop, and prevent Line 9 from being re-ran. The exact details can be found here.

Line 10:

</IfModule> simply closes the if statement that was started on Line 2.

Line 11:

Another comment!

And that’s it. A full explanation of the WordPress htaccess file.


Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )


Connecting to %s