Modern WordPress Development – Composer

composerComposer is a PHP dependency manager that’s been in the wild for roughly 2 years. In short it helps mitigate the extremely antiquated ways PHP developers had been managing third party libraries. Composer is nothing new to PHP, as I said it’s over 2 years old, but WordPress has been slow to get on board. I’ve set up a workflow that, I admit, is “somewhat flawed,” but is a step in the right direction for managing WordPress via Composer. The goal of this article is to be a reference and I am going to keep it as concise as possible. To install Composer follow this guide, be sure to install it globally. For a more in-depth guide read excellent Scott Walkinshaw’s posts Using Composer with WordPress and WordPress Plugins with Composer and buy the Roots screencast Using Composer with WordPress it’s worth 3x it’s cost. One quick note, is all Composer requires a composer.json file which is essentially a manifest that outlines everything we want completed for the project. Also, I will show you my completed json file below and you can use that as a reference for any notes I make to indexes in this article.

Manually Add WordPress to Composer

Composer’s de facto repository for packages is at packagist.org, since there is no official WordPress packagist package in that repo, we can manually add WordPress to our package by adding the following into our manifest’s “repositories” key (which is an array):

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

Ignore the *type* webroot and *require* of webroot-installer for now, I’ll get to that in the next section. What this does is add a manually add a package to our manifest. We tell it that its name is WordPress which is arbitrary, we can call it whatever we want, we list the version as the most recent (as of this writing 3.7.1) and tell it where it is located, in the “dist” key– where we set that it is a zip file and it’s located at the official WordPress github repository. We choose to keep the WordPress core in a directory “wp” – later you will see we will store our application specific packages (plugins, themes) in a directory in line with “wp” i.e. our application specific packages will live in /our/server/app/ and WordPress core will live in /our/server/wp/ which gives us excellent and flexible separation of concerns.

Change the Directory WordPress is Installed In

Composer, by default, stores all packages in a /vendors/ directory. To get around that we can use fancy guy’s webroot installer plugin for Composer… and guess what, we can just require it, so no manual downloading necessary… told you composer is great! If you refer to the last section, we can see how to change the behavior of Composer. Since we are going to want to install WordPress in a subdirectory of the root and not stuffed in the vendors directory (which is Composer’s default behavior), we modify the setting of our custom WordPress package. First we set the package type to “webroot” so that it uses the webroot plugin for Composer and we require the webroot plugin for this particular package. We set the desired destination of the package in the “extra” key below, e.g. we add

 "webroot-dir": "wp",
 "webroot-package": "wordpress"

to the composer.json’s “extra” index. Additionally, we are going to want to set where WordPress plugins, themes and must use plugins are to go. To do so we set the “installer-paths” key in the “extra” key of the composer.json file like such:

"installer-paths": {
    "app/plugins/{$name}/": ["type:wordpress-plugin"],
    "app/mu-plugins/{$name}/": ["type:wordpress-muplugin"],
    "app/themes/{$name}/": ["type:wordpress-theme"]
}

I chose app as the subdirectory where my applications’ non-core files will be located – you can choose whatever you want. You can keep it as wp-content or rename it to content as Mark Jaquith does in WordPress Skeleton.

WordPress Packagist

Outlandish created an awesome repository for WordPress Plugins, WordPress Packagist. This repository mirrors the WordPress Plugin Repository and allows you to include plugins listed within it super easy. It even sets them as “wordpress-plugin” type so the plugins will listen to our installer-paths declaration. To access this repository we have to tell our manifest that we are going to be using this repository by adding an entry to its “repositories” array like such:

    {
      "type":"composer",
      "url":"http://wpackagist.org"
    }

We tell it that this repository is set up as a composer style repo and that it lives at http://wpackagist.org. Now we can simply add plugins to our project by adding to our “require” key’s object the name of the package (prefixed with our source, wpackagist/) and the version of the plugin we wish to install like such:

"wpackagist/easy-responsive-carousel":"0.4.5"

