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! π
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?
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]
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. π
Luke – looks like a good approach, but doesn’t seem to work for me.
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.
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.
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
IsnΓΒ΄t there anywhere a Mod_Rewrite ganerator available?
Would be best selution I think.
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.
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.
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
No, the goal is to *not* have the marker in the URL.
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
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.
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
Thanx Luke, with your solution you finished my endless work.
Thanx to Alex for this helpful blog.
Aah, mod_rewrite to the rescue!
Really found the man files hard to read; great to see that someone fixed this for me over 3 years ago π