Bundled symfony/translation-contracts 3.x causes fatal error with other plugins' Symfony copies

Hi, I want to flag a dependency-collision issue caused by how Cornerstone bundles Symfony, in case it’s useful for a future update.

Cornerstone ships its own copy of symfony/translation-contracts (3.x) here:

/wp-content/themes/pro/cornerstone/includes/integration/Twig/vendor/symfony/translation-contracts/TranslatorInterface.php

It’s loaded under the global, unscoped namespace Symfony\Contracts\Translation. The problem is that other plugins also bundle Symfony Translation, sometimes pinned to an older contracts version (2.x). Because none of these copies are namespace-prefixed, whichever autoloader registers first wins, and when Cornerstone’s v3 interface loads first, any plugin shipping a Translator built against contracts 2.x fails PHP’s signature compatibility check and triggers a fatal error.

In my case this took down Metricool plugin’s REST endpoint entirely (500 / “PHP Fatal error: Declaration of … Translator::trans() must be compatible with … TranslatorInterface::trans(): string”), because the v3 interface requires a : string return type the older implementation doesn’t declare.

I confirmed at runtime (via Reflection) that the interface being loaded resolves to Cornerstone’s bundled copy, which is why I’m raising it here as well as with the other plugin’s author.

The robust fix on the bundling side is namespace-prefixing/scoping the vendored Symfony dependencies (e.g. via php-scoper or Mozart), so Cornerstone’s copy can’t clash with another component’s. That’s increasingly common practice for WordPress themes/plugins that vendor Symfony, precisely to avoid this class of global-namespace collision.

Happy to provide any further detail (exact versions, environment, reproduction). Thanks!

Hello Guillermo,

Thank you for this exceptionally detailed and well-diagnosed report — we genuinely appreciate the time you took to trace this with Reflection and pinpoint the exact file path.

You are 100% correct on the root cause. The issue is indeed that Cornerstone vendors symfony/translation-contracts (v3.x) in the global, unscoped namespace ( Symfony\Contracts\Translation ). When our autoloader registers first, the v3 interface (with the : string return type) forces a fatal signature mismatch on any plugin that bundles an older v2 implementation — exactly as you described with Metricool’s REST endpoint.

I’ve already escalated this to our Core/Cornerstone development team for our upcoming release planning. While scoping the entire Symfony dependency tree isn’t a trivial refactor, we recognize this is a breaking compatibility risk for our users, and we’re evaluating the effort to implement it properly.

Best Regards