david winter

Install and manage WordPress with Composer

Well over two years have passed since my previous blog post on managing WordPress with git was written. A lot has changed since then. Composer has taken the PHP world by storm and the majority of developers are seeing the benefits and embracing it.

Using Composer, you can list a set of requirements for your project, and let it figure out where everything needs to be installed to, what dependencies are required, and how to obtain them.

If you’re not familiar with Composer, I would recommend that you go and read the Getting Started guide. This howto assumes you have knowledge of, and have perhaps used Composer before. This howto will cover installing WordPress with Composer. Following blog posts will cover installing themes and plugins.

Installing WordPress

First, you need to make sure you have Composer installed for your project, this is easily done by running the following command:

mkdir my-wordpress-project
cd my-wordpress-project
curl -sS https://getcomposer.org/installer | php

You will now have a composer.phar file in your project directory.

Create a new composer.json file with the following contents:

    "repositories": [
            "type": "package",
            "package": {
                "name": "wordpress",
                "type": "webroot",
                "version": "4.0",
                "dist": {
                    "type": "zip",
                    "url": "https://github.com/WordPress/WordPress/archive/4.0.zip"
                "require" : {
                    "fancyguy/webroot-installer": "1.0.0"
    "require": {
        "wordpress": "4.*",
        "fancyguy/webroot-installer": "1.0.0"
    "extra": {
        "webroot-dir": "public/wp",
        "webroot-package": "wordpress"

A quick explanation of what the above is doing for us. WordPress doesn’t support Composer installs out of the box - it doesn’t provide a composer.json file. So we have to create a virtual Composer package for WordPress. We give it a name, version and location to a zip file archive where it can be downloaded from.

We don’t want the package to be installed to the default vendor directory that Composer would use. We need to specify a different directory. We do this with the aid of the webroot installer package. By giving our virtual package a type of webroot, the plugin will detect and relocate the install location of WordPress to public/wp.

We define the preferred install located in the extra section of the composer.json file.

We need to create the public directory:

mkdir public

Note: It’s good practice to have a separate directory in your projects for your document root. This is so that if you have any other files, that shouldn’t be served via the web server, you can place them outside of the public directory.

You can now run:

php composer.phar install

This will pull down WordPress for you into the correct location.

Now with a normal install you’d go ahead and proceed with the famous 5 minute install. But because we want to be able to use Composer for any future WordPress updates, we don’t want to change any of the contents of the public/wp directory. We want to be able to ignore this directory with our source code management tool.

In order to be able to use WordPress, we need to copy some files from the public/wp directory to the public directory.

cp -R public/wp/{wp-content,index.php,wp-config-sample.php} public/

mv public/wp-config-sample.php public/wp-config.php

In public/index.php, modify the following line:

require( dirname( __FILE__ ) . '/wp-blog-header.php' );


require( dirname( __FILE__ ) . '/wp/wp-blog-header.php' );

We’re just updating the path as we want to reference the core WordPress files in the public/wp directory.

Go to https://api.wordpress.org/secret-key/1.1/salt/ and update the lines in your public/wp-config.php file:

define('AUTH_KEY', 'put your unique phrase here');
define('SECURE_AUTH_KEY', 'put your unique phrase here');
define('LOGGED_IN_KEY', 'put your unique phrase here');
define('NONCE_KEY', 'put your unique phrase here');
define('AUTH_SALT', 'put your unique phrase here');
define('SECURE_AUTH_SALT', 'put your unique phrase here');
define('LOGGED_IN_SALT', 'put your unique phrase here');
define('NONCE_SALT', 'put your unique phrase here');

That’ll secure your WordPress install. Configure your database settings as you normally would.

Now we need to set a few additional constants for the configuration.

define('WP_CONTENT_DIR', __DIR__ . '/wp-content');
define('WP_CONTENT_URL', 'http://' . $_SERVER['SERVER_NAME'] . '/wp-content');
define('WP_SITEURL', 'http://' . $_SERVER['SERVER_NAME'] . '/wp');
define('WP_HOME', 'http://' . $_SERVER['SERVER_NAME']);

Because the wp-content directory isn’t in the same place as the core WordPress files (remember, it is now one directory level above), we need to tell the config file where it actually is. The same with the core WordPress files.

Some other optional tidy up; remove the default twenty* themes:

rm -rf public/wp-content/themes/twenty*

Remove the default Hello Dolly plugin too:

rm public/wp-content/plugins/hello.php

You probably have an idea of what theme you’ll be using. Setting this constant will define the default theme, so that you don’t need to manually set this in your admin. This is optional.

define('WP_DEFAULT_THEME', 'mytheme');

Regarding housekeeping with your source code management tool. You’d want to ignore the composer.phar file and public/wp directory. Everything else can be committed and pushed.

Updating WordPress

Say you want to update to version 4.0.1 when it is released. In your composer.json file, update the section under repositories so it looks like:

    "type": "package",
    "package": {
        "name": "wordpress",
        "type": "webroot",
        "version": "4.0.1",
        "dist": {
            "type": "zip",
            "url": "https://github.com/WordPress/WordPress/archive/4.0.1.zip"
        "require" : {
            "fancyguy/webroot-installer": "1.0.0"

We’ve updated the version number and the URL for the zip archive to reference the new versioned file.

You can then run:

php composer.phar update wordpress

Then commit your composer.json and composer.lock files.

That’s all there is to it. This is quite a stable workflow, and my next blog posts will cover handling the installation of plugins and themes.


Questions? Comments? Your 2¢'s? → @davidwinter