Custom WordPress Plugins & Themes (not in a repository)

There may come a time that you want to include a plugin that is not located in a Composer repository, for example they may just live on github or somewhere else as a zip file. We can easily add this as an element of the “respositories” key in our composer.json file like such:

    {
      "type": "package",
      "package": {
        "name": "easy-nag-popup",
        "type": "wordpress-plugin",
        "version": "2.1.7.1",
        "dist": {
          "type": "zip",
          "url": "https://github.com/matstars/easy-nag-popup/archive/2.1.7.1.zip"
        },
        "require" : {
          "fancyguy/webroot-installer": "1.*"
        }
      }
    }

and be sure to include it in the “requires” key like such:

    "easy-nag-popup":"2.1.7.1"

We can even do this for themes, like such:

    {
      "type": "package",
      "package": {
        "name": "roots",
        "type": "wordpress-theme",
        "version": "6.5.0",
        "dist": {
          "type": "zip",
          "url": "https://github.com/roots/roots/archive/6.5.0.zip"
        },
        "require" : {
          "fancyguy/webroot-installer": "1.*"
        }
      }
    }

Notice how I specified the type as wordpress-theme, this will follow the installer-paths set in the “extra” key.

Let’s Compose!

Remember how I said this process was somewhat flawed? This is where that “somewhat flawed” kicks in. Before I get into that, let’s take a look at the composer.json file we have created:

{
  "repositories": [
    {
      "type":"composer",
      "url":"http://wpackagist.org"
    },
    {
      "type": "package",
      "package": {
        "name": "wordpress",
        "type": "webroot",
        "version": "3.7.1",
        "dist": {
          "type": "zip",
          "url": "https://github.com/WordPress/WordPress/archive/3.7.1.zip"
        },
        "require" : {
          "fancyguy/webroot-installer": "1.*"
        }
      }
    },
    {
      "type": "package",
      "package": {
        "name": "easy-nag-popup",
        "type": "wordpress-plugin",
        "version": "2.1.7.1",
        "dist": {
          "type": "zip",
          "url": "https://github.com/matstars/easy-nag-popup/archive/2.1.7.1.zip"
        },
        "require" : {
          "fancyguy/webroot-installer": "1.*"
        }
      }
    },
    {
      "type": "package",
      "package": {
        "name": "roots",
        "type": "wordpress-theme",
        "version": "6.5.0",
        "dist": {
          "type": "zip",
          "url": "https://github.com/roots/roots/archive/6.5.0.zip"
        },
        "require" : {
          "fancyguy/webroot-installer": "1.*"
        }
      }
    }      

  ],
  "require": {
    "wordpress": "3.7.1",
    "fancyguy/webroot-installer": "1.0.0",
    "wpackagist/advanced-custom-fields":"*",
    "wpackagist/posts-to-posts":"1.4.*",
    "wpackagist/easy-responsive-carousel":"0.4.5",
    "easy-nag-popup":"2.1.7.1",
    "roots":"6.5.0"

  },
  "extra": {
    "webroot-dir": "wp",
    "webroot-package": "wordpress",
    "installer-paths": {
        "app/plugins/{$name}/": ["type:wordpress-plugin"],
        "app/mu-plugins/{$name}/": ["type:wordpress-muplugin"],
        "app/themes/{$name}/": ["type:wordpress-theme"]
    }
  }

}

