How to Install WordPress Plugins with Composer

Last Updated March 19, 2018

What happens when you’re working with another WordPress developer, both developing a site locally, and someone updates the plugins on their local version? Their syntax and implementation may be different than yours if it was a major release. Suddenly, your local copy is broken. –No fault of your own, just inconsistencies within the project.

What do you do? How do you prevent that from happening?

Let me present another scenario. Maybe this one will hit a little closer to home. Everytime you set up a WordPress site, you have to go through the same motions of downloading, installing, and activating a set of plugins. Maybe you’ve upped the ante a little bit and have a set of files on your local machine you just copy and paste everything over. Regardless, it’s still a pain when those plugins are updated. You have to visit each individual site, download the revised plugin code and replace the existing copy on your hard drive.

There must be an easier way…and there is!


I’ve started using Composer in my workflow, evaporating most (if not all) headaches.

First things first

Let’s get Composer on your machine (COUGH Mac).

If you visit Composer’s site, it will explain your options in more detail. My preference, though, was to install it globally so that the composer command can be run anywhere on your system.

Open the Terminal and from the command line, run:

curl -sS | php
mv composer.phar /usr/local/bin/composer


If the above fails due to permissions, run the mv line again with sudo.

On to the fun part…

Within your WordPress project directory, create a file called composer.json.

composer.json within the WordPress directory

As the extension suggests, this is a preference file, written in json that describes the plugins you’ll be installing and their version numbers.

Here’s my broilerplate. Feel free to copy it and use it as a starting point for your own projects.

Let me walk you through it line by line.

The first few lines are pretty obvious. Name is the name of your project. You can replace ahhacreative/PROJECTNAME with your information. Ideally, this should reflect your repo name.

Under authors, you can change “Amy (Haywood) Dutton” and “email” to include your name and email address respectively.

I’m going to jump down to line 31, where it reads extras. This defines the paths for both plugins and themes. As you can tell, I have a wp-content folder within the root that includes sub directories for plugins and themes.

On line 38, I’ve listed all the plugins that the project requires.

WP Packagist makes this easy. They mirror all the WordPress plugin and theme directories as Composer repositories.

What does that mean?

If you go to and find a plugin you want to implement, you can also find it on WP Packagist.

Take the first plugin I have listed: Intuitive Custom Post Order. The part of the URL that comes after /plugin is the name of the WP Packagist repo.

Intuitive Custom Post Order on WordPress

If you’re still not exactly sure what the name of the repo is, WP Packagist just implemented a search on their site. (Quick Note: I searched for “intuitive custom post order”, first, and it did not return any results. But, searching for “intuitive-custom-post-order” returned what I was looking for.)

Intuitive Custom Post Order on WPacketgist

Line 39 includes the full name of the repository: “wpackagist-plugin/intuitive-custom-post-order”.

Screenshot of Composer gist

You can also see there are several other plugins from Wp Packagist that I’m referencing:

"wpackagist-plugin/intuitive-custom-post-order" : "3.0.*",
"wpackagist-plugin/wordpress-seo" : "2.0.*",
"wpackagist-plugin/wp-help" : "1.4.*",
"wpackagist-plugin/better-wp-security" : "4.9.*",
"wpackagist-plugin/minqueue" : "1.1.*",
"wpackagist-plugin/worker" : "4.*",

The number following the name is the version number. The star serves as a wildcard. This means for Intuitive Custom Post Order, versions 3.0.1 or 3.0.4 would both qualify. You also have the option of being explicit when you define the version number:

"wpackagist-plugin/intuitive-custom-post-order" : “3.0.7”


Just checking to see if you’re paying attention here. One of the cases I made for Composer was that it would lock down your plugin files. How does that work with wildcards and version numbers, obviously 3.0.1 and 3.0.4 are not the same. — For now you can just trust me or if it’s really bothering, skip down to the section where I talk about the composer.lock file.

The only reason that Composer knows to look at WP Packagist for these packages, is because it’s defined as a reference on line 11 and 12.

"type" : "composer",
"url" : ""

Setting up a Premium WordPress Plugin (or a plugin on a private repository)

You’ll notice several other repositories are referenced on lines 14 – 29:

"type" : "vcs",
"url" : ""
"type" : "vcs",
"url" : ""
"type" : "vcs",
"url" : ""
"type" : "vcs",
"url" : ""

and implemented on lines 45 – 48:

"ahhacreative/ahha_plugin_gravityforms" : "1.*",
"ahhacreative/ahha_plugin_wpdbmigratepro" : "1.*",
"ahhacreative/ahha_plugin_acf" : "5.2.*",
"ahhacreative/ahha_plugin_backupbuddy" : "*"

The reason these are different is because they are premium plugins and unavailable on I still want to use Composer, though, so I’m hosting them in private GitHub and BitBucket repositories.

First, I tell Composer what type of files they are (vcs) and where they are located (url).

"type" : "vcs",
"url" : ""


The URL is the SSH address, NOT HTTPS.

