From 1029e40908670b6267b785aae74e6c14a389288f Mon Sep 17 00:00:00 2001 From: Jonathan Miller Date: Sun, 5 Jul 2026 17:11:51 -0500 Subject: [PATCH 1/2] fix(installer): self-heal orphaned com_component-mokosuitebackup on update The old "Type - Name" component made Joomla register a duplicate component under element com_component-mokosuitebackup (its own extension row, admin menu, schema rows and administrator/ folder), orphaning the real com_mokosuitebackup on the old version. The manifest fix (#213) prevents new occurrences; this reconciles already-affected sites automatically. Package postflight now removes any component whose element matches %component%mokosuitebackup% (excluding com_mokosuitebackup): deletes its #__menu, #__schemas and #__update_sites_extensions rows, the #__extensions record, and the stray admin folder. Idempotent and non-fatal. Claude-Session: https://claude.ai/code/session_01WbGBN9VyRK61zczYWcCQ2i --- CHANGELOG.md | 3 ++ source/script.php | 106 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 109 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9792d5fa..9d05235a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,9 @@ # Changelog ## [Unreleased] +### Fixed +- Package `postflight` now removes the orphaned `com_component-mokosuitebackup` registration (stray extension record, admin menu items, schema rows, and `administrator/` folder) left behind by the old "Type - Name" component `` — self-healing on update so affected sites reconcile to the real `com_mokosuitebackup`. (#213 follow-up) + ## [02.56.08] --- 2026-07-05 ## [02.56.08] --- 2026-07-05 diff --git a/source/script.php b/source/script.php index ebf16d01..dbd12a54 100644 --- a/source/script.php +++ b/source/script.php @@ -172,6 +172,11 @@ class Pkg_MokoSuiteBackupInstallerScript /* Migrate profiles with old default backup_dir values to [DEFAULT_DIR] placeholder */ $this->migrateDefaultBackupDir(); + /* Remove the orphaned mis-registered component (element + com_component-mokosuitebackup) left behind when the component + briefly used the "Type - Name" convention. Self-healing on every update. */ + $this->removeOrphanedComponent(); + /* Install completion notice (install and update) */ $this->installSuccessful(); @@ -192,6 +197,107 @@ class Pkg_MokoSuiteBackupInstallerScript } } + /** + * Remove the orphaned component registration created when the component + * briefly used the "Type - Name" display convention. Joomla derives a + * component's element from its , so "Component - MokoSuiteBackup" + * produced element com_component-mokosuitebackup — its own extension record, + * admin menu items, schema rows and administrator/ folder — orphaning the real + * com_mokosuitebackup on the old version. This reconciles affected sites on + * update. Idempotent and non-fatal: does nothing when no orphan exists. + * + * @return void + */ + private function removeOrphanedComponent(): void + { + try { + $db = Factory::getDbo(); + + $query = $db->getQuery(true) + ->select($db->quoteName(['extension_id', 'element'])) + ->from($db->quoteName('#__extensions')) + ->where($db->quoteName('type') . ' = ' . $db->quote('component')) + ->where($db->quoteName('client_id') . ' = 1') + ->where($db->quoteName('element') . ' LIKE ' . $db->quote('%component%mokosuitebackup%')) + ->where($db->quoteName('element') . ' <> ' . $db->quote('com_mokosuitebackup')); + $db->setQuery($query); + $orphans = $db->loadObjectList(); + + if (empty($orphans)) { + return; + } + + foreach ($orphans as $orphan) { + $id = (int) $orphan->extension_id; + + /* Admin menu items owned by the orphan component */ + $db->setQuery( + $db->getQuery(true) + ->delete($db->quoteName('#__menu')) + ->where($db->quoteName('component_id') . ' = ' . $id) + )->execute(); + + /* Schema-version rows */ + $db->setQuery( + $db->getQuery(true) + ->delete($db->quoteName('#__schemas')) + ->where($db->quoteName('extension_id') . ' = ' . $id) + )->execute(); + + /* Update-site mapping (leave #__update_sites; harmless if orphaned) */ + $db->setQuery( + $db->getQuery(true) + ->delete($db->quoteName('#__update_sites_extensions')) + ->where($db->quoteName('extension_id') . ' = ' . $id) + )->execute(); + + /* The bogus extension record itself */ + $db->setQuery( + $db->getQuery(true) + ->delete($db->quoteName('#__extensions')) + ->where($db->quoteName('extension_id') . ' = ' . $id) + )->execute(); + + /* The stray admin component folder on disk */ + $this->deleteFolderRecursive(JPATH_ADMINISTRATOR . '/components/' . $orphan->element); + + Factory::getApplication()->enqueueMessage( + 'MokoSuiteBackup: removed orphaned component registration "' + . htmlspecialchars($orphan->element, ENT_QUOTES, 'UTF-8') . '".', + 'info' + ); + } + } catch (\Throwable $e) { + /* Never block the install/update over best-effort cleanup */ + Log::add('MokoSuiteBackup orphan-component cleanup failed: ' . $e->getMessage(), Log::WARNING, 'jerror'); + } + } + + /** + * Recursively delete a directory (version-independent, no Folder dependency). + * + * @param string $dir Absolute path + * + * @return void + */ + private function deleteFolderRecursive(string $dir): void + { + if ($dir === '' || !is_dir($dir)) { + return; + } + + $items = new \RecursiveIteratorIterator( + new \RecursiveDirectoryIterator($dir, \FilesystemIterator::SKIP_DOTS), + \RecursiveIteratorIterator::CHILD_FIRST + ); + + foreach ($items as $item) { + $item->isDir() ? @rmdir($item->getPathname()) : @unlink($item->getPathname()); + } + + @rmdir($dir); + } + /** * Generate a cryptographically random webcron secret word on fresh install. */ From 39d94a31d6ee3f1d4188841fb3a5973ffa756011 Mon Sep 17 00:00:00 2001 From: "mokogitea-actions[bot]" Date: Sun, 5 Jul 2026 22:14:22 +0000 Subject: [PATCH 2/2] chore(version): pre-release bump to 02.56.11-dev [skip ci] --- .mokogitea/workflows/issue-branch.yml | 2 +- SECURITY.md | 2 +- source/packages/com_mokosuitebackup/mokosuitebackup.xml | 2 +- .../packages/com_mokosuitebackup/sql/updates/mysql/02.56.11.sql | 1 + .../mod_mokosuitebackup_cpanel/mod_mokosuitebackup_cpanel.xml | 2 +- .../packages/plg_actionlog_mokosuitebackup/mokosuitebackup.xml | 2 +- source/packages/plg_console_mokosuitebackup/mokosuitebackup.xml | 2 +- source/packages/plg_content_mokosuitebackup/mokosuitebackup.xml | 2 +- .../packages/plg_quickicon_mokosuitebackup/mokosuitebackup.xml | 2 +- source/packages/plg_system_mokosuitebackup/mokosuitebackup.xml | 2 +- source/packages/plg_task_mokosuitebackup/mokosuitebackup.xml | 2 +- .../plg_webservices_mokosuitebackup/mokosuitebackup.xml | 2 +- source/pkg_mokosuitebackup.xml | 2 +- 13 files changed, 13 insertions(+), 12 deletions(-) create mode 100644 source/packages/com_mokosuitebackup/sql/updates/mysql/02.56.11.sql diff --git a/.mokogitea/workflows/issue-branch.yml b/.mokogitea/workflows/issue-branch.yml index 5c613bdb..0a619b94 100644 --- a/.mokogitea/workflows/issue-branch.yml +++ b/.mokogitea/workflows/issue-branch.yml @@ -5,7 +5,7 @@ # FILE INFORMATION # DEFGROUP: MokoGitea.Workflow # INGROUP: mokocli.Automation -# VERSION: 02.56.08 +# VERSION: 02.56.11 # BRIEF: Auto-create feature branch when an issue is opened name: "Universal: Issue Branch" diff --git a/SECURITY.md b/SECURITY.md index f4be5c2f..6fe43d08 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -23,7 +23,7 @@ DEFGROUP: Template-Joomla INGROUP: Template-Joomla.Documentation REPO: https://git.mokoconsulting.tech/MokoConsulting/Template-Joomla PATH: /SECURITY.md -VERSION: 02.56.08 +VERSION: 02.56.11 BRIEF: Security vulnerability reporting and handling policy --> diff --git a/source/packages/com_mokosuitebackup/mokosuitebackup.xml b/source/packages/com_mokosuitebackup/mokosuitebackup.xml index fd913205..1958f4ed 100644 --- a/source/packages/com_mokosuitebackup/mokosuitebackup.xml +++ b/source/packages/com_mokosuitebackup/mokosuitebackup.xml @@ -17,7 +17,7 @@ display label there. --> MokoSuiteBackup - 02.56.08 + 02.56.11 2026-06-02 Moko Consulting hello@mokoconsulting.tech diff --git a/source/packages/com_mokosuitebackup/sql/updates/mysql/02.56.11.sql b/source/packages/com_mokosuitebackup/sql/updates/mysql/02.56.11.sql new file mode 100644 index 00000000..2efa9c33 --- /dev/null +++ b/source/packages/com_mokosuitebackup/sql/updates/mysql/02.56.11.sql @@ -0,0 +1 @@ +/* 02.56.11 — no schema changes */ diff --git a/source/packages/mod_mokosuitebackup_cpanel/mod_mokosuitebackup_cpanel.xml b/source/packages/mod_mokosuitebackup_cpanel/mod_mokosuitebackup_cpanel.xml index 0eff09e4..69e52ca7 100644 --- a/source/packages/mod_mokosuitebackup_cpanel/mod_mokosuitebackup_cpanel.xml +++ b/source/packages/mod_mokosuitebackup_cpanel/mod_mokosuitebackup_cpanel.xml @@ -8,7 +8,7 @@ --> Module - MokoSuiteBackup - cPanel - 02.56.08 + 02.56.11 2026-06-23 Moko Consulting hello@mokoconsulting.tech diff --git a/source/packages/plg_actionlog_mokosuitebackup/mokosuitebackup.xml b/source/packages/plg_actionlog_mokosuitebackup/mokosuitebackup.xml index 2cb6fe13..87a9629e 100644 --- a/source/packages/plg_actionlog_mokosuitebackup/mokosuitebackup.xml +++ b/source/packages/plg_actionlog_mokosuitebackup/mokosuitebackup.xml @@ -7,7 +7,7 @@ --> Action Log - MokoSuiteBackup - 02.56.08 + 02.56.11 2026-06-04 Moko Consulting hello@mokoconsulting.tech diff --git a/source/packages/plg_console_mokosuitebackup/mokosuitebackup.xml b/source/packages/plg_console_mokosuitebackup/mokosuitebackup.xml index d3467ed2..f3c89007 100644 --- a/source/packages/plg_console_mokosuitebackup/mokosuitebackup.xml +++ b/source/packages/plg_console_mokosuitebackup/mokosuitebackup.xml @@ -7,7 +7,7 @@ --> Console - MokoSuiteBackup - 02.56.08 + 02.56.11 2026-06-04 Moko Consulting hello@mokoconsulting.tech diff --git a/source/packages/plg_content_mokosuitebackup/mokosuitebackup.xml b/source/packages/plg_content_mokosuitebackup/mokosuitebackup.xml index 4bcb8eaa..6f5f5e4e 100644 --- a/source/packages/plg_content_mokosuitebackup/mokosuitebackup.xml +++ b/source/packages/plg_content_mokosuitebackup/mokosuitebackup.xml @@ -7,7 +7,7 @@ --> Content - MokoSuiteBackup - 02.56.08 + 02.56.11 2026-06-04 Moko Consulting hello@mokoconsulting.tech diff --git a/source/packages/plg_quickicon_mokosuitebackup/mokosuitebackup.xml b/source/packages/plg_quickicon_mokosuitebackup/mokosuitebackup.xml index 9b244efd..449adfda 100644 --- a/source/packages/plg_quickicon_mokosuitebackup/mokosuitebackup.xml +++ b/source/packages/plg_quickicon_mokosuitebackup/mokosuitebackup.xml @@ -1,7 +1,7 @@ Quick Icon - MokoSuiteBackup - 02.56.08 + 02.56.11 2026-06-02 Moko Consulting hello@mokoconsulting.tech diff --git a/source/packages/plg_system_mokosuitebackup/mokosuitebackup.xml b/source/packages/plg_system_mokosuitebackup/mokosuitebackup.xml index 7189b8af..95a1128d 100644 --- a/source/packages/plg_system_mokosuitebackup/mokosuitebackup.xml +++ b/source/packages/plg_system_mokosuitebackup/mokosuitebackup.xml @@ -7,7 +7,7 @@ --> System - MokoSuiteBackup - 02.56.08 + 02.56.11 2026-06-02 Moko Consulting hello@mokoconsulting.tech diff --git a/source/packages/plg_task_mokosuitebackup/mokosuitebackup.xml b/source/packages/plg_task_mokosuitebackup/mokosuitebackup.xml index 20cb8eed..5ec8d01e 100644 --- a/source/packages/plg_task_mokosuitebackup/mokosuitebackup.xml +++ b/source/packages/plg_task_mokosuitebackup/mokosuitebackup.xml @@ -7,7 +7,7 @@ --> Task - MokoSuiteBackup - 02.56.08 + 02.56.11 2026-06-02 Moko Consulting hello@mokoconsulting.tech diff --git a/source/packages/plg_webservices_mokosuitebackup/mokosuitebackup.xml b/source/packages/plg_webservices_mokosuitebackup/mokosuitebackup.xml index 50a9860e..c46c9d0b 100644 --- a/source/packages/plg_webservices_mokosuitebackup/mokosuitebackup.xml +++ b/source/packages/plg_webservices_mokosuitebackup/mokosuitebackup.xml @@ -7,7 +7,7 @@ --> Web Services - MokoSuiteBackup - 02.56.08 + 02.56.11 2026-06-02 Moko Consulting hello@mokoconsulting.tech diff --git a/source/pkg_mokosuitebackup.xml b/source/pkg_mokosuitebackup.xml index 2105b087..d71a757e 100644 --- a/source/pkg_mokosuitebackup.xml +++ b/source/pkg_mokosuitebackup.xml @@ -8,7 +8,7 @@ Package - MokoSuiteBackup mokosuitebackup - 02.56.08 + 02.56.11 2026-06-02 Moko Consulting hello@mokoconsulting.tech