Originally published at recca0120.github.io
WordPress plugin development has a unique problem: all plugins run in the same PHP process.
Your plugin uses guzzlehttp/guzzle 7.0. Another plugin uses guzzlehttp/guzzle 6.0. Both run composer install independently, but only one version gets loaded at runtime — whichever plugin's autoloader registers first. If the versions are incompatible, you get a fatal error.
You can't control this, because you don't know what else your users have installed.
Mozart's solution: copy your vendor dependencies and add your own namespace prefix to everything, making them completely distinct from anyone else's copy.
The Core Problem
PHP classes are global. GuzzleHttp\Client can only have one definition.
Mozart renames it to YourPlugin\Dependencies\GuzzleHttp\Client. Even if someone else loads the original GuzzleHttp\Client, they're now entirely separate classes that don't interfere with each other.
Installation
Mozart has its own dependencies. Use Docker or a PHAR to keep Mozart isolated from your project's vendor:
# Docker (recommended)
docker run --rm -it -v ${PWD}:/project/ coenjacobs/mozart /mozart/bin/mozart compose
# Global install (simpler, but risky)
composer global require coenjacobs/mozart
# PHAR
php mozart.phar compose
Configuration
Add Mozart config to extra in composer.json:
{"extra":{"mozart":{"dep_namespace":"MyPlugin\\Dependencies\\","dep_directory":"/vendor-prefixed/","classmap_prefix":"MyPlugin_","packages":["guzzlehttp/guzzle","psr/http-client"],"excluded_packages":["psr/container"],"delete_vendor_directories":true}}}
| Option | Purpose |
|---|---|
dep_namespace |
Prefix added to all namespaces |
dep_directory |
Where processed files go |
classmap_prefix |
Prefix for classes without namespaces |
packages |
Which packages to process (all require entries if omitted) |
excluded_packages |
Packages to skip |
delete_vendor_directories |
Remove original vendor directories after processing |
Running
# verify config
mozart config
# run prefixing
mozart compose
After running, vendor-prefixed/ contains the rewritten code:
// Before
namespace GuzzleHttp;
use Psr\Http\Client\ClientInterface;
// After
namespace MyPlugin\Dependencies\GuzzleHttp;
use MyPlugin\Dependencies\Psr\Http\Client\ClientInterface;
All use statements, type hints, and string references in class_exists() calls are updated together.
Automating With Composer Scripts
{"scripts":{"post-install-cmd":["mozart compose"],"post-update-cmd":["mozart compose"]}}
Mozart runs automatically after every composer install or composer update.
Using the Prefixed Code in Your Plugin
After Mozart processes dependencies, load its generated autoloader instead of the original vendor one:
// plugin.php
require_once __DIR__ . '/vendor-prefixed/autoload.php';
// Then use normally — the prefixed version loads transparently
use MyPlugin\Dependencies\GuzzleHttp\Client;
$client = new Client();
Classes Without Namespaces
Some older packages don't use namespaces:
// Before
class Container { ... }
Mozart prefixes the class name:
// After
class MyPlugin_Container { ... }
All new Container() call sites are updated to new MyPlugin_Container() as well.
Limitations
Dynamic class names: Mozart can't track this pattern:
$class = 'GuzzleHttp\\Client';
$obj = new $class(); // not rewritten
Mozart's own dependencies: Mozart itself uses libraries. Requiring it directly into your project can cause the same conflicts you're trying to solve — hence the Docker or PHAR recommendation.
Ecosystem shift: Mozart is still maintained (latest: 1.1.3), but many developers have moved to }}">Strauss, a fork that addresses a few known Mozart limitations — better constant prefixing, full files autoloader support, and license compliance handling.
Summary
There's no official WordPress solution for dependency conflicts. Mozart is the most direct approach: copy dependencies, prefix namespaces, make your classes completely distinct from everyone else's.
If you run into Mozart's limitations — constant prefixing, file autoloaders, license headers — }}">Strauss is worth a look.
References
- Mozart GitHub Repository — Source code and full configuration documentation
- Strauss: The Mozart Fork — Drop-in replacement that addresses known Mozart limitations
- Composer Docs: the extra field — How to configure tools via composer.json extra
- WordPress Plugin Development: Best Practices — Official WordPress plugin development guidelines