Files
2026-07-13 09:51:34 +00:00

8.7 KiB

Changelog

[Unreleased]

[02.63.00] --- 2026-07-13

[02.62.00] --- 2026-07-13

[02.61.00] --- 2026-07-13

[02.60.00] --- 2026-07-12

[02.59.00] --- 2026-07-12

Fixed

  • Pre-update backup now fires for every extension update/uninstall, not just the first one in a 10-minute window. A coarse 600-second session throttle (armed after any pre-action backup — even after updating MokoSuiteBackup itself or a core Joomla update) was disabling the client-side interceptor and the server-side fallback for all extensions for 10 minutes, so distinct updates silently went un-backed-up (looked like "only the backup extension triggers it"). Replaced with one backup per Update action: a single batch/click still backs up once (deduped per-request), the client re-fire is skipped via a one-shot action-keyed flag (consumed once), and the core-update path uses its own dedicated key so it no longer suppresses extension backups.
  • Pre-update backup on the Joomla Update page is now seamless (Akeeba-style): after the full-screen backup runs, the plugin auto-ticks Joomla's "I have taken a backup" checkbox and clicks Install, so the update continues automatically instead of stopping for a second manual click.
  • Pre-update full-screen backup now actually fires on the Joomla Update page. The "Install the update" button posts to option=com_joomlaupdate&layout=update (Joomla's confirm/updating page) — carrying only layout=update, no view/task — so the previous match on view=update/update.install never triggered. The plugin now intercepts layout=update (as well as view=update and the legacy update.install) and returns the browser there flagged is_backed_up=1.

Added

  • Snapshot transfer + master→slave injection (#237): download a content snapshot as a portable .msbsnap file (zip of manifest.json + snapshot.json + a sha256 integrity check); import one on another site via a new Import button on the Snapshots page (materialises a local snapshot record you can then restore); and a direct injection APIPOST /api/index.php/v1/mokosuitebackup/snapshot/inject — so a master site can push a snapshot straight into a slave's Web Services API. Two conflict modes ship now: overwrite (replace matching items by ID — master wins) and create (skip existing, add only new), selectable per inject call or defaulted in Options → Snapshot Transfer. A receiving site must opt in via the new Allow Snapshot Injection setting. A third duplicate mode inserts everything as brand-new records with remapped IDs (articles, categories, modules — plus their tags, custom-field values and featured flags) using Joomla's Table API so assets/UCM/nested-sets stay valid; each item is inserted defensively (a bad item is skipped and logged, never fatal).
  • Full-screen backup now also fronts extension updates and uninstalls (Extensions → Update / Manage), not just core Joomla updates. Because com_installer's update.update / manage.remove are POST actions (CSRF token + a checked cid[] list) that a server-side redirect can't cleanly resume, this is done client-side: the toolbar Update/Uninstall click is intercepted, the selection is captured, the full-screen backup runs, and on return the original selection is restored and the real POST form is re-submitted. Gated by backup_before_update / backup_before_uninstall, super-user only, and deduped to one backup per Update action.
  • Manual "Backup Now" completion now offers a View backup record button (links straight to the record that was just created). It appears only for manual backups — the pre-update / pre-uninstall flow hands control back to Joomla instead.
  • Full-screen backup screen (view=runbackup) for both pre-update and manual backups, modelled on Akeeba's Backup-on-Update — replaces the earlier popup-modal approach. Clicking Joomla's Install the update now redirects (server-side, Akeeba-style) to a dedicated full-page backup screen that runs the stepped backup with a real progress bar and then automatically continues the update via a validated returnurl (flagged is_backed_up=1 so the backup isn't repeated). Crucially, no backup runs synchronously inside the update request — which is what white-screened large sites. The dashboard Backup Now now opens the same full-screen screen instead of an inline modal. (#196)
  • Retention now prunes remote copies too: when a backup is pruned by age/count, its archive is deleted from every enabled remote destination (SFTP / FTP / S3 / Google Drive), not just the local copy. Each uploader gained an idempotent delete() method (already-absent file = success), and removal is best-effort — a failing destination is logged but never blocks local pruning. The shared standalone restore.php is intentionally left in place (every backup overwrites it, so newer backups still depend on it). (#229)

Changed

  • Consolidated backup plumbing into shared helpers (#230):
    • New RemoteUploaderFactory replaces the createUploaderFromParams() copy that was duplicated in BackupEngine and SteppedBackupEngine.
    • RetentionManager is now the single retention authority — it takes the global max_age_days/max_backups fallback and gained pruneOrphans(); the system plugin's hourly cleanup delegates to it and its duplicate deleteBackupRecord() logic is removed.
    • The backend controller, Web Services API controller, and legacy cli/mokosuitebackup.php now run backups through the shared BackupRunner (gaining the normalized complete/warning/fail status) instead of instantiating BackupEngine directly.

Fixed

  • Package installer is now honest about success: the postflight no longer prints "installed successfully" / next-steps when the install actually failed or only partially completed. Joomla logs a failed child extension but still runs the package postflight, so the postflight now (a) verifies every bundled child declared in the manifest actually registered in #__extensions (matched by element + type, and folder/group for plugins) and (b) verifies the component's schema tables — derived dynamically from the installed install.mysql.sql — actually exist. If anything is missing it enqueues an error listing what's missing and stops before the success message. Fail-open: any manifest/DB/IO glitch is treated as "nothing missing" so a transient error never turns a good install into a false failure. Unconditional housekeeping (e.g. download-key restore) still runs regardless.
  • Pre-update full-screen backup screen now actually triggers on Joomla 6 (and 4/5). The redirect matched only the legacy update.install task, which Joomla 4/5/6 don't use — they server-side-redirect to the updating page view=update, which then extracts the downloaded package from JavaScript. The plugin now intercepts the view=update page load (the last point before any files change) and returns the browser there flagged is_backed_up=1 so the extraction proceeds after the backup. (update.finalise is intentionally not intercepted — by then the files are already extracted.)
  • Pre-update/uninstall backup no longer white-screens the update on large sites. The synchronous backup that runs inside the extension update/uninstall request now raises max_execution_time/memory_limit (and ignore_user_abort) like the web-cron path, so it can't exhaust the request's default limits mid-backup. (Core Joomla updates additionally get a full-screen backup screen — see below.)
  • Archive names for CLI/console-triggered backups no longer come out as joomla.invalid_…. The [HOST] placeholder took $_SERVER['HTTP_HOST'] verbatim, but Joomla's console fills that with the reserved sentinel host joomla.invalid; the resolver now treats that (like empty/localhost) as unusable and falls back to the configured live_site host, then the system hostname. (Set the site's live_site to get the exact domain in CLI-built names.)
  • Standalone restore script generation no longer aborts backups with str_replace() expects at least 3 arguments, 2 given. MokoRestore::generateStandaloneScript() had a str_replace() call (the "Backup Archive" pre-check rewrite) that was missing its $php subject argument, so every standalone-mode backup fatally errored while "Generating standalone restore.php…" — the archive still finalized and uploaded, but no restore.php was ever produced (the true root cause behind #226). (#226)
  • Remote upload: the standalone restore script upload is no longer silent — its result is now checked and logged, and a failed restore-script upload marks the backup as warning (previously the result was discarded, so a missing restore script on the remote went unreported while the archive still showed success). (#226)