Composer is the standard dependency management tool for PHP. It allows you to define your project's libraries, WordPress Core, plugins, and themes in a single composer.json file.
Using Composer makes deployment pipelines (CI/CD) repeatable and keeps your Git repository clean, since third-party source code (such as plugins from WordPress.org) does not need to be committed directly to your repository.
Seravo's default project template uses Composer out of the box, and we recommend it for all professionally maintained WordPress sites.
How Composer Works with WordPress
In a WordPress project, Composer is configured via the composer.json file located in the project root (/data/wordpress/). The configuration typically relies on three key sections: repositories, require, and extra.
1. Repositories (Package Sources)
To allow Composer to discover official WordPress plugins and themes, you need to configure WPackagist as a package source. WPackagist mirrors the entire WordPress.org plugin and theme directory as Composer-compatible packages.
"repositories": [
{
"type": "composer",
"url": "https://wpackagist.org",
"only": [
"wpackagist-plugin/*",
"wpackagist-theme/*"
]
}
]
You can also add your own private Git repositories to this section later.
2. Required Packages (require)
This section lists all packages required by your site along with their version constraints. The example below installs WordPress Core, the mandatory Seravo plugin, and a plugin and theme from WPackagist:
"require": {
"php": ">=8.0",
"johnpbloch/wordpress-core": "^6.4",
"seravo/seravo-plugin": "*",
"wpackagist-plugin/two-factor": "^0.8",
"wpackagist-theme/twentytwentyfour": "*"
}The caret constraint
^6.4allows minor and patch updates (e.g.,6.4.1), while preventing automatic upgrades to the next major version (7.0).The wildcard
*installs the latest available version.
3. Installation Paths (extra.installer-paths)
By default, Composer installs all packages into the vendor/ directory in the project root. Because WordPress expects plugins and themes in specific directories, you must map the installation paths accordingly:
"extra": {
"installer-paths": {
"htdocs/wp-content/plugins/{$name}/": ["type:wordpress-plugin"],
"htdocs/wp-content/mu-plugins/{$name}/": ["type:wordpress-muplugin"],
"htdocs/wp-content/themes/{$name}/": ["type:wordpress-theme"]
},
"wordpress-install-dir": "htdocs/wordpress"
}This configuration instructs composer/installers to automatically place any package of type wordpress-plugin into /htdocs/wp-content/plugins/.
Adding Custom Git Repositories (Themes and Plugins)
The best way to manage custom-built plugins and themes is to maintain them in their own dedicated Git repositories (e.g., on GitHub or Bitbucket) and pull them into your main project via Composer.
1. Create a composer.json in the root of your theme or plugin:
{
"name": "company/custom-theme",
"type": "wordpress-theme",
"license": "GPL-3.0-or-later",
"description": "Custom client theme"
}2. Add the Git source to your main project's composer.json:
Add a new entry to the existing repositories array:
"repositories": [
{
"type": "vcs",
"url": "[email protected]:company/custom-theme.git"
}
]
3. Require the package:
"require": {
"company/custom-theme": "dev-main"
}Note: Using dev-main or dev-master always fetches the latest commit from that branch. You can also specify semantic version tags (such as 1.0.0) if you tag releases in your theme or plugin repository.
Commercial and Private WordPress Plugins
WPackagist only mirrors free plugins hosted on WordPress.org. For commercial Pro plugins (such as ACF Pro or Gravity Forms), there are two common ways to manage them alongside Composer:
Commit the plugin code to your project repository:
The simplest approach is to install the plugin manually and exclude it from Composer. Download the ZIP archive, extract it into
wp-content/plugins/commercial-plugin/, and track that folder in Git by adding an exception to your.gitignorefile:!htdocs/wp-content/plugins/commercial-plugin/
Use third-party package repositories (Premium Repositories):
Many teams use services like Private Packagist, Satis, or official vendor Composer endpoints (for example, ACF Pro provides an official
composer.json-compatible repository URL for license holders). Authentication keys are typically stored in anauth.jsonfile or via environment variables (.env).
Running Composer Commands
You can install and update dependencies in your local development environment or on the server via SSH (from the project root /data/wordpress/):
composer install– Installs the exact package versions locked incomposer.lock. (This is the command used by CI/CD pipelines and automated deployments).composer update– Checks for newer compatible package versions, installs them, and updatescomposer.lock.composer require wpackagist-plugin/plugin-name– Searches for the specified plugin, adds it tocomposer.json, and installs it immediately.
Common Issues and Troubleshooting
PHP runs out of memory (
Allowed memory size exhausted): Resolving complex dependency trees can exceed the default PHP memory limit. Bypass the limit for a single run usingCOMPOSER_MEMORY_LIMIT=-1 composer update.Private Git repository download fails (
Permission denied): Connect to the server with SSH agent forwarding enabled (ssh -A user@server) so Composer can authenticate using your local SSH keys. Alternatively, store your API tokens in anauth.jsonfile in the project root (ensureauth.jsonis ignored in.gitignore).Package installs into
vendor/instead ofwp-content/: Check that the package's owncomposer.jsondefines the proper package type ("type": "wordpress-plugin","wordpress-theme", or"wordpress-muplugin").Lock file mismatch (
composer.lock is not up to date): Ifcomposer.jsonwas edited manually, update the lock file's content hash by runningcomposer update --lock.
See Also
If you need assistance configuring SSH keys for private Git repositories on Seravo's servers or troubleshooting Composer deployment pipelines, contact our support team at [email protected].
