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:
| |
Configuration
Add Mozart config to extra in composer.json:
| |
| 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
| |
After running, vendor-prefixed/ contains the rewritten code:
| |
All use statements, type hints, and string references in class_exists() calls are updated together.
Automating With Composer Scripts
| |
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:
| |
Classes Without Namespaces
Some older packages don’t use namespaces:
| |
Mozart prefixes the class name:
| |
All new Container() call sites are updated to new MyPlugin_Container() as well.
Limitations
Dynamic class names: Mozart can’t track this pattern:
| |
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
