Articles, WordPress

Deploying WordPress Plugins and Sites Built Using Composer

I’m a big fan of Composer, which I believe will give you super powers. I am happy that it is gaining in popularity in the WordPress world. I often hear from developers who love it, but are not sure what to do about the vendor directory in their plugins or themes or sites.

I spoke about the advantages of challenges of using Composer in a recent episode of The Plugin Architect podcast. I use Composer in most of my plugins. Most of Ingot’s code is in Composer packages, which helps us share code between different versions and add-ons. I also helped refactor the plugins Maps Builder and Maps Builder Pro by WordImpress to make sharing code between the pro and free versions easier.

Often times people are not sure what to commit or gitignore and the best way to deploy their code to keep their package size small. I’d like to answer a few questions to help you make the best of Composer for WordPress development.

Should You Ignore The Vendor Directory In Your Git Repo?

TL;DR yes.

A lot of people are hesitant to gitignore the vendor directory and other dependencies in their GIT repos. Most of the managed hosts encourage you to use GIT to manage your dependencies when using GIT as a deploy tool. This is not good practice for  a few reasons.

First, it is messy and redundant. Why should I use a GIT to manage changes in code that is managed by a different VCS system? It doesn’t make sense. A change to a dependency should require a commit in the configuration file for Composer, Bower, NPM, etc, but not commits of actual code.

Also, keep in mind that by default, Composer checks out all packages as GIT repos. That’s great in development, but not something you want included in your final product. Composer is built with this in mind. But you should not ship your plugins with Composer packages as GIT repos or push GIT repos of dependencies to your site.

Down with redundancy and bloat, folks.


TL;DR –prefer-dist

Let’s talk about two scenarios, site deployment and shipping plugins. The solutions are pretty similar.

Site Deployment

The first situation is where you are deploying a site using GIT and Composer. If your live server has Composer installed — a rarity for some bizarre  reason in the WordPress managed hosting space — then this is easy. Use Composer to manage dependencies and gitignore the vendor directory and when you deploy use the –prefer-dist argument to tell composer to not checkout the whole GIT repo.

Laravel Forge, which is a server provisioning and deployment system of industry, has this line in its default deploy script:

composer install --no-interaction --no-dev --prefer-dist

This tells Composer to install with none of the packages that are required for development only, like your unit test framework, and to get the packaged distribution of the dependency, not the whole GIT repo. I have no idea what --no-interaction does, but let’s assume its good.

You probably want to add –optimize-autoloader to that if you’re not using Laravel, which runs that in one of its post install scripts.


CalderaWP WapuuI make more plugins than I make sites. Most Caldera Forms add-ons use Composer to manage at least two dependencies. I’ve written a Grunt script that helps automate this process. It checks out all of the dependencies using composer update --prefer-dist and then copies everything to a sub directory, which it then zips and deletes.

This means that my plugin repos, have a directory, usually called releases, with a ZIP file I can upload to our site. I used to add an automated SVN deploy when I was working on plugins that need to go to Now I just open that ZIP file and drag it into a new tag inside the SVN repo, opened with phpStorm and commit that.

What Else?

TL;DR Alot
Photo by: Jasper van der MeijThere are a few other challenges when using Composer. But I really do think they are outweighed  by the benefits. Composer is an essential part of the workflow for modern WordPress development.

Nor are these issues unique to Composer. I should probably write a follow up on using Bower Installer to solve a similar problem with Bower and NPM.

Composer is a great tool, and I hope you will try it, and when you do, this will have helped you learn how to make it work properly with GIT.



  1. Unsatisfield-with-Satis

    “Down with redundancy and bloat, folks.”

    No question that redundancy adds bloat and certain amounts of churn to update cycles. Sometimes its worth the trade-off to have more stability […or… could it be…stabuildity* YEEEAAAAAHHHH]. Increased dependencies adds more potential weak links in your chain.

    I’m curious what your take is on the NPM / Leftpad dust-up from earlier this year?

    * I just wanted to make a good CSI meme joke. Please dear god do not let this stupid word salad become a thing.

  2. Hey Josh,

    First off, I’ve got to say that I appreciate how clearly you express the benefits to using Composer, and outline a simple process for using it. Composer is indeed awesome, and you do a good job of selling it.

    A question: how do you develop in situations where your plugin is broken out into multiple Composer-managed dependencies, as Ingot is? Say I’m working on a module that’s part of a larger plugin. I’m doing my work in a branch within this module’s repo. If I want to try something out, is my only recourse to commit code in the module, push it, and then run `composer update` in the plugin’s directory? I know I could work out of the `vendor` directory, but obviously that’s not a good practice (no way to see the changes you’ve made, and the work has to be duplicated into the actual repo). I imagine I could use Composer in symlink mode, but that still seems to me like an odd solution.

    Is there a way to handle this well, or is it just a matter of making and accepting one of these compromises I’ve mentioned? Thanks!

    • Hey Lucas,

      You would use a custom repository of type “path” for that. This tells Composer that you have that specific repository on the same machine, and it will just put a symlink to its path into the vendor folder.


    • Hi Lucas!

      When I’m working on Ingot, or a plugin like that I do open the vendor directory in my IDE and edit the packages there. Since they are checked out as Git repos, I just Git add/commit/push right from inside of the package. I’m not sure if that’s good or bad practice, but it’s practical.

      • That’s absolutely the right way how to do it. I was struggling with the same problems when I’ve started using Composer in my themes and plugins, but later on figured out that:
        1) If you don’t lock the dependency to a specific version (v1.2.3), but rather a branch (dev-master), composer will pull a .git dir with your dependency. If that’s not the case, you can always use –prefer-source flag.
        2) You can then commit freely directly from the vendor/// directory and push to the upstream. Only make sure that if you’re switching branches, keep the “dev-” in composer.json in sync with your changes.

        Composer is probably the best thing that happened to PHP in last 10 years (HHVM/PHP7 being right behind it).

        Hey Josh, one question. How do you do the deployments? One option is surely ssh to a server and run `composer install` again as suggested. But it can get very tedious, especially if you have to do it many times or you have a team of more people and not everyone has ssh access to the server. Do you use CI/CD? And if yes, how?

Leave a Reply

Theme by Anders Norén