Skip to content

v0.31.10.0 — Critical Module Deletion Fix

Choose a tag to compare

@bertugfahriozer bertugfahriozer released this 23 May 19:41
· 22 commits to master since this release

This release ships a critical data-loss fix in the module uninstall pipeline along with sitemap correctness fixes, CSRF token-sync repairs, and several frontend cleanups. All ci4ms deployments should upgrade — prior versions would wipe the entire database when uninstalling a single module due to a misuse of CodeIgniter 4's MigrationRunner::regress() API.

⚠️ Critical

  • Single Module Deletion Wiped Entire Database. ModuleInstaller::rollbackModuleMigrations() called MigrationRunner::regress(0) after setNamespace(), expecting namespace-scoped rollback. CI4's regress() nulls $this->namespace internally and walks the full migration history, so uninstalling any module would down every registered module's migrations and drop the entire database. The rollback path now iterates only the target module's namespace history and calls force() per migration in reverse order, with a finally block that resets the shared runner singleton.

🛠️ Fixed

  • Sitemap URL Duplication. BlogModel and PagesModel sitemap entries returned fully-qualified URLs via site_url() while ci4seopro\SitemapBuilder prepends baseUrl, producing malformed <loc>https://hosthttps://host/...</loc> values. Models now return path-only loc values, matching the package contract.
  • Sitemap Multilingual Coverage. Both sitemap models now LEFT JOIN their *_langs tables so localized records are included instead of being filtered out by the primary-table-only query.
  • Backend CSRF Hidden Input Stale. setCsrfHash() now syncs every csrf_field() hidden input on the page after token regeneration; non-AJAX form submissions following an AJAX request no longer hit 403 Forbidden.
  • Backend CSRF Empty-Body POSTs. ajaxPrefilter writes a pre-encoded URL string for empty POST bodies instead of building an object that jQuery would later re-serialize back to empty, stripping the token from the request.
  • Frontend Captcha Auto-Fire. captchaF() no longer issues a POST /commentCaptcha on every public page load; the bootstrap is now gated on the presence of .captcha markup.
  • Methods Update View — Broken Route. Back-to-list link now resolves to the correct methodList route alias (was list, which does not exist).
  • Methods Update View — Checkbox Active State. inNavigation, isBackoffice, and hasChild flags now render correctly checked for existing records; added (bool) casts to compare integer storage (1 / 0) against strict boolean equality.

♻️ Changed

  • elFinder Dialog Reuse. pageImgelfinderDialog() and pageMultipleImgelfinderDialog() cache and reopen their existing jQuery wrapper instead of rebuilding the dialog on every invocation. Eliminates leaked event handlers, redundant cssAutoLoad HTTP requests, and the per-second sync exception when polling a destroyed instance (now wrapped in try/catch).
  • Captcha Refresh Trigger. Refresh button migrated from inline onclick="captchaF()" to a .captcha-refresh class bound via the existing delegated handler inside captchaF() — cleaner markup/behavior separation.

➕ Added

  • .gitignore Entries. CLAUDE.md and ci4ms-specs/ are now excluded so per-developer agent tooling artifacts stay out of version control.

⬆️ Upgrade Notes

  1. Pull the new release; no schema migration is required for the framework itself.
  2. Run php spark cache:clear after deploying so the cached settings, menu, and permission entries pick up the new app.version.
  3. The app.version value in your existing .env is not rewritten automatically — bump it to 0.31.10.0 manually if you rely on that key (the installer and ci4ms:setup CLI command already use the new value for fresh installations).
  4. Before uninstalling any module on a pre-0.31.10.0 deployment, take a full database backup — the legacy code path is destructive. After upgrading, module uninstall is safe and properly scoped.
  5. If you maintain a fork or downstream module pipeline that touched MigrationRunner::regress(0), audit it for the same antipattern — the framework method does not honor setNamespace().

Full changelog: 0.31.9.0...0.31.10.0