Apache's mod_rewrite and PHP's REQUEST_URI variable
Solution 1:
The "problem" is related to mod_dir (although mod_dir isn't strictly "the" problem - it's doing the correct thing and "fixing" the URL).
Since wp-admin
is a physical directory, mod_dir "fixes" the URL by appending a trailing slash (required in order to correctly serve the directory index, eg. index.php
). It does this with a 301 redirect. The problem is that this is occurring after your internal rewrite which results in the rewrite being turned into a redirect, thus exposing your /wordpress
subdirectory.
So, the correct URL is strictly /wp-admin/
(with a trailing slash). If you didn't have your /wordpress
subdirectory and everything was in the document root then mod_dir would simply redirect /wp-admin
to /wp-admin/
, which would then result in /wp-admin/index.php
being served (as an internal subrequest).
What you need to do is append the trailing slash manually. If the requested URL does not end in a slash but would otherwise map to a physical directory within the /wordpress
subdirectory then append the trailing slash (via an external redirect). This redirect should occur before your internal rewrites.
So, try the following before your existing directives:
# Append a slash if it is omitted and would map to a directory
RewriteCond %{REQUEST_URI} !^/wordpress/
RewriteCond %{REQUEST_URI} !/$
RewriteCond %{DOCUMENT_ROOT}/wordpress/$1 -d
RewriteRule (.*) /$1/ [R=302,L]
What this does is, for any request that does not already start /wordpress/
and does not end in a slash but does map to a physical directory within the /wordpress
subdirectory then redirect and append a slash. So, a request for /wp-admin
gets redirected /wp-admin/
, providing /wordpress/wp-admin
exists as a directory. (Your internal rewrites then route the URL as before.)
You will need to make sure your browser cache is cleared (or test with the browsers object inspector open and disable the cache) since the earlier 301 redirects (by mod_dir) will have been cached.
When you are sure it's working OK then change the 302
(temporary) redirect to a 301
(permanent) - if that is the intention. 302s are cached by the browser, so makes testing that bit easier.
Aside:
Apache's REQUEST_URI
vs PHP's $_SERVER['REQUEST_URI']
...Apache passing to the PHP
$_SERVER['REQUEST_URI']
variable the URL after it has been rewritten rather than the original one requested.
Apache doesn't actually pass the REQUEST_URI
variable from mod_rewrite to PHP directly. Whilst these two variables have the same name, as far as I can tell, PHP itself populates this variable from the request.
The Apache REQUEST_URI
server variable and PHP's $_SERVER['REQUEST_URI']
superglobal actually contain different information:
- PHP's
$_SERVER['REQUEST_URI']
contains the query string, Apache'sREQUEST_URI
server variable does not; it contains the URL-path only. - PHP's
$_SERVER['REQUEST_URI']
contains the original URL-path from the request, not the rewritten URL. Whereas Apache'sREQUEST_URI
server variable is updated (throughout the request) to contain the rewritten URL. - The URL-path component of
$_SERVER['REQUEST_URI']
is not URL decoded (ie. %-decoded). Whereas the ApacheREQUEST_URI
server variable is %-decoded. (NB: The query string portion of the URL always remains %-encoded in both Apache and PHP. If you need to examine the %-encoded URL-path in Apache then checkTHE_REQUEST
Apache server variable.)