htaccess – Redirect Nested WordPress Folder

.htaccessredirectWordpress

I've been trying for hours and am already a bit on the edge about this, so I am probably not seeing the obvious.

I have two WordPress sites, one is my "main" page which people see when they come to my domain root, and one is a private blog:

www.example.com and www.example.com/blog

On my server root, I would like to keep both pages organized in separate folders, to keep it clean. These folders I named wp-main and wp-blog. To redirect the domains I started fiddling with .htaccess, but I can't seem to get it right – blog is the problem. main works fine with instructions from here, but the blog doesn't load the WordPress theme (displays raw content), and does not redirect to any subfolders. If I take away the redirect rules for main, the blog index gets loaded, but still no subfolder redirect.

Can anybody help me out here?

<IfModule mod_rewrite.c>
RewriteEngine on
RewriteBase /

## redirect for main
RewriteCond %{HTTP_HOST} ^(www.)?example.com$
RewriteCond %{REQUEST_URI} !^/wp-main($|/)$
RewriteCond %{REQUEST_URI} !^/blog($|/)$
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ /wp-main/$1
RewriteCond %{HTTP_HOST} ^(www.)?example.com$
RewriteRule ^(/)?$ wp-main/index.php 

## redirect for blog
RewriteRule ^blog(.*)$ /wp-blog/$1
</IfModule>

Best Answer

RewriteCond %{REQUEST_URI} !^/wp-main($|/)$
RewriteCond %{REQUEST_URI} !^/blog($|/)$

You should remove the $ (end-of-string anchor) at the end of these two CondPatterns. Otherwise, requests for /blog/<something> will get routed to /wp-main/..., since the above condition is satisfied (since it does not match the pattern ^/blog($|/)$).

Consider reversing your logic and rewrite /blog (the more specific URL) first. (And use L flags to prevent additional processing.)


UPDATE: Try the following instead...

I've reversed the logic, so that /blog is handled first (the more specific URL). This avoids you having to explicitly avoid /blog when rewriting the main site. I've also assumed that you only have one domain (which I asked about in my earlier comment) - this avoids the requirement to check the Host header (ie. HTTP_HOST server variable). If you do have more than one domain on your account then your current directives were incomplete anyway.

You do not need the <IfModule mod_rewrite.c> wrapper, unless your site is intended to function without mod_rewrite (it is not).

Potentially, all you need is:

RewriteEngine on

# Rewrite blog site
RewriteRule ^blog/?(.*)$ /wp-blog/$1 [L]

# Rewrite everything else to the main site
RewriteRule (.*) /wp-main/$1 [L]

A few assumptions:

  • Each subdirectory (/wp-blog and /wp-main) has its own .htaccess file (with mod_rewrite directives) - this prevents a rewrite loop.

  • There are no static resources outside of these WordPress installations. All static resources are also rewritten. eg. /images/foo.jpg is internally rewritten to /wp-main/images/foo.jpg and /blog/images/foo.jpg is rewritten to /wp-blog/images/foo.jpg etc. You never reference /wp-main or /wp-blog directly in client-side HTML. If there are shared static resources in other locations (eg. a /scripts subdirectory off the real document root) then you will either need an additional filesystem check (if there are too may locations to list) or include an exception for this location, before the existing directives. For example:

    RewriteRule ^scripts/ - [L]
    
  • Both /blog and /blog/ (with a slash) access your blog homepage (this avoids /blog being rewritten to your main site). Ideally, only /blog/ should access your blog and /blog would redirect to this. This can be achieved with an additional redirect before the blog rewrite:

    # Rewrite blog site
    RewriteRule ^(blog)$ /$1/ [R=302,L]
    RewriteRule ^blog/?(.*)$ /wp-blog/$1 [L]
    

    Change the 302 (temporary) to 301 (permanent) only when you are sure this is what you want and have confirmed that it works OK. 301s are cached persistently by the browser.


Then, each .htaccess file in the respective subdirectory should be of the form:

RewriteEngine On
RewriteRule ^index\.php$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . index.php [L]

No need to specify the RewriteBase or include the subdirectory in the RewriteRule substitution.