2
Pre-Update-Backup
Jonathan Miller edited this page 2026-07-15 01:17:05 +00:00

Pre-Update Backup (Full-Screen)

Applies to MokoSuiteBackup 02.64.00.

MokoSuiteBackup can automatically run a full-screen backup before Joomla changes anything — before a Joomla core update, before an extension update, and before an extension uninstall. The backup runs on its own dedicated full-page screen (modelled on Akeeba's Backup-on-Update), shows a real progress bar, and then hands control back to Joomla so the original action continues.

The design goal is safety without white-screens: no backup ever runs synchronously inside the update request on the core-update path. Running a large-site backup inside the update request is exactly what white-screened sites in earlier approaches, so the core-update flow always redirects to the standalone backup screen first.

Turning it on

Configure under Components → MokoSuiteBackup → Options → Pre-Action (com_mokosuitebackup component options):

Option Param Default Covers
Backup before update backup_before_update No Joomla core updates and extension updates
Backup before uninstall backup_before_uninstall No Extension uninstalls (Extensions → Manage)

The backup runs with the component's default profile (default_profile, defaults to profile 1).

Both features are Super User only — the interception and the redirect are gated on core.admin. A non-super-user updating an extension is never intercepted.

One backup per Update action (not a time throttle)

A pre-action backup fires once per Update/Uninstall action, not on a timer.

Earlier builds used a coarse 600-second (10-minute) session throttle. That throttle armed after any pre-action backup — including after updating MokoSuiteBackup itself or after a core Joomla update — and then disabled both the client-side interceptor and the server-side fallback for every extension for 10 minutes, so distinct updates silently went un-backed-up. That is fixed in 02.59.00+:

  • Per-request dedupe — a batch update fires the handler once per extension, all in the same request, so the synchronous fallback backs up only once per request (preactionRan guard).
  • One-shot skip flag — when the full-screen backup already ran, its completion posts ajax.preupdateAck, which sets a session skip flag that is consumed once. The re-fired update/uninstall then skips the duplicate backup, but the next distinct action backs up again.
  • Dedicated core-update key — the core-update path uses its own session key (mokosuitebackup.core_update_backed_up), so it no longer suppresses extension backups (a core update never fires onExtensionBeforeUpdate).

How it works — Joomla core updates (server-side, seamless)

For a core update the plugin intercepts server-side in onAfterRoute (maybeRedirectForUpdate), before com_joomlaupdate renders the page:

  1. The "Install the update" click posts to option=com_joomlaupdate&layout=update (Joomla 4/5/6's confirm/updating page, which then extracts the downloaded package from JavaScript). The plugin matches layout=update (and also the legacy view=update / task=update.install) — the last moment before any files change.
  2. It redirects the browser to the full-screen backup screen (option=com_mokosuitebackup&view=runbackup&tmpl=component&autostart=1) with a validated returnurl back to the same update page, flagged is_backed_up=1.
  3. The backup runs on its own page. On completion the browser returns to layout=update&is_backed_up=1.
  4. On return, onBeforeCompileHead injects a small script that auto-ticks Joomla's "I have taken a backup" checkbox and clicks Install — so the update continues automatically (Akeeba-style), instead of stopping for a second manual click.

update.finalise is deliberately not intercepted — by then the files are already extracted, so a pre-update backup would be too late.

How it works — extension updates / uninstalls (client-side)

com_installer's update.update and manage.remove / manage.uninstall are POST actions carrying a CSRF token and a checked cid[] list — a server-side GET redirect can't cleanly resume them. So this path is handled client-side by media/plg_system_mokosuitebackup/js/installer-backup.js, injected on Extensions → Update and Extensions → Manage (onBeforeCompileHead).

In Joomla 6 the toolbar buttons are web components (<button task="update.update">), not inline onclick, so the script uses a capture-phase click listener on any element carrying a matching task attribute — it runs before the toolbar's own handler:

  1. Intercept the Update/Uninstall click in the capture phase. If nothing is selected (cid[]), it does nothing and lets Joomla show its own "please select" notice.
  2. Capture the checked cid[] selection into sessionStorage, build a validated returnurl (base64, UTF-8 safe) back to the current page with msb_resume=1, and send the browser to the full-screen backup screen (view=runbackup) with msb_action=update|uninstall.
  3. The backup runs on its own page. On completion it posts ajax.preupdateAck for that action (arming the one-shot skip), then returns to the original page with msb_resume=1.
  4. Resume — the script restores the checked cid[] selection, sets window.__msbResuming so the interceptor doesn't re-fire, and re-fires the real toolbar action so the update POST proceeds. Two Joomla-6 details matter here (both fixed in 02.63.x): the task attribute is on the outer <joomla-toolbar-button> but the click handler is bound to the inner <button>, so the script clicks the inner element; and a list-selection toolbar button starts disabled until boxchecked fires a change event, so the script dispatches that event before re-firing. While the re-fired update POST runs, a full-screen "the update is now running — please wait" overlay is shown so the admin knows it is working.

If the redirect can't be built (e.g. btoa() fails on non-Latin1 input), the script bails without preventing the click, so Joomla's own update/uninstall proceeds normally.

A server-side fallback (onExtensionBeforeUpdate / onExtensionBeforeUninstall) still exists for the extension path. When it does run synchronously, it raises max_execution_time / memory_limit and sets ignore_user_abort(true) (mirroring the web-cron path) so a large-site backup can't exhaust the request's limits mid-backup. The one-shot skip flag prevents this fallback from duplicating the client-side backup.

The full-screen backup screen

view=runbackup (Runbackup\HtmlView + tmpl/runbackup/default.php) is the shared full-page screen used by both the pre-action flow and the dashboard Backup Now:

  • Auto-starts the stepped backup over AJAX (ajax.init → looped ajax.step) with a full-bleed, Atum-coloured progress bar on a black backdrop.
  • While the backup runs it shows a prominent "do not close this window or switch to another window until the backup finishes" warning, plus a Cancel button. Cancelling requires a double confirmation; on confirm it stops the stepped loop, best-effort cancels the record server-side (ajax.cancelBackup), and returns to the dashboard without continuing any pending update. A beforeunload prompt also fires if you try to close/navigate away mid-backup.
  • The returnurl is validated in the layout to block open-redirect / javascript: XSS: it accepts only an absolute http(s) URL whose host matches this site, or a single-slash root-relative path; backslashes/control chars and protocol-relative //host are rejected. An invalid value falls back to no redirect.
  • Pre-action flow (a returnurl is present): the screen shows an "Automatically continue the update when the backup finishes" checkbox, ticked by default. On completion it posts ajax.preupdateAck (arming the one-shot skip), then:
    • checked → hands straight back to Joomla and the update continues seamlessly;
    • unticked → stops on a completion panel offering a View backup record link (opens in a new window) and a Continue the update button, so you hand back manually when ready.
  • Manual Backup Now (no returnurl): on completion it shows a View backup record button (linking to the record just created) and Back to dashboard.
  • On failure the update is blocked. In the pre-action flow a failed backup offers only Retry (re-run the backup) or Back to dashboard — there is intentionally no "continue without backup", so a broken backup can never let the update proceed unprotected. (The manual Backup Now flow just offers Retry.)

Notifications

Every pre-action backup surfaces its outcome in the admin as an enqueued message — success, warning, or failure — so a successful pre-update backup is visible (earlier builds only messaged on failure).