CPalius CMF 2.2.11
Released: 2026-09-25 · Channel: stable · Critical: yes
Deleting a module's files by hand (instead of deactivating it first) could take down unrelated pages, and a query-budget guard was tripping on pages that had nothing to do with the feature it was protecting. Both traced back to the same root pattern: several places read the same piece of state independently instead of through the one path built to be safe, so a fix applied to one of them left the others exposed. This release closes both.
What's fixed
Deleting a module's files without deactivating it first could crash unrelated pages instead of being safely ignored. The module health check trusted PHP's class_exists() to tell it whether a module's code was still there. Under composer install --optimize-autoloader (what every packaged release runs), class_exists() reads a static classmap generated once, not the actual filesystem — so it kept reporting a deleted module's class as present long after the files were gone, only failing later and uncaught, the moment something actually tried to use it (a template rendering that module's views, a class another module still referenced directly). The check now verifies the file is actually on disk first. A module whose files are removed by hand is now quarantined immediately and cleanly, the same as any other broken module, instead of crashing whatever page happens to touch it next.
The Forum module rendered every post through a class that lived in the Importer module. Forum's post-rendering path called Importer's BBCode-cleanup converter unconditionally, on every post, regardless of whether that post was ever imported — a permanent, undeclared runtime dependency on a module Forum's own manifest never listed as required (Importer already declares Forum as a dependency; the reverse was never supposed to exist). Forum posts stopped rendering entirely if Importer was ever removed. The converter now lives in Forum itself; Importer references Forum's copy, matching the dependency direction already declared in Importer's own manifest.
A shared per-request query budget was being spent by code that didn't check whether anyone had already asked. Seven separate places — four AACP dashboard widgets, the two listeners that read and write the origin cache on every request, and the Varnish response header listener — each queried the same performance-backend-status table independently instead of sharing the one request-scoped lookup already built for exactly this. On a single request touching more than a couple of these, the combined query count could exceed the safety budget meant to catch runaway lazy-loading elsewhere, and the failure surfaced on whatever ran last — most often the origin cache write, silently, with no visible error to the visitor. All seven now share one lookup per request.
Upgrade notes
No schema changes. No manual steps.
Known limitations
This does not, on its own, repair a production install where a module was already deleted with an old build's classmap still in place — regenerating that classmap requires either restoring the deleted files temporarily or applying this update through a path that replaces cp-includes/vendor (a full-release update, not a hand-copied file). See the upgrade guidance that accompanied this release for your specific situation.