How and Why Install WordPress Core in a Subdirectory

#

We all love the famous WordPress 5 minute install, but personally I really don’t like looking at all the WordPress files in the root of the site. It’s messy and looks unprofessional. What other sites would have a dependency located right in the root?

Luckily, WordPress allows us to customize the structure of our install directory in a number of ways, and in doing so we benefit from a certain level of security through obscurity. In this article, I’ll be showing you some methods for restructuring, as well as some pitfalls to avoid.

WordPress Core

WordPress itself has a great codex article describing how to set up a new install with the core files inside a subdirectory, but I thought I would do something a little different using WP-CLI.

The below gist is a small script which leverages WP-CLI to create a new WordPress site installation with the core files in a subdirectory. The script could be improved on for future re-use, but as an example it shows the basics of what is needed for the core files to run in a subdirectory:

  1. Download the WordPress install to the subdirectory
  2. Copy the index.php file to to the root
  3. Amend the path to wp-blog-header.php in index.php
  4. Update the ‘siteurl’ in the wp_options table to include the subdirectory path

Another great way to install WordPress like this is to use Composer. Gilbert has been writing a great series about using Composer with WordPress and will be covering this approach later, but I thought it was worth the mention for this scenario.

WordPress can be installed via your composer.json as a dependency and we can execute some post install commands to set up the site in a pre WordPress installation state:

{
    "name": "polevaultweb/wp-composer-core-sub-dir",
    "description": "Installing WordPress in a subdirectory with Composer",
    "require": {
        "php": ">=5.4",
        "johnpbloch/wordpress-core-installer": "0.2.0",
        "johnpbloch/wordpress": "~4.2"
    },
    "extra": {
        "wordpress-install-dir": "wp"
    },
    "scripts": {
        "post-install-cmd": [
            "cp wp/index.php ./index.php",
            "sed -i '' \"s/\\/wp-blog-header/\\/wp\\/wp-blog-header/g\" index.php"
        ]
    }
}

Once the install has been completed you will be viewing the site with the wp path included. To remove that you will need to edit the ‘home’ option of the wp_options table…

wp option update home http://wpcomposer.dev

wp-config.php

When I started to organize my WordPress installs in this way I didn’t know that the wp-config.php file could actually be placed a level above the core files without further config, so your structure would be like:

WordPress directory structure

I find it easier having the config file in the root, than having to navigate into the core directory for edits. However, that made me think about security: where is best to put wp-config.php? There is an argument that it should be placed even higher than the site’s root folder, and that argument has been really well explained here.

If you do decide to move the file outside of the site directory you will need to do the following (taken from answer on Stack Exchange):

  1. Move the wp-config.php file to your decided location on the server, e.g. ../conf (change this where applicable).
  2. Create a new empty ‘wp-config.php` in the site root.
  3. Add this to the file:
/** Absolute path to the WordPress directory. */
if ( !defined('ABSPATH') )
    define('ABSPATH', dirname(__FILE__) . '/');

/** Location of your WordPress configuration. */
require_once(ABSPATH . '../conf/wp-config.php');

wp-content

With our WordPress core files now in a subdirectory, it doesn’t really make sense to have the wp-content directory inside it. Themes, plugins and user uploads should be separate to the core files, especially if they are version controlled.

Again WordPress gives us a way to accomplish this, using some constants in wp-config.php:

define( 'WP_CONTENT_URL', get_option('home') .  '/content' );
define( 'WP_CONTENT_DIR', dirname( ABSPATH ) . '/content' );

I’ve renamed the wp-content directory to simply content here. As Mark Jaquith argues in his WordPress skeleton site, it is cleaner and no longer in the scope of the wp directory. I’ve also used get_option('home') to make this snippet reusable.

If your site is a multisite installation then you may have issues defining the URL and directory like this. If these constants are undefined, by default WordPress sets them in /wp-includes/default-constants.php like so:

define( 'WP_CONTENT_URL', get_option('siteurl') . '/wp-content');
define( 'WP_CONTENT_DIR', ABSPATH . 'wp-content' );

Notice the use of get_option('siteurl') in the URL constant. This means that the constant will be specific to a subsite when using multisite. If we define the URL ourselves, it will not be dynamic in this way.

We actually came across this issue whilst developing the upcoming pro upgrade for WP Offload S3. I had my local development site set up with the core files in a subdirectory and wp-content in the root defined with the constant. This meant that when I inserted media into a post for a subsite, the URL did not contain the subsite path:

http://mysite.dev/wp-content/uploads/sites/3/2015/07/image.png

Instead of:

http://mysite.dev/testsubsite/wp-content/uploads/sites/3/2015/07/image.png

This has caused us a few headaches, but is exactly what WordPress means when they show this error when installing multisite on an install with a custom content directory:

Multisite compatibility error

WP Migrate DB Pro

The WordPress codex article also describes how to use a pre-existing subdirectory install.
If you have existing content that will now have incorrect URLs you can use the export feature of WP Migrate (Pro) to produce an export of your database with the old URLs replaced with the new ones. You can then import the SQL file back into your database.

We often receive support requests from people attempting to perform a migration where one site has the core files in a subdirectory and the other does not. Unfortunately we don’t support that at the moment. The sites would need to be converted to the same type of install before a successful migration can take place. We do support migrations between two sites with the same name subdirectory where the WordPress core files are stored. We are looking to introduce full migration support in the future.

I hope this has given you a good idea of the different directory structures WordPress allows, and a different approach to implementing the install.

What’s your preferred WordPress install setup? Let me know in the comments below.

About the Author

Iain Poulson

Iain is a WordPress and PHP developer from England. He builds free and premium plugins, as well as occasionally blogging about WordPress. Moonlights as a PhpStorm evangelist.