diff --git a/source/packages/com_mokosuitebackup/mokosuitebackup.xml b/source/packages/com_mokosuitebackup/mokosuitebackup.xml index 76d0579..4efcd62 100644 --- a/source/packages/com_mokosuitebackup/mokosuitebackup.xml +++ b/source/packages/com_mokosuitebackup/mokosuitebackup.xml @@ -39,6 +39,15 @@ COM_MOKOJOOMBACKUP + COM_MOKOJOOMBACKUP_SUBMENU_DASHBOARD + COM_MOKOJOOMBACKUP_SUBMENU_BACKUPS + COM_MOKOJOOMBACKUP_SUBMENU_PROFILES cli diff --git a/source/script.php b/source/script.php index e5a044c..3c79849 100644 --- a/source/script.php +++ b/source/script.php @@ -206,6 +206,9 @@ class Pkg_MokoSuiteBackupInstallerScript return; } + // Ensure submenu items exist (Joomla only creates them on fresh install) + $this->ensureSubmenuItems(); + // Sync submenu icons in #__menu (Joomla doesn't update icons on upgrades) $this->syncMenuIcons(); @@ -327,6 +330,109 @@ class Pkg_MokoSuiteBackupInstallerScript } } + /** + * Ensure admin submenu items exist in #__menu. + * + * On updates Joomla does not re-create submenu entries from the manifest, + * so we use the Installer's own _buildAdminMenus pathway via the + * component's MenuTable API to create any missing items. + */ + private function ensureSubmenuItems(): void + { + $submenus = [ + [ + 'link' => 'index.php?option=com_mokosuitebackup&view=dashboard', + 'title' => 'COM_MOKOJOOMBACKUP_SUBMENU_DASHBOARD', + 'img' => 'class:home', + ], + [ + 'link' => 'index.php?option=com_mokosuitebackup&view=backups', + 'title' => 'COM_MOKOJOOMBACKUP_SUBMENU_BACKUPS', + 'img' => 'class:database', + ], + [ + 'link' => 'index.php?option=com_mokosuitebackup&view=profiles', + 'title' => 'COM_MOKOJOOMBACKUP_SUBMENU_PROFILES', + 'img' => 'class:cog', + ], + ]; + + try { + $db = Factory::getDbo(); + + // Find the parent menu item for our component + $query = $db->getQuery(true) + ->select([$db->quoteName('id'), $db->quoteName('menutype')]) + ->from($db->quoteName('#__menu')) + ->where($db->quoteName('client_id') . ' = 1') + ->where($db->quoteName('level') . ' = 1') + ->where($db->quoteName('link') . ' LIKE ' . $db->quote('index.php?option=com_mokosuitebackup%')) + ->setLimit(1); + $db->setQuery($query); + $parent = $db->loadObject(); + + if (!$parent) { + return; + } + + // Get the component extension_id + $query = $db->getQuery(true) + ->select($db->quoteName('extension_id')) + ->from($db->quoteName('#__extensions')) + ->where($db->quoteName('element') . ' = ' . $db->quote('com_mokosuitebackup')) + ->where($db->quoteName('type') . ' = ' . $db->quote('component')) + ->setLimit(1); + $db->setQuery($query); + $componentId = (int) $db->loadResult(); + + if (!$componentId) { + return; + } + + foreach ($submenus as $submenu) { + // Check if this submenu item already exists + $query = $db->getQuery(true) + ->select('COUNT(*)') + ->from($db->quoteName('#__menu')) + ->where($db->quoteName('client_id') . ' = 1') + ->where($db->quoteName('link') . ' = ' . $db->quote($submenu['link'])); + $db->setQuery($query); + + if ((int) $db->loadResult() > 0) { + continue; + } + + // Use Joomla's MenuTable to create the item properly + $table = Factory::getApplication() + ->bootComponent('com_menus') + ->getMVCFactory() + ->createTable('Menu', 'Administrator'); + + $table->menutype = $parent->menutype; + $table->title = $submenu['title']; + $table->alias = strtolower(str_replace(' ', '-', $submenu['title'])); + $table->link = $submenu['link']; + $table->type = 'component'; + $table->published = 1; + $table->parent_id = $parent->id; + $table->level = 2; + $table->component_id = $componentId; + $table->client_id = 1; + $table->img = $submenu['img']; + $table->language = '*'; + $table->access = 1; + + $table->setLocation($parent->id, 'last-child'); + + if (!$table->check() || !$table->store()) { + error_log('MokoSuiteBackup: Failed to create submenu "' . $submenu['title'] . '": ' . $table->getError()); + } + } + } catch (\Throwable $e) { + error_log('MokoSuiteBackup: ensureSubmenuItems() failed: ' . $e->getMessage()); + } + } + private function syncMenuIcons(): void { $iconMap = [