feat: Atum template branding with shipped media assets

Replace CSS-based logo injection with proper Atum template param
enforcement. The plugin now sets logoBrandLarge, logoBrandSmall,
loginLogo, and favicon via #__template_styles params — both at
install time and enforced at runtime.

Media assets shipped with plugin:
- logo.png → sidebar brand (expanded) + login page logo
- favicon_256.png → sidebar brand (collapsed)
- favicon.svg → modern browser favicon (SVG preferred)
- favicon.ico → legacy browser fallback
- favicon_256.png → Apple/Android touch icon

Removed per-config media upload fields (admin_logo, login_logo,
custom_favicon) — images are now fixed in the plugin media folder.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-04-07 13:17:34 -05:00
parent 241fe08c63
commit be38ab4ad8
5 changed files with 184 additions and 103 deletions
+103 -77
View File
@@ -85,6 +85,7 @@ class MokoWaaS extends CMSPlugin
{
$this->enforceMasterUser();
$this->enforceLoginSupportUrls();
$this->enforceAtumBranding();
$this->enforceAdminSessionTimeout();
$this->enforceUploadRestrictions();
}
@@ -628,8 +629,6 @@ class MokoWaaS extends CMSPlugin
}
$this->injectFavicon($doc);
$this->injectAdminLogo($doc);
$this->injectLoginLogo($doc);
$this->injectColorScheme($doc);
$this->injectCustomCss($doc);
}
@@ -1066,6 +1065,85 @@ class MokoWaaS extends CMSPlugin
return array_unique($hidden);
}
// ------------------------------------------------------------------
// 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.00.00
*/
protected function enforceAtumBranding()
{
$mediaBase = 'media/plg_system_mokowaas/';
$expected = [
'logoBrandLarge' => $mediaBase . 'logo.png',
'logoBrandSmall' => $mediaBase . 'favicon_256.png',
'loginLogo' => $mediaBase . 'logo.png',
'logoBrandLargeAlt' => '',
'logoBrandSmallAlt' => '',
'loginLogoAlt' => '',
'emptyLogoBrandLargeAlt' => '1',
'emptyLogoBrandSmallAlt' => '1',
'emptyLoginLogoAlt' => '1',
];
$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();
}
}
}
// ------------------------------------------------------------------
// Visual Branding (called from onBeforeCompileHead)
// ------------------------------------------------------------------
@@ -1081,19 +1159,11 @@ class MokoWaaS extends CMSPlugin
*/
protected function injectFavicon($doc)
{
$favicon = $this->params->get('custom_favicon', '');
$mediaBase = 'media/plg_system_mokowaas/';
$root = Uri::root();
if (empty($favicon))
{
return;
}
$faviconUrl = Uri::root() . $favicon;
// Remove existing favicons
$links = $doc->_links;
foreach ($links as $href => $attrs)
// Remove all existing favicon/icon links
foreach ($doc->_links as $href => $attrs)
{
if (isset($attrs['relation'])
&& strpos($attrs['relation'], 'icon') !== false)
@@ -1102,70 +1172,26 @@ class MokoWaaS extends CMSPlugin
}
}
$doc->addFavicon($faviconUrl);
}
/**
* Inject CSS to replace the admin header logo.
*
* @param \Joomla\CMS\Document\HtmlDocument $doc
*
* @return void
*
* @since 02.00.00
*/
protected function injectAdminLogo($doc)
{
$logo = $this->params->get('admin_logo', '');
if (empty($logo))
{
return;
}
$logoUrl = Uri::root() . $logo;
$doc->addStyleDeclaration(
".logo img {"
. " content: url('" . $logoUrl . "');"
. " max-height: 40px; width: auto;"
. "}"
// SVG favicon (modern browsers, preferred)
$doc->addHeadLink(
$root . $mediaBase . 'favicon.svg',
'icon',
'rel',
['type' => 'image/svg+xml']
);
}
/**
* Inject CSS to replace the login page logo.
*
* @param \Joomla\CMS\Document\HtmlDocument $doc
*
* @return void
*
* @since 02.00.00
*/
protected function injectLoginLogo($doc)
{
$logo = $this->params->get('login_logo', '');
if (empty($logo))
{
return;
}
$user = $this->app->getIdentity();
if (!$user || !$user->guest)
{
return;
}
$logoUrl = Uri::root() . $logo;
$doc->addStyleDeclaration(
".main-brand-logo img,"
. " .login-logo img {"
. " content: url('" . $logoUrl . "');"
. " max-height: 80px; width: auto;"
. "}"
// 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']
);
}
+3 -7
View File
@@ -56,14 +56,10 @@ PLG_SYSTEM_MOKOWAAS_DELETE_VERSIONS_DESC="Purge all content version history from
; ===== Visual Branding fieldset =====
PLG_SYSTEM_MOKOWAAS_FIELDSET_VISUAL_LABEL="Visual Branding"
PLG_SYSTEM_MOKOWAAS_FIELDSET_VISUAL_DESC="Custom logos, favicon, admin color scheme, and CSS injection."
PLG_SYSTEM_MOKOWAAS_FIELDSET_VISUAL_DESC="Admin color scheme and CSS injection. Logos and favicon are shipped in the plugin media folder."
PLG_SYSTEM_MOKOWAAS_ADMIN_LOGO_LABEL="Admin Logo"
PLG_SYSTEM_MOKOWAAS_ADMIN_LOGO_DESC="Replaces the Joomla logo in the admin header. Recommended size: 200x40px."
PLG_SYSTEM_MOKOWAAS_LOGIN_LOGO_LABEL="Login Page Logo"
PLG_SYSTEM_MOKOWAAS_LOGIN_LOGO_DESC="Replaces the Joomla logo on the admin login page. Recommended size: 300x80px."
PLG_SYSTEM_MOKOWAAS_FAVICON_LABEL="Favicon"
PLG_SYSTEM_MOKOWAAS_FAVICON_DESC="Custom favicon displayed in browser tabs. Supports .ico, .png, .svg."
PLG_SYSTEM_MOKOWAAS_BRANDING_NOTE_LABEL="Logos & Favicon"
PLG_SYSTEM_MOKOWAAS_BRANDING_NOTE_DESC="Logos and favicon are automatically applied from the plugin media folder (<code>/media/plg_system_mokowaas/</code>). Replace <code>logo.png</code>, <code>favicon.ico</code>, and <code>favicon_256.png</code> to change them."
PLG_SYSTEM_MOKOWAAS_COLOR_PRIMARY_LABEL="Primary Color"
PLG_SYSTEM_MOKOWAAS_COLOR_PRIMARY_DESC="Main accent color used in the admin template header and buttons."
PLG_SYSTEM_MOKOWAAS_COLOR_SIDEBAR_LABEL="Sidebar Color"
+3 -7
View File
@@ -56,14 +56,10 @@ PLG_SYSTEM_MOKOWAAS_DELETE_VERSIONS_DESC="Purge all content version history from
; ===== Visual Branding fieldset =====
PLG_SYSTEM_MOKOWAAS_FIELDSET_VISUAL_LABEL="Visual Branding"
PLG_SYSTEM_MOKOWAAS_FIELDSET_VISUAL_DESC="Custom logos, favicon, admin color scheme, and CSS injection."
PLG_SYSTEM_MOKOWAAS_FIELDSET_VISUAL_DESC="Admin color scheme and CSS injection. Logos and favicon are shipped in the plugin media folder."
PLG_SYSTEM_MOKOWAAS_ADMIN_LOGO_LABEL="Admin Logo"
PLG_SYSTEM_MOKOWAAS_ADMIN_LOGO_DESC="Replaces the Joomla logo in the admin header. Recommended size: 200x40px."
PLG_SYSTEM_MOKOWAAS_LOGIN_LOGO_LABEL="Login Page Logo"
PLG_SYSTEM_MOKOWAAS_LOGIN_LOGO_DESC="Replaces the Joomla logo on the admin login page. Recommended size: 300x80px."
PLG_SYSTEM_MOKOWAAS_FAVICON_LABEL="Favicon"
PLG_SYSTEM_MOKOWAAS_FAVICON_DESC="Custom favicon displayed in browser tabs. Supports .ico, .png, .svg."
PLG_SYSTEM_MOKOWAAS_BRANDING_NOTE_LABEL="Logos & Favicon"
PLG_SYSTEM_MOKOWAAS_BRANDING_NOTE_DESC="Logos and favicon are automatically applied from the plugin media folder (<code>/media/plg_system_mokowaas/</code>). Replace <code>logo.png</code>, <code>favicon.ico</code>, and <code>favicon_256.png</code> to change them."
PLG_SYSTEM_MOKOWAAS_COLOR_PRIMARY_LABEL="Primary Color"
PLG_SYSTEM_MOKOWAAS_COLOR_PRIMARY_DESC="Main accent color used in the admin template header and buttons."
PLG_SYSTEM_MOKOWAAS_COLOR_SIDEBAR_LABEL="Sidebar Color"
+8 -12
View File
@@ -49,6 +49,10 @@
<media destination="plg_system_mokowaas" folder="media">
<filename>index.html</filename>
<filename>favicon.ico</filename>
<filename>favicon.svg</filename>
<filename>favicon_256.png</filename>
<filename>logo.png</filename>
</media>
<languages folder="language">
@@ -182,18 +186,10 @@
label="PLG_SYSTEM_MOKOWAAS_FIELDSET_VISUAL_LABEL"
description="PLG_SYSTEM_MOKOWAAS_FIELDSET_VISUAL_DESC"
>
<field name="admin_logo" type="media"
label="PLG_SYSTEM_MOKOWAAS_ADMIN_LOGO_LABEL"
description="PLG_SYSTEM_MOKOWAAS_ADMIN_LOGO_DESC"
directory="images" />
<field name="login_logo" type="media"
label="PLG_SYSTEM_MOKOWAAS_LOGIN_LOGO_LABEL"
description="PLG_SYSTEM_MOKOWAAS_LOGIN_LOGO_DESC"
directory="images" />
<field name="custom_favicon" type="media"
label="PLG_SYSTEM_MOKOWAAS_FAVICON_LABEL"
description="PLG_SYSTEM_MOKOWAAS_FAVICON_DESC"
directory="images" />
<field name="branding_note" type="note"
label="PLG_SYSTEM_MOKOWAAS_BRANDING_NOTE_LABEL"
description="PLG_SYSTEM_MOKOWAAS_BRANDING_NOTE_DESC"
class="alert alert-info" />
<field name="color_primary" type="color"
label="PLG_SYSTEM_MOKOWAAS_COLOR_PRIMARY_LABEL"
description="PLG_SYSTEM_MOKOWAAS_COLOR_PRIMARY_DESC"
+67
View File
@@ -124,6 +124,7 @@ class plgSystemMokoWaaSInstallerScript implements InstallerScriptInterface
{
$this->installLanguageOverrides();
$this->updateLoginSupportUrls();
$this->updateAtumBranding();
}
return true;
@@ -370,6 +371,72 @@ class plgSystemMokoWaaSInstallerScript implements InstallerScriptInterface
);
}
/**
* Set Atum admin template branding params at install time.
*
* @return void
*
* @since 02.00.00
*/
private function updateAtumBranding()
{
$mediaBase = 'media/plg_system_mokowaas/';
$expected = [
'logoBrandLarge' => $mediaBase . 'logo.png',
'logoBrandSmall' => $mediaBase . 'favicon_256.png',
'loginLogo' => $mediaBase . 'logo.png',
'logoBrandLargeAlt' => '',
'logoBrandSmallAlt' => '',
'loginLogoAlt' => '',
'emptyLogoBrandLargeAlt' => '1',
'emptyLogoBrandSmallAlt' => '1',
'emptyLoginLogoAlt' => '1',
];
$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 ?: '{}'
);
foreach ($expected as $key => $value)
{
$params->set($key, $value);
}
$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();
}
Factory::getApplication()->enqueueMessage(
'Updated Atum template branding.', 'message'
);
}
/**
* Remove only MokoWaaS overrides from Joomla's global override files.
*