Brief rundown of the keys: repositories: Here we list any repositories outside of the official Composer repo (packagist.org), this can include full fledged repositories (wpackagist.org) and individual packages hosted elsewhere (github, bitbucket, etc.) require: what packages are we going to include in our project? Here we include webroot-installer, which helps us store our files where we need to install them, WordPress core, WordPress plugins and WordPress themes. extra: here we list where we want WordPress installed (webroot-dir and webroot-package set to “wp” and “wordpress” to denote where we want what installed, respectively). We also tell webroot-installer the default location for specific package types (i.e. wordpress-plugins in app/plugins, wordpress-muplugins in app/mu-plugins/ and wordpress-themes in app/themes/, respectively). N.B. remember we decided, as a matter of separating concerns, to store the plugins/themes in the directory /app and wordpress core in /wp. Okay, so we have a single composer.json file. Drop it in an empty directory and run composer install. Once you install your composed application, you will see the following directories created: vendor, wp, app as well as a composer.lock file. For all intents and purposes we can ignore the vendor directory. The app directory is where all our application specific code will live (themes/plugins) and the WordPress core will live in the wp directory. Now comes the manual work. Since we are essentially Giving WordPress Its Own Directory, we need to do some manual work. First things first, we have to copy /wp/wp-config-sample.php to the root level and rename it wp-config.php. Let’s edit this file with the information we are going to need to add and update. First things first add your database information as you normally would. Next we need to set some constants for our WordPress environment, namely where our application specific code will live and, optionally, where our must use plugins will live (aside, since it’s a bit of a kludge, I have yet to use must use plugins), if you followed along we would add the following code right after we set our database credentials:

define( 'WP_CONTENT_DIR', dirname( __FILE__ ) . '/app' );
define( 'WP_CONTENT_URL', 'http://' . $_SERVER['HTTP_HOST'] . '/app' );
define( 'WPMU_PLUGIN_DIR', dirname( __FILE__ ) . '/app/mu-plugins' );
define( 'WPMU_PLUGIN_URL', 'http://' . $_SERVER['HTTP_HOST'] . '/app/mu-plugins' );

additionally we need to tell WordPress that our core is not located in the root, but rather in the subdirectory wp. To do so, we need to update the definition of ABS path in the wp-config file, like such:

define('ABSPATH', dirname(__FILE__) . '/wp/');

Next we need to copy /wp/index.php to our root directory and make one minor change: we need to tell index.php where our wp-blog-header.php file is located — it is no longer in our root but in the wp sub directory, so we change the require command to:

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

Let’s run through the WordPress installation, and we can make the final changes. Once the site is set up, if you have been following along, WordPress will be looking for a theme that is not there (at this writing TwentyThirteen), so we have to set Roots as our theme. Finally, since we are using WordPress in a subdirectory, we have to go into Settings > General and remove “/wp” from Site Address (URL)  (not WordPress Address (URL)). We are done! Note, for some reason Roots is not enqueuing the right CSS file, but if you copy Twenty Thirteen from wp/wp-content/themes/ to app/themes/ and activate the Twenty Thirteen theme it works fine.

Hope that this helps you all out there and let me know if there’s anything I missed (I’m still relatively new to Composer) or something that is easier. I need to come up with a way to automate the moving/setting of index.php and wp-config.php – maybe with Grunt. I tried adding a shell script (I’m not too great with writing scripts either) to “scripts” > “post-install-cmd” in composer.json but ran into trouble. Until next time….

7 Responses to “Modern WordPress Development – Composer”

  1. talves

    Great article summed up real nice. I created a WordPress Composer Skeleton on Github.

    It was a first cut attempt at understanding the stack prior to articles like yours.

    Regards,
    Tony

    Reply
  2. naara

    Thank you so much for your tut it’s very clear and easy to follow (it was my first time using composer or even installing roots). Something went wrong with the CSS, as you mentioned it, so I tried to activate Twenty Thirteen from app/themes and reactivate Roots but the CSS remains unloaded. I tried to activate Twenty Thirteen as well, but no CSS. Under the wp admin panel, in Appearance > Themes I can see both themes, but with an broken image link.

    I’d be so grateful if you could help… CHEERS

    Reply
  3. Trevor

    Excellent tutorial. Had some trouble going through the tutorial developed by roots.io, and this cleared up some issues I had with building a good composer file.

    Keep it up!

    Reply
  4. Sandra1n

    Hey, can u tell me why u install wp in “wp” folder?
    Much easier install it in current dir “.” , then manual work is not necessary

    Reply

Leave a Reply