Skip to content

Use namespace prefix on all vendor dependecies #840

Description

@superdav42

Problem

WP-Stateless ships psr/simple-cache v3.0.0 in its vendor/ directory, which defines CacheInterface with native PHP 8 type declarations:

// psr/simple-cache v3 — shipped by wp-stateless
public function get(string $key, mixed $default = null): mixed;

Any other plugin that implements Psr\SimpleCache\CacheInterface against v1 (no native types) will fatal when both plugins are active, because the Jetpack autoloader loads the highest available version globally:

PHP Fatal error: Declaration of WordPress_Simple_Cache::get($key, $default = null)
must be compatible with Psr\SimpleCache\CacheInterface::get(string $key, mixed $default = null): mixed

This was observed in production with WP Ultimo's SSO cache class, but any plugin implementing PSR-16 v1 will hit the same conflict.

Root cause

psr/simple-cache is a transitive dependency (brianhenryie/straussjson-mapper/json-mapperpsr/simple-cache). All upstream packages accept ^1.0 || ^2.0 || ^3.0, so Composer resolves to v3. The vendored Psr\SimpleCache\CacheInterface class is then loaded into the global namespace, where it conflicts with any other plugin's v1-compatible implementation.

This is not specific to psr/simple-cache — the same class of conflict can occur with any shared PSR interface or common library (e.g., psr/log, psr/container, monolog/monolog, guzzlehttp/guzzle) where wp-stateless ships a different major version than another active plugin.

Suggested fix

Use PHP-Scoper or expand the existing Strauss configuration to prefix all vendor namespaces under a plugin-specific prefix (e.g., wpCloud\StatelessMedia\). This is the standard approach for WordPress plugins that ship Composer dependencies — it isolates vendor classes entirely and eliminates cross-plugin autoloader conflicts.

wp-stateless already has Strauss configured in composer.json, but currently only prefixes deliciousbrains/wp-background-processing. Expanding it to cover all packages in vendor/ (particularly PSR interfaces, Symfony components, Monolog, and Guzzle) would prevent this entire class of conflict.

Workaround

Pinning "psr/simple-cache": "^1.0" in composer.json resolves the immediate conflict by forcing v1 (no native types), which is compatible with both wp-stateless's own dependencies and other plugins' v1-style implementations. However, this is a band-aid — the underlying namespace collision risk remains for every other shared library.

Environment

  • WordPress: 6.8
  • PHP: 8.2
  • WP-Stateless: latest develop branch
  • Conflicting plugin: WP Ultimo (any plugin implementing PSR-16 v1 will trigger it)

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions