Skip to content

Prefix Composer dependencies with wp-scoper (no more class conflicts with other plugins) - #336

Open
mostafasoufi wants to merge 2 commits into
feat/ci-cd-tests-deployfrom
feat/wp-scoper
Open

mostafasoufi wants to merge 2 commits into
feat/ci-cd-tests-deployfrom
feat/wp-scoper

Conversation

@mostafasoufi

Copy link
Copy Markdown
Member

Closes #334

⚠️ Based on #335 (CI/CD). Please merge that one first; this PR then shows only the wp-scoper changes. It adds a CI job to testing.yml and adjusts deploy.yml, which is why it is stacked.

🚨 Problem

vendor/ ships enshrined/svg-sanitize and the Symfony polyfills unprefixed. Another plugin bundling the same library (Safe SVG with 1M+ installs bundles enshrined/svg-sanitize; countless plugins bundle symfony/polyfill-php80) can load a different version first, and we end up running against a class we never tested, or with a fatal error. Full write-up in #334.

✅ What this PR does

Uses wp-scoper (a Composer plugin, same as wp-sms and its add-ons) to give every dependency our own namespace.

composer.json

  • require-dev: veronalabs/wp-scoper ^1.4.2
  • extra.wp-scoper: prefix WPParsidate\Dependencies, target packages/, packages enshrined/svg-sanitize + the three Symfony polyfills, update_call_sites: ["inc"], delete_vendor_packages: true
  • config.allow-plugins for wp-scoper

Generated on composer install (committed)

  • packages/ – 39 prefixed PHP files, 77 KB instead of 107 KB (tests, docs and config of the libraries are not copied)
  • packages/autoload.php – classmap autoloader for the dependencies plus PSR-4 autoloading for our own WPParsidate\ → inc/ classes, plus the polyfill bootstrap files

Runtime change – wp-parsidate.php

// before
require_once __DIR__ . '/vendor/autoload.php';

// after
require_once __DIR__ . '/packages/autoload.php';
require_once __DIR__ . '/inc/Functions/Core.php';
require_once __DIR__ . '/inc/Functions/Old.php';

(inc/Functions/*.php were previously loaded through Composer's autoload.files; they are now required directly so vendor/ is not needed at all at runtime.)

Call site updated automatically – inc/Helper/Sanitizing.php

// before
use enshrined\svgSanitize\Sanitizer;
// after
use WPParsidate\Dependencies\enshrined\svgSanitize\Sanitizer;

Repository hygiene

  • vendor/ removed from git and added to .gitignore and .distignore (dev only now)
  • packages/ committed, so git clone still works without running Composer
  • README section explaining the workflow

CI

  • New scoper job in testing.yml: runs composer install and fails if packages/ or inc/ would change, so an out-of-date packages/ can never be merged
  • deploy.yml runs composer install (with dev dependencies so wp-scoper runs); vendor/ is excluded from the ZIP by .distignore
  • tests/unit/DependenciesTest.php: the prefixed Sanitizer class exists and is loaded from packages/; str_contains, str_starts_with, array_is_list, json_validate are available (natively or via the bundled polyfills)

🎁 Benefits

  • 🛡️ No class conflicts with other plugins, ever. Our Sanitizer is WPParsidate\Dependencies\enshrined\svgSanitize\Sanitizer, nobody else has that class.
  • 📌 Deterministic: the library version in composer.lock is the one that runs on the site.
  • 📦 Smaller ZIP: 28% less dependency code, vendor/ no longer shipped.
  • 🤖 No extra build step: it is part of composer install. Add a dependency, run composer install, commit packages/.
  • 🔍 CI-verified: drift between composer.lock and packages/ fails the build.

🔍 Demo – how it works in wp-sms

✅ Tested

$ composer install     # wp-scoper: 4 packages, 39 files prefixed, 1 call site updated
$ composer install     # second run: no changes in packages/ or inc/ (idempotent)
$ composer test
OK (34 tests, 47 assertions)
$ php -l on packages/, inc/, wp-parsidate.php   # no syntax errors

Run locally on PHP 8.0, where array_is_list() and json_validate() are not native, so the test also proves the prefixed polyfills are loaded correctly.

📝 Notes

  • wp-scoper prefixes three define() constants inside the polyfill bootstrap files (FILTER_VALIDATE_BOOL, MYSQLI_REFRESH_REPLICA, CURLOPT_ISSUERCERT_BLOB). The plugin does not use any of them; polyfilled functions are not renamed and keep working.
  • The diff looks large because of the vendor/ → packages/ move; GitHub shows most of it as renames. The hand-written changes are in composer.json, wp-parsidate.php, inc/Helper/Sanitizing.php, .gitignore, .distignore, the two workflows, README and the new test.

@mostafasoufi mostafasoufi changed the title 🛡️ Prefix Composer dependencies with wp-scoper (no more class conflicts with other plugins) Prefix Composer dependencies with wp-scoper (no more class conflicts with other plugins) Sep 13, 2026
@mostafasoufi
mostafasoufi force-pushed the feat/wp-scoper branch 2 times, most recently from 96c5a49 to 6333e8d Compare September 13, 2026 07:18
@mostafasoufi
mostafasoufi force-pushed the feat/ci-cd-tests-deploy branch from c211907 to c812909 Compare September 13, 2026 07:23
Mostafa Soufi added 2 commits September 13, 2026 11:23
…ther plugins

- Add veronalabs/wp-scoper as a dev dependency and configure it in
  composer.json. On composer install it copies enshrined/svg-sanitize and
  the Symfony polyfills into packages/ under the WPParsidate\Dependencies
  namespace and generates packages/autoload.php.
- Load packages/autoload.php (plus inc/Functions/*.php) from the main
  plugin file instead of vendor/autoload.php, so vendor/ is no longer
  needed at runtime.
- Commit packages/, git-ignore vendor/ and exclude it from the release ZIP.
- Update the SVG sanitizer call site to the prefixed namespace.
- Add a CI job that fails when packages/ does not match composer.lock, and
  tests that verify dependencies load from packages/ and polyfilled
  functions are available.
… lint job

- Pin config.platform.php to 7.4 so composer.lock only contains packages
  that install on the plugin's minimum PHP version.
- Exclude packages/ from the php -l job: it is vendored code and
  polyfill-php83/bootstrap81.php intentionally uses PHP 8.1 syntax (it is
  only loaded on PHP >= 8.1).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant