fix: use Joomla ModuleModel::save() for admin module setup
Generic: Repo Health / Site Health (push) Has been skipped
Generic: Repo Health / Site Health (pull_request) Has been skipped
Generic: Repo Health / Access control (push) Successful in 1s
Universal: PR Check / Branch Policy (pull_request) Successful in 1s
Generic: Repo Health / Access control (pull_request) Successful in 1s
Universal: Secret Scanning / Gitleaks Secret Scan (pull_request) Successful in 6s
Universal: Auto Version Bump / Version Bump (push) Successful in 11s
Universal: PR Check / Validate PR (pull_request) Failing after 13s
Universal: Pre-Release / Build Pre-Release (${{ inputs.stability || github.ref_name }}) (push) Successful in 19s
Platform: moko-platform CI / Gate 1: Code Quality (pull_request) Failing after 38s
Platform: moko-platform CI / Gate 1: Code Quality (push) Failing after 39s
Platform: moko-platform CI / Gate 2: Unit Tests (8.1) (push) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.2) (push) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.3) (push) Has been cancelled
Platform: moko-platform CI / Gate 3: Self-Health Check (push) Has been cancelled
Platform: moko-platform CI / Gate 4: Governance (push) Has been cancelled
Platform: moko-platform CI / Gate 5: Template Integrity (push) Has been cancelled
Platform: moko-platform CI / CI Summary (push) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.1) (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.2) (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 2: Unit Tests (8.3) (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 3: Self-Health Check (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 4: Governance (pull_request) Has been cancelled
Platform: moko-platform CI / Gate 5: Template Integrity (pull_request) Has been cancelled
Platform: moko-platform CI / CI Summary (pull_request) Has been cancelled
Generic: Repo Health / Scripts governance (push) Has been cancelled
Generic: Repo Health / Repository health (push) Has been cancelled
Generic: Repo Health / Report Issues (push) Has been cancelled
Universal: PR Check / Build RC Package (pull_request) Has been cancelled
Universal: PR Check / Report Issues (pull_request) Has been cancelled
Generic: Repo Health / Scripts governance (pull_request) Has been cancelled
Generic: Repo Health / Repository health (pull_request) Has been cancelled
Generic: Repo Health / Report Issues (pull_request) Has been cancelled

Replace raw DB queries with Joomla's ModuleModel to properly handle
module creation, position, published state, and #__modules_menu
assignment. Fixes modules not showing after install despite being
marked as published.

Also fix cpanel default collapsed state to 0 (expanded).
This commit is contained in:
Jonathan Miller
2026-06-09 12:11:10 -05:00
parent 61b01e3d7a
commit c676f0d5d8
2 changed files with 48 additions and 180 deletions
+47 -179
View File
@@ -944,219 +944,87 @@ class Pkg_MokosuiteInstallerScript
*/
private function setupCpanelModule(): void
{
try
{
$db = Factory::getDbo();
// Enable the module
$query = $db->getQuery(true)
->update($db->quoteName('#__extensions'))
->set($db->quoteName('enabled') . ' = 1')
->where($db->quoteName('type') . ' = ' . $db->quote('module'))
->where($db->quoteName('element') . ' = ' . $db->quote('mod_mokosuite_cpanel'));
$db->setQuery($query);
$db->execute();
// Check if a module instance already exists in #__modules
$query = $db->getQuery(true)
->select('id')
->from($db->quoteName('#__modules'))
->where($db->quoteName('module') . ' = ' . $db->quote('mod_mokosuite_cpanel'));
$db->setQuery($query);
$existingId = (int) $db->loadResult();
if ($existingId > 0)
{
// Ensure it's published with correct position
$db->setQuery(
$db->getQuery(true)
->update('#__modules')
->set('published = 1')
->set($db->quoteName('position') . ' = ' . $db->quote('top'))
->where('id = ' . $existingId)
)->execute();
return;
}
// Create the module instance on the cpanel position
$module = (object) [
'title' => 'MokoSuite',
'note' => '',
'content' => '',
'ordering' => 0,
'position' => 'top',
'checked_out' => null,
'checked_out_time' => null,
'publish_up' => null,
'publish_down' => null,
'published' => 1,
'module' => 'mod_mokosuite_cpanel',
'access' => 6, // Super Users only
'showtitle' => 0,
'params' => '{"show_health":"1","show_plugins":"1"}',
'client_id' => 1, // Administrator
'language' => '*',
];
$db->insertObject('#__modules', $module, 'id');
$moduleId = (int) $module->id;
if ($moduleId)
{
// Assign to all admin pages
$map = (object) [
'moduleid' => $moduleId,
'menuid' => 0, // 0 = all pages
];
$db->insertObject('#__modules_menu', $map);
}
}
catch (\Throwable $e)
{
Log::add('CPanel module setup error: ' . $e->getMessage(), Log::WARNING, 'mokosuite');
}
$this->ensureAdminModule('mod_mokosuite_cpanel', 'MokoSuite', 'top', 6, 0, '{"show_health":"1","show_plugins":"1"}');
}
/**
* Set up the MokoSuite admin sidebar menu module at position 0.
*/
private function setupAdminMenuModule(): void
{
try
{
$db = Factory::getDbo();
$this->ensureAdminModule('mod_mokosuite_menu', 'MokoSuite Menu', 'menu', 3, 0);
}
// Enable the module extension
$db->setQuery(
$db->getQuery(true)
->update($db->quoteName('#__extensions'))
->set($db->quoteName('enabled') . ' = 1')
->where($db->quoteName('type') . ' = ' . $db->quote('module'))
->where($db->quoteName('element') . ' = ' . $db->quote('mod_mokosuite_menu'))
)->execute();
// Check if module instance exists
$db->setQuery(
$db->getQuery(true)
->select('id')
->from($db->quoteName('#__modules'))
->where($db->quoteName('module') . ' = ' . $db->quote('mod_mokosuite_menu'))
);
$existingId = (int) $db->loadResult();
if ($existingId > 0)
{
$db->setQuery(
$db->getQuery(true)
->update('#__modules')
->set('published = 1')
->set($db->quoteName('position') . ' = ' . $db->quote('menu'))
->where('id = ' . $existingId)
)->execute();
return;
}
$module = (object) [
'title' => 'MokoSuite Menu',
'note' => '',
'content' => '',
'ordering' => 0,
'position' => 'menu',
'checked_out' => null,
'checked_out_time' => null,
'publish_up' => null,
'publish_down' => null,
'published' => 1,
'module' => 'mod_mokosuite_menu',
'access' => 3,
'showtitle' => 0,
'params' => '{}',
'client_id' => 1,
'language' => '*',
];
$db->insertObject('#__modules', $module, 'id');
if ((int) $module->id)
{
$db->insertObject('#__modules_menu', (object) ['moduleid' => (int) $module->id, 'menuid' => 0]);
}
}
catch (\Throwable $e)
{
Log::add('Admin menu module setup error: ' . $e->getMessage(), Log::WARNING, 'mokosuite');
}
private function setupCacheModule(): void
{
$this->ensureAdminModule('mod_mokosuite_cache', 'MokoSuite Cache Cleaner', 'status', 3, 8);
}
/**
* Set up the cache cleaner module in the admin status bar position.
* Ensure an admin module is published at the correct position using Joomla's ModuleModel.
*
* Uses the Joomla MVC save pipeline so that #__modules_menu mappings,
* checked_out, and all internal bookkeeping are handled correctly.
*/
private function setupCacheModule(): void
private function ensureAdminModule(string $element, string $title, string $position, int $access = 3, int $ordering = 0, string $params = '{}'): void
{
try
{
$db = Factory::getDbo();
// Enable the module extension
// Enable the extension entry
$db->setQuery(
$db->getQuery(true)
->update($db->quoteName('#__extensions'))
->set($db->quoteName('enabled') . ' = 1')
->where($db->quoteName('type') . ' = ' . $db->quote('module'))
->where($db->quoteName('element') . ' = ' . $db->quote('mod_mokosuite_cache'))
->update('#__extensions')
->set('enabled = 1')
->where('type = ' . $db->quote('module'))
->where('element = ' . $db->quote($element))
)->execute();
// Check if module instance exists
// Find existing module instance
$db->setQuery(
$db->getQuery(true)
->select('id')
->from($db->quoteName('#__modules'))
->where($db->quoteName('module') . ' = ' . $db->quote('mod_mokosuite_cache'))
->from('#__modules')
->where('module = ' . $db->quote($element))
->setLimit(1)
);
$existingId = (int) $db->loadResult();
$moduleId = (int) $db->loadResult();
if ($existingId > 0)
{
$db->setQuery(
$db->getQuery(true)
->update('#__modules')
->set('published = 1')
->set($db->quoteName('position') . ' = ' . $db->quote('status'))
->where('id = ' . $existingId)
)->execute();
return;
}
$module = (object) [
'title' => 'MokoSuite Cache Cleaner',
'note' => '',
'content' => '',
'ordering' => 8,
'position' => 'status',
'checked_out' => null,
'checked_out_time' => null,
'publish_up' => null,
'publish_down' => null,
// Build save data — Joomla's ModuleModel expects this format
$data = [
'title' => $title,
'module' => $element,
'position' => $position,
'published' => 1,
'module' => 'mod_mokosuite_cache',
'access' => 3,
'access' => $access,
'ordering' => $ordering,
'showtitle' => 0,
'params' => '{}',
'client_id' => 1,
'language' => '*',
'params' => $params,
'assignment' => 0, // 0 = all pages
];
$db->insertObject('#__modules', $module, 'id');
if ((int) $module->id)
if ($moduleId > 0)
{
$mm = (object) ['moduleid' => (int) $module->id, 'menuid' => 0];
$db->insertObject('#__modules_menu', $mm, 'moduleid');
$data['id'] = $moduleId;
}
// Use Joomla's ModuleModel to handle save + menu assignment
\Joomla\CMS\MVC\Factory\MVCFactory::class;
$app = Factory::getApplication();
/** @var \Joomla\Component\Modules\Administrator\Model\ModuleModel $model */
$model = $app->bootComponent('com_modules')
->getMVCFactory()
->createModel('Module', 'Administrator', ['ignore_request' => true]);
if (!$model->save($data))
{
Log::add("Module setup ({$element}): " . $model->getError(), Log::WARNING, 'mokosuite');
}
}
catch (\Throwable $e)
{
Log::add('Cache module setup error: ' . $e->getMessage(), Log::WARNING, 'mokosuite');
Log::add("Module setup ({$element}): " . $e->getMessage(), Log::WARNING, 'mokosuite');
}
}