Migrating Directory Structures of Existing Blogs into a WordPress 3.0 Network

The WordPress Network adventures continue! In migrating existing sites, I found myself facing the challenge of keeping existing non-WP directory structures in place. In one case I had a WordPress site that had non-WP directories littering the root directory, and in another WordPress was installed not in the root but in a sub-directory.

In the first case I did not find an acceptable solution, but in the second case I did. (I should mention that my network uses the sub-domain structure.)

Case 1: Non-WordPress directories in the root

In this case, WP is installed at the root: example.com/. I also have directories at that level — example.com/foo — that contain what might be described as stand-alone, non-WP micro-sites. In the non-network install, WP was being cool and not interfering with them.

Moving it into the network, the site becomes number x. Since blogs.dir/x/files is served as example.com/files, I had hoped I could simply move the directories over as blogs.dir/x/foo and have them served as example.com/foo, but no dice.

What you CAN do is put the directories in the network root. The upside is that they appear as intended for the domain in question. The downside is that they appear for ALL domains in the network. In my case that’s unacceptable.

I’m hoping that in the future a plugin appears to address this issue, but for now the verdict is that it’s not possible. If you or someone you know is working on a plug-in for this, I’d happily put some beer money towards the cause!

Case 2: WordPress installed in a sub-directory

In this case, I have a domain where WP is installed in a sub-directory — example.com/foo/ — and a lot is going on in the other sub-directories. I wanted to migrate the blog without messing up the other directories.

So I created a symbolic link in place of the /foo folder to serve up the network site. Since I’m on MediaTemple, I used the directions in the trusty KB article to create the link. I navigated to the html folder of example.com and did:

ln -s /home/####/domains/wordpress-domain.com/html foo

(### being my server number, wordpress-domain.com being the domain where my WP network is installed, and foo being the directory in question)

When I mapped the domain (using the Domain Mapping plugin), I did so as example.com/foo. And under site properties I added /foo to the path. Doing these things lets me pull up the homepage. Awesome!

But there were two problems: logging-in, and permalinks.

Logging-in

With this mapping, I couldn’t log-in to the site. The problem appears to be that there was a discrepancy between the directory WP thought it was trying to log-in to, /foo/, and the directory where it was actually located, the root.

There’s a plug-in for that! From the description: “By default the wordpress cookie exactly matches the URL of your installation, this plugin removes any subfolders from the cookie so that your whole domain has access to it.”

Be sure to only activate the plug-in for the site in question and not your root site.

Pretty Permalinks

I ran into trouble when I clicked a permalink, or otherwise left the start directory as the rewrite rules from the WP domain’s .htaccess weren’t being applied.

So I grabbed some mod_rewrite code from a test installation, and compared it to that from the root domain. I determined which lines were needed for the file uploads, and which for the permalinks. The problem is that the last line, essential for the permalinks, redirects all requests (the “.” matches any character) through wordpress — including those to the domains we’re trying not to touch!

The way I managed to do it was to put in exceptions for the files and folders I wanted left alone. I would have preferred not to do it this way as it means I have to include a line for each one, but for the scale of the site I was dealing with it was no big deal. If someone knows of a solution that doesn’t involve exclusions, please let me know!

Here’s the finished mod_rewrite:

RewriteEngine On
RewriteBase /foo/
RewriteRule ^([_0-9a-zA-Z-]+/)?wp-admin$ $1wp-admin/ [R=301,L]
RewriteRule ^([_0-9a-zA-Z-]+/)?(wp-(content|admin|includes).*) $2 [L]
 
# here's the format for excluding files in the root
RewriteCond %{REQUEST_URI} !^.somefile\.html
 
# and here's the format for excluding directories
RewriteCond %{REQUEST_URI} !^/somedirectory
 
RewriteRule . /foo/index.php [L]

And that’s it! I imported the site and now I’ve one less WP install to worry about. The site in question for this case, by-the-way, was halfempty.com/wp/.

Any questions or comments, please let me know. I hope this helps you in your own projects.

Posted July 4th, 2010

Tagged:

  • http://www.andrewnacin.com Andrew Nacin

    WordPress doesn’t really like symlinks because many PHP functions don’t like symlinks.

    Case 1 is rather easy to achieve with a rewrite rule. Entirely untested, but something along these lines should work — in a nutshell, you can include HTTP_HOST in mod_rewrite conditionals pretty easily.

    RewriteEngine On
    RewriteCond %{HTTP_HOST} !^thedomain\.com
    RewriteRule /foo/(.*) index.php [L]

  • http://www.andrewnacin.com Andrew Nacin

    Tested this time. Works like a charm. Just as long as you include it before the rewrite rules redirect all confirmed files and directories to nothing and stop all additional rewriting with [L]. My example .htaccess file is for subdirectories, but the install was also serving multiple subdomains (each being a network). So in this case I wanted test-only to only be accessible from the test subdomain. Everything else in the test-only directory was then redirected to index.php.

    RewriteEngine On
    RewriteBase /
    RewriteRule ^index\.php$ – [L]

    # uploaded files
    RewriteRule ^([_0-9a-zA-Z-]+/)?files/(.+) wp-includes/ms-files.php?file=$2 [L]

    # add a trailing slash to /wp-admin
    RewriteRule ^([_0-9a-zA-Z-]+/)?wp-admin$ $1wp-admin/ [R=301,L]

    RewriteCond %{HTTP_HOST} !^test\.mysite\.com
    RewriteRule ^test-only/(.*) index.php [L]

    RewriteCond %{REQUEST_FILENAME} -f [OR]
    RewriteCond %{REQUEST_FILENAME} -d
    RewriteRule ^ – [L]
    RewriteRule ^([_0-9a-zA-Z-]+/)?(wp-(content|admin|includes).*) $2 [L]
    RewriteRule ^([_0-9a-zA-Z-]+/)?(.*\.php)$ $2 [L]
    RewriteRule . index.php [L]