One of the trade-offs to going with a fully WordPress driven site for content is a little URL awkwardness for image and archive files you want to show/link to on a page.
For example, in a “standard” site it is pretty easy to have a page at this location:
http://example.com/foo/
and a related file download at this location:
http://example.com/foo/download/foo.zip
If you are using a CMS like WordPress to create the page here:
http://example.com/foo/ (or http://example.com/foo)
then there is no existing directory structure to allow you to put the ‘download/foo.zip’ into.
You can set up custom rewrite rules for each file you reference, but I prefer the “set it and forget it” approach rather than the “micro maintenance” approach. The solution I’m using is fairly simple.
I’m setting up a psuedo-mirror of the site WordPress page structure under a site/ directory. This means that in the example above, I will place the foo.zip file in a directory like this:
/site/foo/download/foo.zip
I then need to rewrite the /foo/download/foo.zip URL to point to the /site/foo/download/foo.zip file.
The WordPress rules only kick in when a file doesn’t exist, so you might think I should be able to simply put the file at /foo/download/foo.zip. Unfortunately, directory level URLs (/foo/) will get caught as “existing” too, keeping the WordPress rules from kicking in. Using the rewrite into a sub-directory solves this.
This only needs to happen for files with file extensions like .php, .html, .zip, .tar.gz, etc. so I need (what should be) a rather simple condition (RewriteCond) and rule (RewriteRule). Unfortunately, I’ve been banging my head against this for too long and I haven’t gotten it to work.
If your mod_rewrite-fu is stronger than mine (or if you have a different solution), perhaps you can help me in the comments.
If you are a mod_rewrite guru and are willing to be a go-to resource for me on mod_rewrite issues (paid, of course), let me know. I waste way too much time futzing with this stuff trying to get it to work.
UPDATE: I now have a very good working solution thanks to Luke Baker. His approach is a lot better than mine was: check to see if the file exists in my psuedo-site structure (DocumentRoot/site/file.gif), then rewrite the URL if it does. Here is the working rewrite code:
RewriteCond %{DOCUMENT_ROOT}site%{REQUEST_URI} -f
RewriteRule (.*) /site%{REQUEST_URI} [L]Thanks Luke!
Popularity: 5% [?]

Ajay D'Souza adds this Comment:
Hi Alex,
I’m no expert, but what rules have you used so far?
I take it you have already implemented it but it doesn’t work?
October 10th, 2006 at 11:39 am
Luke Baker adds this Comment:
The following seemed to work for me from a .htaccess file. You’d want the wordpress rules to be below these two.
RewriteEngine On
RewriteCond %{DOCUMENT_ROOT}/site%{REQUEST_URI} -f
RewriteRule (.*) /site%{REQUEST_URI} [L]
October 10th, 2006 at 11:45 am
Alex adds this Comment:
I’ve been trying a bunch of stuff. My last attempt looked something like this:
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} \.(gif|jpg|png|php|html|txt|tar|gz|zip)$ [NC]
RewriteRule ^(.*)?$ /site/$1 [QSA,L]
If this is totally ridiculous, feel free to laugh.
October 10th, 2006 at 11:46 am
Alex adds this Comment:
Luke - looks like a good approach, but doesn’t seem to work for me.
October 10th, 2006 at 11:49 am
Luke Baker adds this Comment:
Alex, I’ll assume that by not working means the RewriteCond never evaluates to true, which means it isn’t generating the proper path with the %{DOCUMENT_ROOT}/site${REQUEST_URI} part. Try seeing what that would evaluate to by handcrafting a RewriteRule that uses that. For example, if I were doing it on a non-production server:
RewriteRule .* http://0.0.0.0/%{DOCUMENT_ROOT}/site%{REQUEST_URI} [R,L]
Then I’d try to hit a URL like http://example.com/f[...]load/foo.zip and see where you get redirected to.
October 10th, 2006 at 12:17 pm
matthijs adds this Comment:
The reason the RewriteCond never evaluates to true is that there is no REQUEST_FILENAME - it doesn’t exist in the requested location.
You need to have some sort of marker in your URLs to tell you’re looking for a file, something like
http://example.com/f[...]omething.zip
and your rule would simply be
RewriteRule ^(.+)\/download\/(.+) /site/$1/download/$2
or somesuch
That’s what I’d do, anyways. Just make sure you can tell if something is a filedownload that needs to be redirected.
October 10th, 2006 at 12:28 pm
Alex adds this Comment:
I think that this URL does indicate a file:
http://example.com/f[...]load/foo.zip
And I want to be able to support any file, not just a download URL:
http://example.com/foo/bar.txt
http://example.com/foo/bar.gif
http://example.com/foo/bar/file.php
October 10th, 2006 at 12:36 pm
Abazza adds this Comment:
Isn“t there anywhere a Mod_Rewrite ganerator available?
Would be best selution I think.
October 11th, 2006 at 12:02 am
Florian adds this Comment:
I’ve done it like this some time ago.
RewriteCond %{REQUESTURI} ^\/(.*)/download\/(.*)
RewriteRule . /download/%1/%2 [R,L]
It’s only a memory yet, so I’m not sure if I did forget something.
October 11th, 2006 at 3:45 am
Alex adds this Comment:
That would probably help for files in a “download” directory, but that isn’t the solution I’m looking for. Luke Baker came up with a great solution, it is there in the post body now.
October 11th, 2006 at 6:33 am
Erik adds this Comment:
If i get you right… then: In order to get the “marker” into URLs without actually marking them, you could simply let a preformatting plugin (eg: Jerome’s Preformatted) parse all links right when you save a post to the db. you could for example search all links and images for URIs starting with a “/” then replace it with that needed string/folder… (for feed validity you would of course do it absolute)
Just an idea - i know this doesn’t solve the mod_rewrite problem - but in the end could make the pretty simple satisfying
October 12th, 2006 at 12:24 am
Alex adds this Comment:
No, the goal is to *not* have the marker in the URL.
October 12th, 2006 at 7:44 am
Sudar adds this Comment:
Hi Alex,
I think you missed out a slash between the document_root and the site folder in the first line.
It should be
RewriteCond %{DOCUMENT_ROOT}/site%{REQUEST_URI} -f
instead of
RewriteCond %{DOCUMENT_ROOT}site%{REQUEST_URI} -f
since document_root does not include a slash at the end.
Cheers,
Sudar
November 27th, 2006 at 2:24 am
Alex adds this Comment:
Interestingly, the slash was required on a Linux box and was required to be absent on a Mac OS X box. My guess is that this comes from the https.conf setting, which can define the directory location with or without the slash.
November 27th, 2006 at 8:47 am
Ron adds this Comment:
Very nice!
This is exactly what I was looking for. After hours of fiddling and searching I stumbled across your blog, Alex.
Thanks Luke for posting your solution, you’ve helped more than just one person.
Ron
May 16th, 2007 at 7:44 pm
Abazza adds this Comment:
Thanx Luke, with your solution you finished my endless work.
Thanx to Alex for this helpful blog.
May 27th, 2007 at 12:24 pm