refactor: remove branding/identity from core plugin (#154)
Remove 8 branding methods and 4 call sites (-428 lines): - enforceAtumBranding(), hexToHsl(), injectFavicon() - enforceLoginSupportUrls(), loadLanguageOverrides() - getPlaceholders(), parseLanguageFile(), setTemplateParam() MokoWaaS is an admin tools suite, not a branding layer. Core plugin docblock updated to reflect new purpose. Authored-by: Moko Consulting Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -24,7 +24,7 @@
|
||||
* REPO: https://github.com/mokoconsulting-tech/mokowaas
|
||||
* VERSION: 02.33.01
|
||||
* PATH: /src/Extension/MokoWaaS.php
|
||||
* NOTE: Handles Joomla system events for rebranding functionality
|
||||
* NOTE: Core system plugin for MokoWaaS admin tools suite
|
||||
*/
|
||||
|
||||
namespace Moko\Plugin\System\MokoWaaS\Extension;
|
||||
@@ -42,10 +42,9 @@ use Joomla\CMS\User\UserHelper;
|
||||
use Psr\Container\ContainerInterface;
|
||||
|
||||
/**
|
||||
* MokoWaaS Brand System Plugin
|
||||
* MokoWaaS Core System Plugin
|
||||
*
|
||||
* This plugin rebrands the Joomla system interface with MokoWaaS identity.
|
||||
* It applies language overrides and ensures consistent branding across the platform.
|
||||
* This plugin provides core coordination for the MokoWaaS admin tools suite.
|
||||
*
|
||||
* @since 01.04.00
|
||||
*/
|
||||
@@ -187,18 +186,14 @@ class MokoWaaS extends CMSPlugin implements BootableExtensionInterface
|
||||
$this->handleMokoApi($mokoAction);
|
||||
}
|
||||
|
||||
// Admin-only core controls (branding, emergency access, master user)
|
||||
// Admin-only core controls (emergency access, master user)
|
||||
// NOTE: enforceHttps, enforceDevMode, enforceAdminSessionTimeout,
|
||||
// enforceUploadRestrictions are now in feature plugins
|
||||
if ($this->app->isClient('administrator'))
|
||||
{
|
||||
$this->handleEmergencyAccess();
|
||||
$this->enforceMasterUser();
|
||||
$this->enforceLoginSupportUrls();
|
||||
$this->enforceAtumBranding();
|
||||
}
|
||||
|
||||
$this->loadLanguageOverrides();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -698,102 +693,6 @@ class MokoWaaS extends CMSPlugin implements BootableExtensionInterface
|
||||
return in_array($clientIp, $allowedIps, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Build the placeholder → value map from plugin params.
|
||||
*
|
||||
* @return array Associative array of placeholder => replacement value
|
||||
*
|
||||
* @since 02.01.08
|
||||
*/
|
||||
protected function getPlaceholders()
|
||||
{
|
||||
return [
|
||||
'{{BRAND_NAME}}' => self::BRAND_NAME,
|
||||
'{{COMPANY_NAME}}' => self::COMPANY_NAME,
|
||||
'{{SUPPORT_URL}}' => self::SUPPORT_URL,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Load language override templates and inject resolved strings into Joomla.
|
||||
*
|
||||
* Reads the override template shipped with the plugin, replaces
|
||||
* {{BRAND_NAME}}, {{COMPANY_NAME}} and {{SUPPORT_URL}} with the
|
||||
* values from plugin params, then injects the resolved strings into
|
||||
* the active Language object.
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
* @since 02.01.08
|
||||
*/
|
||||
protected function loadLanguageOverrides()
|
||||
{
|
||||
$language = $this->app->getLanguage();
|
||||
$tag = $language->getTag();
|
||||
$pluginPath = JPATH_PLUGINS . '/system/mokowaas';
|
||||
$isAdmin = $this->app->isClient('administrator');
|
||||
|
||||
$overridePath = $isAdmin
|
||||
? $pluginPath . '/administrator/language/overrides/' . $tag . '.override.ini'
|
||||
: $pluginPath . '/language/overrides/' . $tag . '.override.ini';
|
||||
|
||||
if (!file_exists($overridePath))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
$strings = $this->parseLanguageFile($overridePath);
|
||||
$placeholders = $this->getPlaceholders();
|
||||
|
||||
foreach ($strings as $key => $value)
|
||||
{
|
||||
$language->_strings[$key] = str_replace(
|
||||
array_keys($placeholders),
|
||||
array_values($placeholders),
|
||||
$value
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse a language INI file and return the raw strings (with placeholders).
|
||||
*
|
||||
* @param string $filePath The path to the language file
|
||||
*
|
||||
* @return array Array of language strings (key => raw value)
|
||||
*
|
||||
* @since 02.01.08
|
||||
*/
|
||||
protected function parseLanguageFile($filePath)
|
||||
{
|
||||
$strings = [];
|
||||
|
||||
if (!file_exists($filePath))
|
||||
{
|
||||
return $strings;
|
||||
}
|
||||
|
||||
$content = file_get_contents($filePath);
|
||||
$lines = explode("\n", $content);
|
||||
|
||||
foreach ($lines as $line)
|
||||
{
|
||||
$line = trim($line);
|
||||
|
||||
if ($line === '' || $line[0] === ';')
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (preg_match('/^([A-Z0-9_]+)="(.+)"$/i', $line, $matches))
|
||||
{
|
||||
$strings[strtoupper($matches[1])] = $matches[2];
|
||||
}
|
||||
}
|
||||
|
||||
return $strings;
|
||||
}
|
||||
|
||||
/**
|
||||
* Event triggered after an extension's config is saved.
|
||||
*
|
||||
@@ -1044,7 +943,6 @@ class MokoWaaS extends CMSPlugin implements BootableExtensionInterface
|
||||
return;
|
||||
}
|
||||
|
||||
$this->injectFavicon($doc);
|
||||
$this->redirectHelpMenu($doc);
|
||||
|
||||
// Hide MokoWaaS from plugin list for non-master users
|
||||
@@ -4419,115 +4317,7 @@ class MokoWaaS extends CMSPlugin implements BootableExtensionInterface
|
||||
* @since 02.01.08
|
||||
*/
|
||||
|
||||
/**
|
||||
* Set a parameter on a template style.
|
||||
*
|
||||
* @param string $template Template element name
|
||||
* @param string $key Parameter key
|
||||
* @param mixed $value Parameter value
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
* @since 02.31.00
|
||||
*/
|
||||
private function setTemplateParam(string $template, string $key, $value): void
|
||||
{
|
||||
try
|
||||
{
|
||||
$db = Factory::getDbo();
|
||||
$query = $db->getQuery(true)
|
||||
->select([$db->quoteName('id'), $db->quoteName('params')])
|
||||
->from($db->quoteName('#__template_styles'))
|
||||
->where($db->quoteName('template') . ' = ' . $db->quote($template));
|
||||
$db->setQuery($query);
|
||||
$styles = $db->loadObjectList();
|
||||
|
||||
foreach ($styles as $style)
|
||||
{
|
||||
$params = new \Joomla\Registry\Registry($style->params ?: '{}');
|
||||
|
||||
if ($params->get($key) != $value)
|
||||
{
|
||||
$params->set($key, $value);
|
||||
|
||||
$db->setQuery(
|
||||
$db->getQuery(true)
|
||||
->update($db->quoteName('#__template_styles'))
|
||||
->set($db->quoteName('params') . ' = ' . $db->quote($params->toString()))
|
||||
->where($db->quoteName('id') . ' = ' . (int) $style->id)
|
||||
)->execute();
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (\Throwable $e)
|
||||
{
|
||||
// Silent
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Enforce login support module URLs on admin requests.
|
||||
*
|
||||
* Checks the mod_loginsupport module params and corrects them if
|
||||
* they have been changed away from the expected values.
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
* @since 02.01.08
|
||||
*/
|
||||
protected function enforceLoginSupportUrls()
|
||||
{
|
||||
$expected = [
|
||||
'forum_url' => 'https://mokoconsulting.tech/support',
|
||||
'documentation_url' => 'https://mokoconsulting.tech/kb',
|
||||
'news_url' => 'https://mokoconsulting.tech/news',
|
||||
];
|
||||
|
||||
$db = Factory::getDbo();
|
||||
$query = $db->getQuery(true)
|
||||
->select([$db->quoteName('id'), $db->quoteName('params')])
|
||||
->from($db->quoteName('#__modules'))
|
||||
->where($db->quoteName('module') . ' = '
|
||||
. $db->quote('mod_loginsupport'));
|
||||
|
||||
$db->setQuery($query);
|
||||
$modules = $db->loadObjectList();
|
||||
|
||||
if (empty($modules))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
foreach ($modules as $module)
|
||||
{
|
||||
$params = new \Joomla\Registry\Registry(
|
||||
$module->params ?: '{}'
|
||||
);
|
||||
$needsFix = false;
|
||||
|
||||
foreach ($expected as $key => $url)
|
||||
{
|
||||
if ($params->get($key) !== $url)
|
||||
{
|
||||
$params->set($key, $url);
|
||||
$needsFix = true;
|
||||
}
|
||||
}
|
||||
|
||||
if ($needsFix)
|
||||
{
|
||||
$update = $db->getQuery(true)
|
||||
->update($db->quoteName('#__modules'))
|
||||
->set($db->quoteName('params') . ' = '
|
||||
. $db->quote($params->toString()))
|
||||
->where($db->quoteName('id') . ' = '
|
||||
. (int) $module->id);
|
||||
|
||||
$db->setQuery($update);
|
||||
$db->execute();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------
|
||||
// Tenant Restrictions (called from onAfterRoute)
|
||||
@@ -4584,224 +4374,6 @@ class MokoWaaS extends CMSPlugin implements BootableExtensionInterface
|
||||
return $this->masterNames;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------
|
||||
// Atum Template Branding (called from onAfterInitialise)
|
||||
// ------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Enforce Atum admin template branding params.
|
||||
*
|
||||
* Sets logoBrandLarge, logoBrandSmall, loginLogo, and alt text
|
||||
* in the Atum template style params. Uses the plugin's media
|
||||
* folder as the image source. Only writes to DB when values
|
||||
* have drifted.
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
* @since 02.01.08
|
||||
*/
|
||||
protected function enforceAtumBranding()
|
||||
{
|
||||
$mediaBase = 'media/plg_system_mokowaas/';
|
||||
|
||||
// Logo params
|
||||
$expected = [
|
||||
'logoBrandLarge' => $mediaBase . 'logo.png',
|
||||
'logoBrandSmall' => $mediaBase . 'favicon_256.png',
|
||||
'loginLogo' => $mediaBase . 'logo.png',
|
||||
'logoBrandLargeAlt' => '',
|
||||
'logoBrandSmallAlt' => '',
|
||||
'loginLogoAlt' => '',
|
||||
'emptyLogoBrandLargeAlt' => '1',
|
||||
'emptyLogoBrandSmallAlt' => '1',
|
||||
'emptyLoginLogoAlt' => '1',
|
||||
];
|
||||
|
||||
// Hardcoded color scheme
|
||||
$primary = self::COLOR_PRIMARY;
|
||||
$sidebar = self::COLOR_SIDEBAR;
|
||||
$link = self::COLOR_LINK;
|
||||
|
||||
if (!empty($primary))
|
||||
{
|
||||
// Convert hex to HSL for Atum's hue param
|
||||
$hsl = $this->hexToHsl($primary);
|
||||
|
||||
if ($hsl)
|
||||
{
|
||||
$expected['hue'] = sprintf(
|
||||
'hsl(%d, %d%%, %d%%)',
|
||||
$hsl[0], $hsl[1], $hsl[2]
|
||||
);
|
||||
}
|
||||
|
||||
$expected['special-color'] = $primary;
|
||||
}
|
||||
|
||||
if (!empty($sidebar))
|
||||
{
|
||||
$expected['header-color'] = $sidebar;
|
||||
}
|
||||
|
||||
if (!empty($link))
|
||||
{
|
||||
$expected['link-color'] = $link;
|
||||
}
|
||||
|
||||
$db = Factory::getDbo();
|
||||
$query = $db->getQuery(true)
|
||||
->select([$db->quoteName('id'), $db->quoteName('params')])
|
||||
->from($db->quoteName('#__template_styles'))
|
||||
->where($db->quoteName('template') . ' = '
|
||||
. $db->quote('atum'))
|
||||
->where($db->quoteName('client_id') . ' = 1');
|
||||
|
||||
$db->setQuery($query);
|
||||
$styles = $db->loadObjectList();
|
||||
|
||||
if (empty($styles))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
foreach ($styles as $style)
|
||||
{
|
||||
$params = new \Joomla\Registry\Registry(
|
||||
$style->params ?: '{}'
|
||||
);
|
||||
$needsFix = false;
|
||||
|
||||
foreach ($expected as $key => $value)
|
||||
{
|
||||
if ($params->get($key) !== $value)
|
||||
{
|
||||
$params->set($key, $value);
|
||||
$needsFix = true;
|
||||
}
|
||||
}
|
||||
|
||||
if ($needsFix)
|
||||
{
|
||||
$update = $db->getQuery(true)
|
||||
->update($db->quoteName('#__template_styles'))
|
||||
->set($db->quoteName('params') . ' = '
|
||||
. $db->quote($params->toString()))
|
||||
->where($db->quoteName('id') . ' = '
|
||||
. (int) $style->id);
|
||||
|
||||
$db->setQuery($update);
|
||||
$db->execute();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a hex color to HSL values.
|
||||
*
|
||||
* @param string $hex Hex color (e.g., "#1a2744")
|
||||
*
|
||||
* @return array|null [hue, saturation%, lightness%] or null
|
||||
*
|
||||
* @since 02.01.08
|
||||
*/
|
||||
protected function hexToHsl($hex)
|
||||
{
|
||||
$hex = ltrim($hex, '#');
|
||||
|
||||
if (strlen($hex) !== 6)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
$r = hexdec(substr($hex, 0, 2)) / 255;
|
||||
$g = hexdec(substr($hex, 2, 2)) / 255;
|
||||
$b = hexdec(substr($hex, 4, 2)) / 255;
|
||||
|
||||
$max = max($r, $g, $b);
|
||||
$min = min($r, $g, $b);
|
||||
$l = ($max + $min) / 2;
|
||||
|
||||
if ($max === $min)
|
||||
{
|
||||
return [0, 0, (int) round($l * 100)];
|
||||
}
|
||||
|
||||
$d = $max - $min;
|
||||
$s = $l > 0.5
|
||||
? $d / (2 - $max - $min)
|
||||
: $d / ($max + $min);
|
||||
|
||||
if ($max === $r)
|
||||
{
|
||||
$h = ($g - $b) / $d + ($g < $b ? 6 : 0);
|
||||
}
|
||||
elseif ($max === $g)
|
||||
{
|
||||
$h = ($b - $r) / $d + 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
$h = ($r - $g) / $d + 4;
|
||||
}
|
||||
|
||||
$h = $h / 6;
|
||||
|
||||
return [
|
||||
(int) round($h * 360),
|
||||
(int) round($s * 100),
|
||||
(int) round($l * 100),
|
||||
];
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------
|
||||
// Visual Branding (called from onBeforeCompileHead)
|
||||
// ------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Replace the default favicon with a custom one.
|
||||
*
|
||||
* @param \Joomla\CMS\Document\HtmlDocument $doc
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
* @since 02.01.08
|
||||
*/
|
||||
protected function injectFavicon($doc)
|
||||
{
|
||||
$mediaBase = 'media/plg_system_mokowaas/';
|
||||
$root = Uri::root();
|
||||
|
||||
// Remove all existing favicon/icon links
|
||||
foreach ($doc->_links as $href => $attrs)
|
||||
{
|
||||
if (isset($attrs['relation'])
|
||||
&& strpos($attrs['relation'], 'icon') !== false)
|
||||
{
|
||||
unset($doc->_links[$href]);
|
||||
}
|
||||
}
|
||||
|
||||
// SVG favicon (modern browsers, preferred)
|
||||
$doc->addHeadLink(
|
||||
$root . $mediaBase . 'favicon.svg',
|
||||
'icon',
|
||||
'rel',
|
||||
['type' => 'image/svg+xml']
|
||||
);
|
||||
// ICO fallback (legacy browsers)
|
||||
$doc->addHeadLink(
|
||||
$root . $mediaBase . 'favicon.ico',
|
||||
'alternate icon',
|
||||
'rel',
|
||||
['type' => 'image/vnd.microsoft.icon']
|
||||
);
|
||||
// PNG for Apple/Android
|
||||
$doc->addHeadLink(
|
||||
$root . $mediaBase . 'favicon_256.png',
|
||||
'apple-touch-icon',
|
||||
'rel',
|
||||
['sizes' => '256x256']
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user