Then, I reference them as project requirements:

"ahaywood/ahha-gravityforms" : "1.8.*",

That takes care of our composer.json file. Woo hoo!

Now let’s talk about actually getting that plugin set up correctly on your BitBucket, GitHub, Beanstalk, or whatever account.

Here’s what I do:

Download the plugin code. Create a folder on my computer where this code can live. I actually have a folder called COMPOSER for this exact purpose.

Composer Folder in Finder

Within the plugin folder, create a composer.json file

composer.json in Finder

Copy and paste the following code:

This file is a lot smaller than before:

  • name is the name of the repository
  • type is the type of file it is. — It could be “wordpress-plugin” or “wordpress-theme”. (Remember, when we talked about installer-paths in our first composer.json file? We defined the install paths for both a wordpress-plugin or wordpress-theme. Line 29 and 30. It actually looks at this line to know what the type of file it is and to make sure it gets installed in the right place.)
  • require this line refers to the version of composer we’re running, NOT the version of the plugin. (Can you tell I’ve gotten that mixed up before?)

Add this folder as a local repository. My app of choice is Tower.

Tower App

Run an initial commit.

Then, create a remote repository and link it to your repository.

Tower - Add Remote

Now, you’ll also need to create a tag for your commit. This relates to the version number you’re referencing in your composer.json file. I like for my numbers to match the develpers’ release numbers.

In Tower, you can click on the branch, then right click on a particular commit. Select “Create New Tag from…” in the drop down menu.

create new tag in Tower

In GitHub, tags are referred to as releases. So, if you’d prefer to do it from their site, you can click on the Releases tab, then Draft a new release.

Create new tag in GitHub

Draft a new release in GitHub

Updating your plugin

When you get ready to update the plugin, simply download the latest release from the developer’s site, then replace all of the code in your local repository with theirs.

Commit it, tag it, and push it to your remote repository.


Let’s download all these plugins and actually install them on WordPress.

Within the root of your project folder, inside the Terminal, run composer install.

Run Composer Install from the Command Line

It might take a while, but when it’s done, you can go to the Plugin screen of WordPress and activate all your plugins.


If you get an error within the Terminal about not having the right privileges to download the plugins, it’s probably related to your SSH keys.

I actually wrote a blog post about Setting up a Site with SSH. I can’t tell you how many times I actually reference that post myself! The post refers to SpringLoops, but the same applies here. Scroll down to where it says, “First, you’ll need to check for existing SSH keys.” Once you copy the keys to your clipboard, you can go to your service of choice, find the section that says SSH keys, and paste them there.

Within GitHub:
Add SSH Key within GitHub

Within BitBucket:
Adding SSH Keys within BitBucket


Error running Composer update

I moved some of my Composer plugins to BitBucket and ran into some problems. I kept getting an error every time I ran composer update:

Error running composer update

I was finally able to get it to work, but I had to change the version number within my main composer.json file to dev-master. In context:

"require": {
     "ahhacreative/ahha_plugin_gravityforms" : "dev-master",
     "ahhacreative/ahha_plugin_wpdbmigratepro" : "dev-master"

Then, within each individual plugin’s composer.json, I had to add a version and dist parameter:

  "name": "ahhacreative/ahha_plugin_wpdbmigratepro",
  "version": "master",
  "type": "wordpress-plugin",
  "require": {
    "composer/installers": "v1.0.6"
  "dist": {
        "url": "",
        "type": "git"

No Submodule mapping found

I just ran into an issue when I was trying to deploy my site via capistrano: No submodule mapping found in .gitmodules for path.

No submodule mapping found

Fortunately, this article pointed me in the right direction. Within my root directory, there’s a file called .gitmodules, I opened it up and all that was listed was the WordPress submodule:

[submodule "wp"]
	path = wp
	url = git://

I added the following lines:

[submodule "ahha_plugin_acf"]
 	path = wp-content/plugins/ahha_plugin_acf
 	url =
[submodule "ahha_plugin_gravityforms"]
 	path = wp-content/plugins/ahha_plugin_gravityforms
 	url =
[submodule "ahha_plugin_wpdbmigratepro"]
 	path = wp-content/plugins/ahha_plugin_wpdbmigratepro
 	url =

Problem solved.


You’ll also notice that now, in addition to your composer.json file, there should be a composer.lock file. This file locks things down. It records the exact version of the file being installed.

If you want to update your site, simply go to the composer.json file, update the version numbers and then go to your project folder, inside the Terminal, and run composer update. Yep! That simple.

This seems awfully complicated…

Like a lot of things in the dev world, it can be a lot up front. That’s the learning curve talking. But, once that’s mastered, things go a whole lot faster. So, here’s my process now:

  1. Create a WordPress project using Yeoman.
  2. Within the root folder, create a composer.json file, copying and pasting my own GitHub boilerplate gist.
  3. Go to my project in the Terminal and type cu (I have Oh My Zsh! installed with the composer plugin activated.)

That’s it! 3 steps

The Conversation