Verify favicon.ico from main branch is present #61

Merged
Copilot merged 7 commits from copilot/update-error-php-from-index into main 2026-01-28 03:48:03 +00:00
20 changed files with 328 additions and 98 deletions

View File

@@ -8,11 +8,15 @@
DEFGROUP: Joomla.Template.Site
INGROUP: Moko-Cassiopeia.Documentation
PATH: ./CHANGELOG.md
VERSION: 03.05.00
VERSION: 03.06.00
BRIEF: Changelog file documenting version history of Moko-Cassiopeia
-->
# Changelog — Moko-Cassiopeia (VERSION: 03.05.00)
# Changelog — Moko-Cassiopeia (VERSION: 03.06.00)
## [03.06.00] 2026-01-28
### Changed
- Updated version to 03.06.00 across all files
## [03.05.01] 2026-01-09
### Added

View File

@@ -10,7 +10,7 @@
INGROUP: Moko-Cassiopeia.Governance
REPO: https://github.com/mokoconsulting-tech/moko-cassiopeia
FILE: CODE_OF_CONDUCT.md
VERSION: 03.05.00
VERSION: 03.06.00
BRIEF: Contributor code of conduct for the Moko-Cassiopeia project.
PATH: /CODE_OF_CONDUCT.md
NOTE: This document defines behavioral expectations and enforcement processes.
@@ -86,7 +86,7 @@ This project is managed from Tennessee, USA. This statement is informational and
* **Repository:** [https://github.com/mokoconsulting-tech/moko-cassiopeia](https://github.com/mokoconsulting-tech/moko-cassiopeia)
* **Path:** /CODE_OF_CONDUCT.md
* **Owner:** Moko Consulting
* **Version:** 03.05.00
* **Version:** 03.06.00
* **Status:** Active
* **Effective Date:** 2025-12-18
* **Last Reviewed:** 2025-12-18

View File

@@ -10,7 +10,7 @@
INGROUP: Moko-Cassiopeia.Governance
REPO: https://github.com/mokoconsulting-tech/moko-cassiopeia
FILE: CONTRIBUTING.md
VERSION: 03.05.00
VERSION: 03.06.00
BRIEF: Contribution guidelines for the Moko-Cassiopeia project.
PATH: /CONTRIBUTING.md
NOTE: This document defines contribution workflow, standards, and governance alignment.
@@ -133,7 +133,7 @@ Participation in this project is governed by the Code of Conduct. Unacceptable b
* **Repository:** [https://github.com/mokoconsulting-tech/moko-cassiopeia](https://github.com/mokoconsulting-tech/moko-cassiopeia)
* **Path:** /CONTRIBUTING.md
* **Owner:** Moko Consulting
* **Version:** 03.05.00
* **Version:** 03.06.00
* **Status:** Active
* **Effective Date:** 2025-12-18
* **Last Reviewed:** 2025-12-18

View File

@@ -10,7 +10,7 @@
INGROUP: Moko-Cassiopeia.Governance
REPO: https://github.com/mokoconsulting-tech/moko-cassiopeia
FILE: GOVERNANCE.md
VERSION: 03.05.00
VERSION: 03.06.00
BRIEF: Project governance model, roles, and decision processes for Moko-Cassiopeia.
PATH: /GOVERNANCE.md
NOTE: This document defines authority, decision making, and escalation paths.
@@ -103,7 +103,7 @@ This project is managed from Tennessee, USA. This statement is informational and
* **Repository:** [https://github.com/mokoconsulting-tech/moko-cassiopeia](https://github.com/mokoconsulting-tech/moko-cassiopeia)
* **Path:** /GOVERNANCE.md
* **Owner:** Moko Consulting
* **Version:** 03.05.00
* **Version:** 03.06.00
* **Status:** Active
* **Effective Date:** 2025-12-18
* **Last Reviewed:** 2025-12-18

View File

@@ -9,11 +9,11 @@
INGROUP: Moko-Cassiopeia.Documentation
REPO: https://github.com/mokoconsulting-tech/moko-cassiopeia
FILE: ./README.md
VERSION: 03.05.00
VERSION: 03.06.00
BRIEF: Documentation for Moko-Cassiopeia template
-->
# Moko-Cassiopeia (VERSION: 03.05.00)
# Moko-Cassiopeia (VERSION: 03.06.00)
A modern, lightweight enhancement layer for Joomla's Cassiopeia
template.

View File

@@ -10,7 +10,7 @@
INGROUP: Moko-Cassiopeia.Governance
REPO: https://github.com/mokoconsulting-tech/moko-cassiopeia
FILE: SECURITY.md
VERSION: 03.05.00
VERSION: 03.06.00
BRIEF: Security policy and vulnerability reporting process for Moko-Cassiopeia.
PATH: /SECURITY.md
NOTE: This policy is process oriented and does not replace secure engineering practices.
@@ -153,7 +153,7 @@ If you want credit, include the name or handle to list in an advisory. If you pr
* **Repository:** [https://github.com/mokoconsulting-tech/moko-cassiopeia](https://github.com/mokoconsulting-tech/moko-cassiopeia)
* **Path:** /SECURITY.md
* **Owner:** Moko Consulting
* **Version:** 03.05.00
* **Version:** 03.06.00
* **Status:** Active
* **Effective Date:** 2025-12-18
* **Last Reviewed:** 2025-12-18

View File

@@ -271,7 +271,7 @@ make test
### Version Management
- Use semantic versioning: Major.Minor.Patch (03.05.00)
- Use semantic versioning: Major.Minor.Patch (03.06.00)
- Update CHANGELOG.md with all changes
- Follow the version hierarchy: dev → rc → version → main
- Never skip stages in the release process

View File

@@ -10,7 +10,7 @@
INGROUP: Moko-Cassiopeia.Documentation
REPO: https://github.com/mokoconsulting-tech/moko-cassiopeia
FILE: docs/README.md
VERSION: 03.05.00
VERSION: 03.06.00
BRIEF: Documentation index for Moko-Cassiopeia template
PATH: /docs/README.md
-->
@@ -41,7 +41,7 @@ This directory contains comprehensive documentation for the Moko-Cassiopeia Joom
* Multi-version testing
* **[Roadmap](ROADMAP.md)** - Version-specific roadmap
* Current features (v03.05.00)
* Current features (v03.06.00)
* Feature evolution timeline
* Planned enhancements
* Development priorities
@@ -105,7 +105,7 @@ This project adheres to [MokoStandards](https://github.com/mokoconsulting-tech/M
* Repository: [https://github.com/mokoconsulting-tech/moko-cassiopeia](https://github.com/mokoconsulting-tech/moko-cassiopeia)
* Path: /docs/README.md
* Owner: Moko Consulting
* Version: 03.05.00
* Version: 03.06.00
* Status: Active
* Effective Date: 2026-01-09

View File

@@ -10,12 +10,12 @@
INGROUP: Moko-Cassiopeia.Documentation
REPO: https://github.com/mokoconsulting-tech/moko-cassiopeia
FILE: docs/ROADMAP.md
VERSION: 03.05.00
VERSION: 03.06.00
BRIEF: Version-specific roadmap for Moko-Cassiopeia template
PATH: /docs/ROADMAP.md
-->
# Moko-Cassiopeia Roadmap (VERSION: 03.05.00)
# Moko-Cassiopeia Roadmap (VERSION: 03.06.00)
This document provides a comprehensive, version-specific roadmap for the Moko-Cassiopeia Joomla template, tracking feature evolution, current capabilities, and planned enhancements.
@@ -24,7 +24,7 @@ This document provides a comprehensive, version-specific roadmap for the Moko-Ca
- [Version Timeline](#version-timeline)
- [Past Releases](#past-releases)
- [Future Roadmap (5-Year Plan)](#future-roadmap-5-year-plan)
- [Current Release (v03.05.00)](#current-release-v030500)
- [Current Release (v03.06.00)](#current-release-v030600)
- [Implemented Features](#implemented-features)
- [Planned Features](#planned-features)
- [Development Priorities](#development-priorities)
@@ -51,9 +51,15 @@ This document provides a comprehensive, version-specific roadmap for the Moko-Ca
- Enforced repository compliance with MokoStandards
- Improved security posture with automated scanning
### v03.05.00 (2026-01-04) - Workflow & Governance
### v03.06.00 (2026-01-28) - Version Update
**Status**: Current Release (in code)
**Changed**:
- Updated version to 03.06.00 across all files
### v03.05.00 (2026-01-04) - Workflow & Governance
**Status**: Mentioned in CHANGELOG (v03.05.00)
**Added**:
- `.github/workflows` directory structure
- CODE_OF_CONDUCT.md from MokoStandards
@@ -431,7 +437,7 @@ The following versions represent our planned annual major releases, each buildin
---
## Current Release (v03.05.00)
## Current Release (v03.06.00)
### System Requirements
- **Joomla**: 4.4.x or 5.x
@@ -835,7 +841,7 @@ Have ideas for future features? We welcome community input!
* Repository: [https://github.com/mokoconsulting-tech/moko-cassiopeia](https://github.com/mokoconsulting-tech/moko-cassiopeia)
* Path: /docs/ROADMAP.md
* Owner: Moko Consulting
* Version: 03.05.00
* Version: 03.06.00
* Status: Active
* Last Updated: 2026-01-27
* Classification: Public Open Source Documentation

View File

@@ -134,7 +134,7 @@ codecept run
**How to run:**
1. Go to Actions → Create version branch
2. Click "Run workflow"
3. Enter version (e.g., 03.05.00)
3. Enter version (e.g., 03.06.00)
4. Select branch prefix (dev/, rc/, or version/)
5. Click "Run workflow"
@@ -322,7 +322,7 @@ make validate-required
git branch -r | grep dev/
# Delete remote branch if needed (carefully!)
git push origin --delete dev/03.05.00
git push origin --delete dev/03.06.00
```
#### "Missing required secrets"
@@ -381,7 +381,7 @@ phpcs --standard=phpcs.xml --report=source src/
1. **Always use version branches:** dev/X.Y.Z, rc/X.Y.Z, version/X.Y.Z
2. **Follow hierarchy:** dev → rc → version → main
3. **Update CHANGELOG:** Document all changes in Unreleased section
4. **Semantic versioning:** Major.Minor.Patch (03.05.00)
4. **Semantic versioning:** Major.Minor.Patch (03.06.00)
### Code Quality

View File

@@ -10,7 +10,7 @@
INGROUP: Moko-Cassiopeia
REPO: https://github.com/mokoconsulting-tech/moko-cassiopeia
PATH: ./templates/moko-cassiopeia/component.php
VERSION: 03.05.00
VERSION: 03.06.00
BRIEF: Main template index file for Moko-Cassiopeia rendering site layout
*/

View File

@@ -10,7 +10,7 @@
INGROUP: Moko-Cassiopeia
REPO: https://github.com/mokoconsulting-tech/moko-cassiopeia
PATH: ./templates/moko-cassiopeia/custom.php
VERSION: 03.05.00
VERSION: 03.06.00
BRIEF: Custom entry template file for Moko-Cassiopeia with user-defined overrides
*/

View File

@@ -10,7 +10,7 @@
INGROUP: Moko-Cassiopeia
REPO: https://github.com/mokoconsulting-tech/moko-cassiopeia
PATH: ./templates/moko-cassiopeia/error.php
VERSION: 03.05.00
VERSION: 03.06.00
BRIEF: Error page template file for Moko-Cassiopeia
*/
@@ -26,72 +26,154 @@ $app = Factory::getApplication();
$params = $this->params;
copilot-pull-request-reviewer[bot] commented 2026-01-22 16:19:06 +00:00 (Migrated from github.com)
Review

The inline comment for template.global.social-media-demo says it loads css/user.css, but in src/templates/joomla.asset.json this asset points to css/global/social-media-demo.css. Please correct the comment to avoid confusion when tracing which CSS is being loaded.

$wa->useStyle('template.global.social-media-demo');   // css/global/social-media-demo.css
The inline comment for `template.global.social-media-demo` says it loads `css/user.css`, but in `src/templates/joomla.asset.json` this asset points to `css/global/social-media-demo.css`. Please correct the comment to avoid confusion when tracing which CSS is being loaded. ```suggestion $wa->useStyle('template.global.social-media-demo'); // css/global/social-media-demo.css ```
copilot-pull-request-reviewer[bot] commented 2026-01-22 16:19:06 +00:00 (Migrated from github.com)
Review

$brandEnabled and $siteDescription are now assigned but no longer used in this template (brand/description are read directly from $this->params later). Please remove these unused variables (or switch the later checks to use them) to avoid dead code and keep params handling consistent.


`$brandEnabled` and `$siteDescription` are now assigned but no longer used in this template (brand/description are read directly from `$this->params` later). Please remove these unused variables (or switch the later checks to use them) to avoid dead code and keep params handling consistent. ```suggestion ```
copilot-swe-agent[bot] commented 2026-01-23 03:19:56 +00:00 (Migrated from github.com)
Review

Fixed in commit 336a3ae - corrected comment to reflect actual asset path css/global/social-media-demo.css.

Fixed in commit 336a3ae - corrected comment to reflect actual asset path `css/global/social-media-demo.css`.
copilot-swe-agent[bot] commented 2026-01-23 03:19:58 +00:00 (Migrated from github.com)
Review

Fixed in commit 336a3ae - removed unused variables $brandEnabled and $siteDescription as they are accessed directly from $this->params in the template.

Fixed in commit 336a3ae - removed unused variables `$brandEnabled` and `$siteDescription` as they are accessed directly from `$this->params` in the template.
$wa = $this->getWebAssetManager();
// Template params
$params_LightColorName = (string) $params->get('colorLightName', 'colors_standard'); // colors_standard|colors_alternative|colors_custom
$params_DarkColorName = (string) $params->get('colorDarkName', 'colors_standard'); // colors_standard|colors_alternative|colors_custom
$params_googletagmanager = $params->get('googletagmanager', false);
$params_googletagmanagerid = $params->get('googletagmanagerid', '');
$params_googleanalytics = $params->get('googleanalytics', false);
$params_googleanalyticsid = $params->get('googleanalyticsid', '');
$params_custom_head_start = $params->get('custom_head_start', '');
$params_custom_head_end = $params->get('custom_head_end', '');
$params_developmentmode = $params->get('developmentmode', false);
// Bootstrap behaviors (assets handled via WAM)
HTMLHelper::_('bootstrap.framework');
HTMLHelper::_('bootstrap.loadCss', true);
HTMLHelper::_('bootstrap.alert');
HTMLHelper::_('bootstrap.button');
HTMLHelper::_('bootstrap.carousel');
HTMLHelper::_('bootstrap.collapse');
HTMLHelper::_('bootstrap.dropdown');
HTMLHelper::_('bootstrap.modal');
HTMLHelper::_('bootstrap.offcanvas');
HTMLHelper::_('bootstrap.popover');
HTMLHelper::_('bootstrap.scrollspy');
HTMLHelper::_('bootstrap.tab');
HTMLHelper::_('bootstrap.tooltip');
HTMLHelper::_('bootstrap.toast');
// ------------------ Params ------------------
$colorLight = (string) $params->get('colorLightName', 'colors_standard');
$colorDark = (string) $params->get('colorDarkName', 'colors_standard');
$themeFab = (int) $params->get('theme_fab_enabled', 1);
$fABodyPos = (string) $params->get('theme_fab_pos', 'br');
$gtmEnabled = (int) $params->get('googletagmanager', 0);
$gtmId = (string) $params->get('googletagmanagerid', '');
$fa6KitCode = (string) $params->get('fA6KitCode', '');
$stickyHeader = (bool) $params->get('stickyHeader', 0);
$brandEnabled = (int) $params->get('brand', 1);
$siteDescription = (string) $params->get('siteDescription', '');
// Drawer icon params (escaped)
$params_leftIcon = htmlspecialchars($params->get('drawerLeftIcon', 'fa-solid fa-chevron-right'), ENT_QUOTES, 'UTF-8');
$params_rightIcon = htmlspecialchars($params->get('drawerRightIcon', 'fa-solid fa-chevron-left'), ENT_QUOTES, 'UTF-8');
$params_leftIcon = htmlspecialchars($params->get('drawerLeftIcon', 'fa-solid fa-chevron-left'), ENT_QUOTES, 'UTF-8');
$params_rightIcon = htmlspecialchars($params->get('drawerRightIcon', 'fa-solid fa-chevron-right'), ENT_QUOTES, 'UTF-8');
// ------------------ Styles ------------------
$wa->useStyle('template.base');
$wa->useStyle('template.user');
// Template/Media path
$templatePath = 'media/templates/site/moko-cassiopeia';
// Light/Dark variable sheets (load before consumers)
if ($wa->assetExists('style', 'template.light.' . $colorLight)) {
$wa->useStyle('template.light.' . $colorLight);
// ===========================
// Web Asset Manager (WAM) — matches your joomla.asset.json
// ===========================
// Core template CSS
$wa->useStyle('template.global.base'); // css/template.css
$wa->useStyle('template.global.social-media-demo'); // css/global/social-media-demo.css
// Optional vendor CSS
$wa->useStyle('vendor.bootstrap-toc');
// Color theme (light + optional dark)
$colorLightKey = strtolower(preg_replace('/[^a-z0-9_.-]/i', '', $params_LightColorName));
$colorDarkKey = strtolower(preg_replace('/[^a-z0-9_.-]/i', '', $params_DarkColorName));
$lightKey = 'template.light.' . $colorLightKey;
$darkKey = 'template.dark.' . $colorDarkKey;
try {
$wa->useStyle('template.light.colors_standard');
} catch (\Throwable $e) {
$wa->registerAndUseStyle('template.light.colors_standard', $templatePath . '/css/global/light/colors_standard.css');
}
if ($wa->assetExists('style', 'template.dark.' . $colorDark)) {
$wa->useStyle('template.dark.' . $colorDark);
try {
$wa->useStyle('template.dark.colors_standard');
} catch (\Throwable $e) {
$wa->registerAndUseStyle('template.dark.colors_standard', $templatePath . '/css/global/dark/colors_standard.css');
}
try {
$wa->useStyle($lightKey);
} catch (\Throwable $e) {
$wa->registerAndUseStyle('template.light.dynamic', $templatePath . '/css/global/light/' . $colorLightKey . '.css');
}
try {
$wa->useStyle($darkKey);
} catch (\Throwable $e) {
$wa->registerAndUseStyle('template.dark.dynamic', $templatePath . '/css/global/dark/' . $colorDarkKey . '.css');
}
// ------------------ Scripts ------------------
// Scripts
$wa->useScript('template.js');
$wa->useScript('theme-init.js');
if ($themeFab === 1) {
$wa->useScript('darkmode-toggle.js');
}
if ($gtmEnabled === 1) {
$wa->useScript('gtm.js');
$wa->useScript('darkmode-toggle.js');
$wa->useScript('vendor.bootstrap-toc.js');
// Meta
$this->setMetaData('viewport', 'width=device-width, initial-scale=1');
if ($this->params->get('faKitCode')) {
$faKit = "https://kit.fontawesome.com/" . $this->params->get('faKitCode') . ".js";
HTMLHelper::_('script', $faKit, ['crossorigin' => 'anonymous']);
} else {
try {
if ($params_developmentmode){
$wa->useStyle('vendor.fa7free.all');
$wa->useStyle('vendor.fa7free.brands');
$wa->useStyle('vendor.fa7free.fontawesome');
$wa->useStyle('vendor.fa7free.regular');
$wa->useStyle('vendor.fa7free.solid');
} else {
$wa->useStyle('vendor.fa7free.all.min');
$wa->useStyle('vendor.fa7free.brands.min');
$wa->useStyle('vendor.fa7free.fontawesome.min');
$wa->useStyle('vendor.fa7free.regular.min');
$wa->useStyle('vendor.fa7free.solid.min');
}
} catch (\Throwable $e) {
if ($params_developmentmode){
$wa->registerAndUseStyle('vendor.fa7free.all.dynamic', $templatePath . '/vendor/fa7free/css/all.css');
$wa->registerAndUseStyle('vendor.fa7free.brands.dynamic', $templatePath . '/vendor/fa7free/css/brands.css');
$wa->registerAndUseStyle('vendor.fa7free.fontawesome.dynamic', $templatePath . '/vendor/fa7free/css/fontawesome.css');
$wa->registerAndUseStyle('vendor.fa7free.regular.dynamic', $templatePath . '/vendor/fa7free/css/regular.css');
$wa->registerAndUseStyle('vendor.fa7free.solid.dynamic', $templatePath . '/vendor/fa7free/css/solid.css');
} else {
$wa->registerAndUseStyle('vendor.fa7free.all.min.dynamic', $templatePath . '/vendor/fa7free/css/all.min.css');
$wa->registerAndUseStyle('vendor.fa7free.brands.min.dynamic', $templatePath . '/vendor/fa7free/css/brands.min.css');
$wa->registerAndUseStyle('vendor.fa7free.fontawesome.min.dynamic', $templatePath . '/vendor/fa7free/css/fontawesome.min.css');
$wa->registerAndUseStyle('vendor.fa7free.regular.min.dynamic', $templatePath . '/vendor/fa7free/css/regular.min.css');
$wa->registerAndUseStyle('vendor.fa7free.solid.min.dynamic', $templatePath . '/vendor/fa7free/css/solid.min.css');
}
}
}
// Optional Font Awesome 6 Kit (preferred) or FA5 fallback
if (!empty($fa6KitCode)) {
HTMLHelper::_('script', 'https://kit.fontawesome.com/' . rawurlencode($fa6KitCode) . '.js', [
'crossorigin' => 'anonymous'
]);
} else {
HTMLHelper::_('stylesheet', 'https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.4/css/all.min.css', ['version' => 'auto'], [
'crossorigin' => 'anonymous',
'referrerpolicy' => 'no-referrer',
]);
}
$wa->useStyle('template.user'); // css/user.css
// ------------------ Context (logo, bootstrap needs) ------------------
$sitename = htmlspecialchars($app->get('sitename'), ENT_QUOTES, 'UTF-8');
// Build logo/title
if ($params->get('logoFile')) {
$logo = HTMLHelper::_(
// -------------------------------------
// Brand: logo from params OR siteTitle
// -------------------------------------
$brandHtml = '';
$logoFile = (string) $this->params->get('logoFile');
if ($logoFile !== '') {
$brandHtml = HTMLHelper::_(
'image',
Uri::root(false) . htmlspecialchars($params->get('logoFile'), ENT_QUOTES),
Uri::root(false) . htmlspecialchars($logoFile, ENT_QUOTES, 'UTF-8'),
$sitename,
['loading' => 'eager', 'decoding' => 'async'],
['class' => 'logo d-inline-block', 'loading' => 'eager', 'decoding' => 'async'],
false,
0
);
} elseif ($params->get('siteTitle')) {
$logo = '<span title="' . $sitename . '">' . htmlspecialchars($params->get('siteTitle'), ENT_COMPAT, 'UTF-8') . '</span>';
} elseif ($this->params->get('siteTitle')) {
$brandHtml = '<span class="site-title" title="' . $sitename . '">'
. htmlspecialchars($this->params->get('siteTitle'), ENT_COMPAT, 'UTF-8')
. '</span>';
} else {
$logo = HTMLHelper::_('image', 'full_logo.png', $sitename, ['class' => 'logo d-inline-block', 'loading' => 'eager', 'decoding' => 'async'], true, 0);
// Fallback to a bundled image (relative to media paths)
copilot-pull-request-reviewer[bot] commented 2026-01-22 16:19:05 +00:00 (Migrated from github.com)
Review

This file now loads Font Awesome 7 CSS (or a kit fallback). However, later in this template the button icons still use Font Awesome 5 class names (fas ...). Without a v4/v5 shim these may not render. Either enable/include a compatibility shim for the kit/CSS, or update the template’s icon markup to the FA7 class syntax used elsewhere (e.g., fa-solid ...).

This file now loads Font Awesome 7 CSS (or a kit fallback). However, later in this template the button icons still use Font Awesome 5 class names (`fas ...`). Without a v4/v5 shim these may not render. Either enable/include a compatibility shim for the kit/CSS, or update the template’s icon markup to the FA7 class syntax used elsewhere (e.g., `fa-solid ...`).
copilot-swe-agent[bot] commented 2026-01-23 03:19:53 +00:00 (Migrated from github.com)
Review

Fixed in commit 336a3ae - updated icon classes from fas to fa-solid to match Font Awesome 7 syntax used throughout the template.

Fixed in commit 336a3ae - updated icon classes from `fas` to `fa-solid` to match Font Awesome 7 syntax used throughout the template.
$brandHtml = HTMLHelper::_('image', 'full_logo.png', $sitename, ['class' => 'logo d-inline-block', 'loading' => 'eager', 'decoding' => 'async'], true, 0);
}
// ------------------ Error details ------------------
@@ -103,23 +185,105 @@ $debugOn = defined('JDEBUG') && JDEBUG;
<!DOCTYPE html>
<html lang="<?php echo $this->language; ?>" dir="<?php echo $this->direction; ?>">
<head>
copilot-pull-request-reviewer[bot] commented 2026-01-22 16:19:05 +00:00 (Migrated from github.com)
Review

Same issue as custom_head_start: trim($params_custom_head_end) can raise a deprecation warning on PHP 8.1+ when the param is null (default). Use an empty-string default/cast, or guard against null before calling trim().

Same issue as `custom_head_start`: `trim($params_custom_head_end)` can raise a deprecation warning on PHP 8.1+ when the param is `null` (default). Use an empty-string default/cast, or guard against `null` before calling `trim()`.
copilot-pull-request-reviewer[bot] commented 2026-01-22 16:19:06 +00:00 (Migrated from github.com)
Review

trim($params_custom_head_start) will emit a deprecation warning on PHP 8.1+ if the param is null (the default here is null). Consider defaulting these params to an empty string, casting to string before trim(), or using a non-null check (e.g. !== null && trim(...) !== '').

`trim($params_custom_head_start)` will emit a deprecation warning on PHP 8.1+ if the param is `null` (the default here is `null`). Consider defaulting these params to an empty string, casting to string before `trim()`, or using a non-null check (e.g. `!== null && trim(...) !== ''`).
copilot-swe-agent[bot] commented 2026-01-23 03:19:43 +00:00 (Migrated from github.com)
Review

Fixed in commit 336a3ae - changed default values from null to empty string '' for custom_head_start and custom_head_end parameters to prevent PHP 8.1+ deprecation warnings.

Fixed in commit 336a3ae - changed default values from `null` to empty string `''` for custom_head_start and custom_head_end parameters to prevent PHP 8.1+ deprecation warnings.
copilot-swe-agent[bot] commented 2026-01-23 03:19:46 +00:00 (Migrated from github.com)
Review

Fixed in commit 336a3ae - changed default value from null to empty string '' and removed trim() call.

Fixed in commit 336a3ae - changed default value from `null` to empty string `''` and removed trim() call.
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="theme-color" content="#ffffff" id="meta-theme-color" />
<?php if ($params_custom_head_start !== '') : ?><?php echo $params_custom_head_start; ?><?php endif; ?>
<jdoc:include type="head" />
<script>
// Early theme application to avoid FOUC
(function () {
try {
var stored = localStorage.getItem('theme');
var prefersDark = window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches;
var theme = stored ? stored : (prefersDark ? 'dark' : 'light');
document.documentElement.setAttribute('data-bs-theme', theme);
} catch (e) {}
})();
</script>
<script>
// Facebook in-app browser warning banner
window.addEventListener('DOMContentLoaded', function () {
var ua = navigator.userAgent || navigator.vendor || window.opera;
var isFacebookBrowser = ua.indexOf('FBAN') > -1 || ua.indexOf('FBAV') > -1;
if (isFacebookBrowser) {
var warning = document.createElement('div');
warning.textContent = '⚠️ KNOWN ISSUE: Images do not load in Facebook Web browser. Please open in external browser for full experience.';
warning.style.position = 'fixed';
warning.style.top = '0';
warning.style.left = '0';
warning.style.right = '0';
warning.style.zIndex = '10000';
warning.style.backgroundColor = '#007bff';
warning.style.color = '#fff';
warning.style.padding = '15px';
warning.style.textAlign = 'center';
warning.style.fontWeight = 'bold';
warning.style.fontSize = '16px';
warning.style.boxShadow = '0 2px 5px rgba(0,0,0,0.2)';
document.body.appendChild(warning);
}
});
</script>
<?php if ($params_custom_head_end !== '') : ?><?php echo $params_custom_head_end; ?><?php endif; ?>
</head>
<body data-theme-fab-pos="<?php echo htmlspecialchars($fABodyPos, ENT_QUOTES, 'UTF-8'); ?>">
<?php if ($gtmEnabled === 1 && !empty($gtmId)) : ?>
<body data-bs-spy="scroll" data-bs-target="#toc" class="site error-page<?php
echo ($this->direction == 'rtl' ? ' rtl' : '');
?>">
<?php if (!empty($params_googletagmanager) && !empty($params_googletagmanagerid)) : ?>
<!-- Google Tag Manager -->
<script>
(function(w,d,s,l,i){
w[l]=w[l]||[];
w[l].push({'gtm.start': new Date().getTime(), event:'gtm.js'});
var f=d.getElementsByTagName(s)[0],
j=d.createElement(s),
dl=l!='dataLayer'?'&l='+l:'';
j.async=true;
j.src='https://www.googletagmanager.com/gtm.js?id='+i+dl;
f.parentNode.insertBefore(j,f);
})(window,document,'script','dataLayer',<?php echo json_encode($params_googletagmanagerid, JSON_HEX_TAG | JSON_HEX_AMP); ?>);
</script>
<!-- End Google Tag Manager -->
<!-- Google Tag Manager (noscript) -->
<noscript>
<iframe src="https://www.googletagmanager.com/ns.html?id=<?php echo htmlspecialchars($gtmId, ENT_QUOTES, 'UTF-8'); ?>"
<iframe src="https://www.googletagmanager.com/ns.html?id=<?php echo htmlspecialchars($params_googletagmanagerid, ENT_QUOTES, 'UTF-8'); ?>"
height="0" width="0" style="display:none;visibility:hidden"></iframe>
</noscript>
<!-- End Google Tag Manager (noscript) -->
<?php endif; ?>
<!-- ========== DUPLICATED HEADER FROM INDEX ========== -->
<header class="header container-header full-width<?php echo $stickyHeader ? ' position-sticky sticky-top' : ''; ?>">
<?php if (!empty($params_googleanalytics) && !empty($params_googleanalyticsid)) : ?>
<!-- Google Analytics (gtag.js) -->
<script async src="https://www.googletagmanager.com/gtag/js?id=<?php echo htmlspecialchars($params_googleanalyticsid, ENT_QUOTES, 'UTF-8'); ?>"></script>
<script>
window.dataLayer = window.dataLayer || [];
function gtag(){dataLayer.push(arguments);}
gtag('js', new Date());
gtag('consent', 'default', {
'ad_storage': 'denied',
'analytics_storage': 'granted',
'ad_user_data': 'denied',
'ad_personalization': 'denied'
});
(function(id){
if (/^G-/.test(id)) {
gtag('config', id, { 'anonymize_ip': true });
} else if (/^UA-/.test(id)) {
gtag('config', id, { 'anonymize_ip': true });
console.warn('Using a UA- ID. Universal Analytics is sunset; consider migrating to GA4.');
} else {
console.warn('Unrecognized Google Analytics ID format:', id);
}
})(<?php echo json_encode($params_googleanalyticsid, JSON_HEX_TAG | JSON_HEX_AMP); ?>);
</script>
<!-- End Google Analytics -->
<?php endif; ?>
<!-- ========== HEADER FROM INDEX ========== -->
<header class="header container-header full-width<?php echo $stickyHeader ? ' position-sticky sticky-top' : ''; ?>" role="banner">
<?php if ($this->countModules('topbar')) : ?>
<div class="container-topbar">
<jdoc:include type="modules" name="topbar" style="none" />
@@ -133,14 +297,16 @@ $debugOn = defined('JDEBUG') && JDEBUG;
</div>
<?php endif; ?>
<?php if ($brandEnabled) : ?>
<?php if ($this->params->get('brand', 1)) : ?>
<div class="grid-child">
<div class="navbar-brand">
<a class="brand-logo" href="<?php echo $this->baseurl; ?>/">
<?php echo $logo; ?>
<?php echo $brandHtml; ?>
</a>
<?php if (!empty($siteDescription)) : ?>
<div class="site-description"><?php echo htmlspecialchars($siteDescription); ?></div>
<?php if ($this->params->get('siteDescription')) : ?>
<div class="site-description">
<?php echo htmlspecialchars($this->params->get('siteDescription'), ENT_QUOTES, 'UTF-8'); ?>
</div>
<?php endif; ?>
</div>
</div>
@@ -153,10 +319,33 @@ $debugOn = defined('JDEBUG') && JDEBUG;
<?php endif; ?>
</div>
<!-- Drawer Toggle Buttons -->
<?php if ($this->countModules('drawer-left')) : ?>
<button class="drawer-toggle-left btn btn-outline-secondary me-2"
type="button"
data-bs-toggle="offcanvas"
data-bs-target="#drawer-left"
aria-controls="drawer-left">
<span class="<?php echo $params_leftIcon; ?>"></span>
</button>
<?php endif; ?>
<?php if ($this->countModules('drawer-right')) : ?>
<button class="drawer-toggle-right btn btn-outline-secondary"
type="button"
data-bs-toggle="offcanvas"
data-bs-target="#drawer-right"
aria-controls="drawer-right">
<span class="<?php echo $params_rightIcon; ?>"></span>
</button>
<?php endif; ?>
<?php if ($this->countModules('menu', true) || $this->countModules('search', true)) : ?>
<div class="grid-child container-nav">
<?php if ($this->countModules('menu', true)) : ?>
<jdoc:include type="modules" name="menu" style="none" />
<nav role="navigation" aria-label="Primary">
<jdoc:include type="modules" name="menu" style="none" />
</nav>
<?php endif; ?>
<?php if ($this->countModules('search', true)) : ?>
<div class="container-search">
@@ -166,7 +355,7 @@ $debugOn = defined('JDEBUG') && JDEBUG;
</div>
<?php endif; ?>
</header>
<!-- ========== END DUPLICATED HEADER ========== -->
<!-- ========== END HEADER ========== -->
<main class="container my-4">
<div class="card border-0 shadow-sm mb-4">
@@ -186,11 +375,11 @@ $debugOn = defined('JDEBUG') && JDEBUG;
<div class="d-flex gap-2 flex-wrap">
<a class="btn btn-primary" href="<?php echo htmlspecialchars(Uri::base(), ENT_QUOTES, 'UTF-8'); ?>">
<i class="fas fa-home me-1" aria-hidden="true"></i>
<i class="fa-solid fa-home me-1" aria-hidden="true"></i>
<?php echo Text::_('JERROR_LAYOUT_HOME_PAGE'); ?>
</a>
<button class="btn btn-outline-secondary" type="button" onclick="history.back();">
<i class="fas fa-arrow-left me-1" aria-hidden="true"></i>
<i class="fa-solid fa-arrow-left me-1" aria-hidden="true"></i>
<?php echo Text::_('JPREV'); ?>
</button>
</div>
@@ -245,7 +434,7 @@ $debugOn = defined('JDEBUG') && JDEBUG;
</section>
<?php endif; ?>
</main>
<footer class="container-footer footer full-width py-4">
<footer class="container-footer footer full-width">
<?php if ($this->countModules('footer-menu', true)) : ?>
<div class="grid-child footer-menu">
<jdoc:include type="modules" name="footer-menu" />
@@ -258,6 +447,37 @@ $debugOn = defined('JDEBUG') && JDEBUG;
<?php endif; ?>
</footer>
<?php if ($this->params->get('backTop') == 1) : ?>
<a href="#top" id="back-top" class="back-to-top-link" aria-label="<?php echo Text::_('TPL_MOKO-CASSIOPEIA_BACKTOTOP'); ?>">
<span class="icon-arrow-up icon-fw" aria-hidden="true"></span>
</a>
<?php endif; ?>
<?php if ($this->countModules('drawer-left', true)) : ?>
<!-- Left Offcanvas Drawer -->
<aside class="offcanvas offcanvas-start" tabindex="-1" id="drawer-left">
<div class="offcanvas-header">
<button type="button" class="btn-close text-reset" data-bs-dismiss="offcanvas" aria-label="<?php echo Text::_('JLIB_HTML_BEHAVIOR_CLOSE'); ?>"></button>
copilot-pull-request-reviewer[bot] commented 2026-01-22 16:19:05 +00:00 (Migrated from github.com)
Review

The GTM ID is embedded into an inline <script> as a JS string using htmlspecialchars(). HTML escaping is not sufficient for JavaScript string context (e.g., an ID containing a ' can break out of the string). Use json_encode($gtmID) (or encode the raw param) when injecting into JS to ensure proper escaping for JS context.

The GTM ID is embedded into an inline `<script>` as a JS string using `htmlspecialchars()`. HTML escaping is not sufficient for JavaScript string context (e.g., an ID containing a `'` can break out of the string). Use `json_encode($gtmID)` (or encode the raw param) when injecting into JS to ensure proper escaping for JS context.
copilot-swe-agent[bot] commented 2026-01-23 03:19:48 +00:00 (Migrated from github.com)
Review

Fixed in commit 336a3ae - replaced htmlspecialchars() with json_encode($params_googletagmanagerid, JSON_HEX_TAG | JSON_HEX_AMP) for proper JavaScript context escaping.

Fixed in commit 336a3ae - replaced `htmlspecialchars()` with `json_encode($params_googletagmanagerid, JSON_HEX_TAG | JSON_HEX_AMP)` for proper JavaScript context escaping.
</div>
<div class="offcanvas-body">
<jdoc:include type="modules" name="drawer-left" style="none" />
</div>
</aside>
<?php endif; ?>
<?php if ($this->countModules('drawer-right', true)) : ?>
<!-- Right Offcanvas Drawer -->
<aside class="offcanvas offcanvas-end" tabindex="-1" id="drawer-right">
<div class="offcanvas-header">
<button type="button" class="btn-close text-reset" data-bs-dismiss="offcanvas" aria-label="<?php echo Text::_('JLIB_HTML_BEHAVIOR_CLOSE'); ?>"></button>
</div>
<div class="offcanvas-body">
<jdoc:include type="modules" name="drawer-right" style="none" />
</div>
</aside>
<?php endif; ?>
<jdoc:include type="modules" name="debug" style="none" />
</body>
</html>

View File

@@ -10,7 +10,7 @@
INGROUP: Moko-Cassiopeia
REPO: https://github.com/mokoconsulting-tech/moko-cassiopeia
PATH: ./templates/moko-cassiopeia/html/com_content/article/toc-left.php
VERSION: 03.05.00
VERSION: 03.06.00
BRIEF: Template override for Joomla articles with Table of Contents aligned left
*/

View File

@@ -10,7 +10,7 @@
INGROUP: Moko-Cassiopeia
REPO: https://github.com/mokoconsulting-tech/moko-cassiopeia
PATH: ./templates/moko-cassiopeia/html/com_content/article/toc-right.php
VERSION: 03.05.00
VERSION: 03.06.00
BRIEF: Template override for Joomla articles with Table of Contents aligned right
*/

View File

@@ -10,7 +10,7 @@
INGROUP: Moko-Cassiopeia
REPO: https://github.com/mokoconsulting-tech/moko-cassiopeia
PATH: ./templates/moko-cassiopeia/index.php
VERSION: 03.05.00
VERSION: 03.06.00
BRIEF: Main template index file for Moko-Cassiopeia rendering site layout
*/

View File

@@ -17,7 +17,7 @@
"defgroup": "Joomla.Template.Site",
"ingroup": "Moko-Cassiopeia.Template.Assets",
"path": "./media/templates/site/moko-cassiopeia/joomla.asset.json",
"version": "03.00.00",
"version": "03.06.00",
"brief": "Joomla asset registry for Moko-Cassiopeia"
}
},

View File

@@ -10,7 +10,7 @@
INGROUP: Moko-Cassiopeia
REPO: https://github.com/mokoconsulting-tech/moko-cassiopeia
PATH: ./templates/moko-cassiopeia/offline.php
VERSION: 03.05.00
VERSION: 03.06.00
BRIEF: Offline page template file for Moko-Cassiopeia
*/

View File

@@ -11,7 +11,7 @@
DEFGROUP: Joomla
INGROUP: Moko-Cassiopeia
PATH: templates/moko-cassiopeia/templateDetails.xml
VERSION: 03.05.00
VERSION: 03.06.00
BRIEF: Template manifest XML file for Moko-Cassiopeia
=========================================================================
-->
@@ -22,7 +22,7 @@
</server>
</updateservers>
<name>moko-cassiopeia</name>
<version>03.05.00</version>
<version>03.06.00</version>
<creationDate>2025-12-23</creationDate>
<author>Jonathan Miller || Moko Consulting</author>
<authorEmail>hello@mokoconsulting.tech</authorEmail>

View File

@@ -10,7 +10,7 @@
INGROUP: Moko-Cassiopeia
REPO: https://github.com/mokoconsulting-tech/moko-cassiopeia
PATH: ./updates.xml
VERSION: 03.05.00
VERSION: 03.06.00
BRIEF: Update manifest XML file for Moko-Cassiopeia
-->
@@ -22,7 +22,7 @@
<type>template</type>
<client>site</client>
<version>03.05.00</version>
<version>03.06.00</version>
<creationDate>2025-12-12</creationDate>
<author>Jonathan Miller || Moko Consulting</author>
<authorEmail>hello@mokoconsulting.tech</authorEmail>