* * SPDX-License-Identifier: GPL-3.0-or-later * * One-time migration from MokoCassiopeia → MokoOnyx. * Called from index.php on first page load. Creates a .migrated * marker file so it only runs once. */ defined('_JEXEC') or die; use Joomla\CMS\Factory; use Joomla\CMS\Log\Log; (function () { $markerFile = __DIR__ . '/../.migrated'; // Already migrated if (file_exists($markerFile)) { return; } $db = Factory::getDbo(); $app = Factory::getApplication(); $oldName = 'mokocassiopeia'; $newName = 'mokoonyx'; $oldDisplay = 'MokoCassiopeia'; $newDisplay = 'MokoOnyx'; // Init logger Log::addLogger( ['text_file' => 'mokoonyx_migrate.log.php'], Log::ALL, ['mokoonyx_migrate'] ); $log = function (string $msg, int $level = Log::INFO) { Log::add($msg, $level, 'mokoonyx_migrate'); }; $log('=== MokoOnyx migration started (index.php bootstrap) ==='); // Check if MokoCassiopeia has styles to migrate $query = $db->getQuery(true) ->select('*') ->from('#__template_styles') ->where($db->quoteName('template') . ' = ' . $db->quote($oldName)) ->where($db->quoteName('client_id') . ' = 0'); $oldStyles = $db->setQuery($query)->loadObjectList(); if (empty($oldStyles)) { $log('No MokoCassiopeia styles found — fresh install, nothing to migrate.'); @file_put_contents($markerFile, date('Y-m-d H:i:s') . ' fresh install'); return; } $log('Found ' . count($oldStyles) . ' MokoCassiopeia style(s) to migrate.'); // Get the default MokoOnyx style (created by Joomla installer) $query = $db->getQuery(true) ->select('id') ->from('#__template_styles') ->where($db->quoteName('template') . ' = ' . $db->quote($newName)) ->where($db->quoteName('client_id') . ' = 0') ->order($db->quoteName('id') . ' ASC'); $defaultOnyxId = (int) $db->setQuery($query, 0, 1)->loadResult(); $isFirst = true; foreach ($oldStyles as $old) { $newTitle = str_replace($oldDisplay, $newDisplay, $old->title); $newTitle = str_replace($oldName, $newName, $newTitle); $newParams = is_string($old->params) ? str_replace($oldName, $newName, $old->params) : $old->params; if ($isFirst && $defaultOnyxId) { // Apply params to the installer-created default MokoOnyx style $update = $db->getQuery(true) ->update('#__template_styles') ->set($db->quoteName('title') . ' = ' . $db->quote($newTitle)) ->set($db->quoteName('params') . ' = ' . $db->quote($newParams)) ->where('id = ' . $defaultOnyxId); $db->setQuery($update)->execute(); // Set as default if MokoCassiopeia was default if ($old->home == 1) { $db->setQuery( $db->getQuery(true) ->update('#__template_styles') ->set($db->quoteName('home') . ' = 1') ->where('id = ' . $defaultOnyxId) )->execute(); $db->setQuery( $db->getQuery(true) ->update('#__template_styles') ->set($db->quoteName('home') . ' = 0') ->where('id = ' . (int) $old->id) )->execute(); $log('Set MokoOnyx as default site template.'); } $log("Applied params to default MokoOnyx style: {$newTitle}"); $isFirst = false; continue; } // Additional styles: check if already exists $check = $db->getQuery(true) ->select('COUNT(*)') ->from('#__template_styles') ->where($db->quoteName('template') . ' = ' . $db->quote($newName)) ->where($db->quoteName('title') . ' = ' . $db->quote($newTitle)); if ((int) $db->setQuery($check)->loadResult() > 0) { $log("Style '{$newTitle}' already exists — skipping."); continue; } // Create new MokoOnyx style copy $new = clone $old; unset($new->id); $new->template = $newName; $new->title = $newTitle; $new->params = $newParams; $new->home = 0; try { $db->insertObject('#__template_styles', $new, 'id'); $log("Created MokoOnyx style: {$newTitle}"); } catch (\Throwable $e) { $log("Failed to create style '{$newTitle}': " . $e->getMessage(), Log::WARNING); } } // Copy user files from MokoCassiopeia media $oldMedia = JPATH_ROOT . '/media/templates/site/' . $oldName; $newMedia = JPATH_ROOT . '/media/templates/site/' . $newName; if (is_dir($oldMedia) && is_dir($newMedia)) { $userFiles = [ 'css/theme/light.custom.css', 'css/theme/dark.custom.css', 'css/theme/light.custom.min.css', 'css/theme/dark.custom.min.css', 'css/user.css', 'css/user.min.css', 'js/user.js', 'js/user.min.js', ]; $copied = 0; foreach ($userFiles as $rel) { $src = $oldMedia . '/' . $rel; $dst = $newMedia . '/' . $rel; if (is_file($src) && !is_file($dst)) { $dir = dirname($dst); if (!is_dir($dir)) { mkdir($dir, 0755, true); } copy($src, $dst); $copied++; } } if ($copied > 0) { $log("Copied {$copied} user file(s) from MokoCassiopeia."); } } // Update the update server try { $onyxUpdatesUrl = 'https://git.mokoconsulting.tech/MokoConsulting/MokoOnyx/raw/branch/main/updates.xml'; $query = $db->getQuery(true) ->update('#__update_sites') ->set($db->quoteName('location') . ' = ' . $db->quote($onyxUpdatesUrl)) ->set($db->quoteName('name') . ' = ' . $db->quote($newDisplay)) ->where($db->quoteName('location') . ' LIKE ' . $db->quote('%MokoCassiopeia%')); $db->setQuery($query)->execute(); $n = $db->getAffectedRows(); if ($n > 0) { $log("Redirected {$n} update site(s) to MokoOnyx."); } } catch (\Throwable $e) { $log('Update server redirect failed: ' . $e->getMessage(), Log::WARNING); } // Write marker file @file_put_contents($markerFile, date('Y-m-d H:i:s') . " migrated {$oldName} → {$newName}"); $log('=== Migration completed ==='); // Enqueue message for admin if ($app->isClient('administrator')) { $app->enqueueMessage( 'MokoOnyx has imported your MokoCassiopeia settings.
' . 'You can safely uninstall MokoCassiopeia from Extensions → Manage.', 'success' ); } })();