Strauss: The Better Mozart for WordPress Plugin Dependency Isolation

php dev.to

Originally published at recca0120.github.io

If you've read the }}">Mozart overview, you know what problem it solves: WordPress plugins share a PHP process, two plugins using different versions of the same library causes fatal errors, and Mozart prefixes your vendor namespaces to isolate them.

Strauss was forked from Mozart to address several of its known limitations. It's what the community generally recommends now.

What Strauss Changed

Issue Mozart Strauss
files autoloader support Limited Full
Constant prefixing (define()) Not supported Supported
Function prefixing Not supported v0.21.0+
License compliance Questionable Header edits + license files preserved
Destructive defaults Can delete files Non-destructive by default
Zero config Requires setup Works out of the box
Test coverage Limited Comprehensive PHPUnit tests

Installation

Recommended: PHAR

mkdir bin && touch bin/.gitkeep
Enter fullscreen mode Exit fullscreen mode

Add to .gitignore:

bin/strauss.phar
Enter fullscreen mode Exit fullscreen mode

Add to composer.json scripts:

{"scripts":{"prefix-namespaces":["sh -c 'test -f ./bin/strauss.phar || curl -o bin/strauss.phar -L -C - https://github.com/BrianHenryIE/strauss/releases/latest/download/strauss.phar'","@php bin/strauss.phar","@composer dump-autoload"],"post-install-cmd":["@prefix-namespaces"],"post-update-cmd":["@prefix-namespaces"]}}
Enter fullscreen mode Exit fullscreen mode

Downloads the PHAR on first run, uses the cached version after.

Or Require Directly

composer require --dev brianhenryie/strauss
Enter fullscreen mode Exit fullscreen mode

Configuration

Strauss works with zero configuration — it infers the namespace prefix and target directory from your composer.json automatically.

To customize, add extra.strauss:

{"extra":{"strauss":{"target_directory":"vendor-prefixed","namespace_prefix":"MyPlugin\\Vendor\\","classmap_prefix":"MyPlugin_","constant_prefix":"MYPLUGIN_","packages":["guzzlehttp/guzzle"],"exclude_from_copy":{"packages":["psr/container"],"namespaces":["Psr\\Log\\"],"file_patterns":["\\.md$"]},"exclude_from_prefix":{"namespaces":["Psr\\"]}}}}
Enter fullscreen mode Exit fullscreen mode
Option Purpose
target_directory Where processed files go (default: vendor-prefixed)
namespace_prefix Prefix added to namespaces
classmap_prefix Prefix for classes without namespaces
constant_prefix Prefix for define() constants
exclude_from_copy Packages, namespaces, or file patterns to skip entirely
exclude_from_prefix Copy but don't prefix (e.g. PSR interfaces)

Running

composer prefix-namespaces
Enter fullscreen mode Exit fullscreen mode

Or directly:

php bin/strauss.phar
Enter fullscreen mode Exit fullscreen mode

Dry run to preview changes without writing:

php bin/strauss.phar --dry-run
Enter fullscreen mode Exit fullscreen mode

Constant Prefixing

Mozart doesn't handle define(). Strauss does:

// In your dependency
define('GUZZLE_VERSION', '7.0');

// After Strauss
define('MYPLUGIN_GUZZLE_VERSION', '7.0');
Enter fullscreen mode Exit fullscreen mode

Constants are global just like classes — they conflict the same way. This matters for certain packages.

files Autoloader Support

Some packages use files autoloaders (direct require instead of PSR-4). Mozart handles these inconsistently. Strauss processes them fully:

//Package'scomposer.json"autoload":{"files":["src/functions.php"]}
Enter fullscreen mode Exit fullscreen mode

Strauss copies and prefixes these files without missing anything.

Loading in Your Plugin

// plugin.php
require_once __DIR__ . '/vendor-prefixed/autoload.php';

use MyPlugin\Vendor\GuzzleHttp\Client;

$client = new Client();
Enter fullscreen mode Exit fullscreen mode

Or have Strauss inject the autoloader into vendor/autoload.php:

php bin/strauss.phar include-autoloader
Enter fullscreen mode Exit fullscreen mode

Then you only need require vendor/autoload.php — no separate require for vendor-prefixed/.

License Compliance

Strauss adds a note to each modified file's header and preserves original license files. Mozart's handling of this is questionable — open source licenses typically require retaining original attribution. Strauss deals with it properly.

Mozart Configuration Compatibility

If you're currently using Mozart, Strauss reads extra.mozart config directly. No need to migrate immediately:

{"extra":{"mozart":{"dep_namespace":"MyPlugin\\Dependencies\\"}}}
Enter fullscreen mode Exit fullscreen mode

Strauss recognizes and applies it automatically.

Mozart or Strauss?

New project: use Strauss.

Existing Mozart project, consider migrating if:

  • Your dependencies use files autoloaders
  • You need define() constant prefixing
  • License compliance matters
  • You need function prefixing (v0.21.0+)

Migration cost is low — Strauss reads Mozart config, so it's mostly updating the scripts section.

Summary

Strauss and Mozart solve the same problem: WordPress plugin dependency conflicts. The difference is in the details: more complete autoloader support, constant prefixing, proper license handling, and safer defaults.

Start new plugins with Strauss. Migrate existing Mozart setups when you hit a limitation.

References

Source: dev.to

arrow_back Back to Tutorials