From 5e362fe925702a4a6bd1785a54296ff7d64484da Mon Sep 17 00:00:00 2001 From: Jonathan Miller Date: Sun, 12 Jul 2026 15:24:11 -0500 Subject: [PATCH] fix: pre-update backup fires on Joomla Update (match layout=update) The 'Install the update' button posts to option=com_joomlaupdate&layout=update (Joomla's confirm/updating page), carrying only layout=update -- no view, no task. The redirect matched view=update / update.install, so it never fired on the Joomla Update page. Match layout=update (plus view=update and legacy update.install), and return the browser to the same layout flagged is_backed_up=1. Claude-Session: https://claude.ai/code/session_01WbGBN9VyRK61zczYWcCQ2i --- CHANGELOG.md | 3 +++ .../src/Extension/MokoSuiteBackup.php | 21 ++++++++++++------- 2 files changed, 16 insertions(+), 8 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f6bae101..105fd151 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,9 @@ ## [Unreleased] +### Fixed +- 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 API** — `POST /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 skipped if a backup already ran this session. diff --git a/source/packages/plg_system_mokosuitebackup/src/Extension/MokoSuiteBackup.php b/source/packages/plg_system_mokosuitebackup/src/Extension/MokoSuiteBackup.php index 0782c17a..ce47e68d 100644 --- a/source/packages/plg_system_mokosuitebackup/src/Extension/MokoSuiteBackup.php +++ b/source/packages/plg_system_mokosuitebackup/src/Extension/MokoSuiteBackup.php @@ -253,15 +253,18 @@ final class MokoSuiteBackup extends CMSPlugin implements SubscriberInterface return; } - $app = $this->getApplication(); - $input = $app->getInput(); - $view = $input->getCmd('view', ''); - $task = $input->getCmd('task', ''); + $app = $this->getApplication(); + $input = $app->getInput(); + $view = $input->getCmd('view', ''); + $task = $input->getCmd('task', ''); + $layout = $input->getCmd('layout', ''); - // Joomla 4/5/6 updating page (before its JS extracts), or the legacy - // Joomla 3 install task. + // The "Install the update" click posts to option=com_joomlaupdate& + // layout=update — the confirm/updating page, which is where the JS then + // downloads + extracts. (Some flows use view=update; Joomla 3 used + // task=update.install.) Intercept whichever fires — before files change. if ($input->getCmd('option', '') !== 'com_joomlaupdate' - || ($view !== 'update' && $task !== 'update.install')) { + || ($layout !== 'update' && $view !== 'update' && $task !== 'update.install')) { return; } @@ -298,7 +301,9 @@ final class MokoSuiteBackup extends CMSPlugin implements SubscriberInterface $returnUri = new Uri(Uri::base() . 'index.php'); $returnUri->setVar('option', 'com_joomlaupdate'); - if ($view === 'update') { + if ($layout === 'update') { + $returnUri->setVar('layout', 'update'); + } elseif ($view === 'update') { $returnUri->setVar('view', 'update'); } else { $returnUri->setVar('task', $task);