- showtitle) : ?>
+ title;
+ $showTitle = ($contentSource === 'article' && $useArticleTitle && $articleTitle) || $module->showtitle;
+ ?>
+
style="animation-delay: ms;" data-card-delay="">
- showtitle) : ?>
-
title, ENT_QUOTES, 'UTF-8'); ?>
+
+
- showtitle) : ?>
-
title, ENT_QUOTES, 'UTF-8'); ?>
+
+
diff --git a/src/packages/plg_system_mokojoomhero/src/Extension/MokoJoomHero.php b/src/packages/plg_system_mokojoomhero/src/Extension/MokoJoomHero.php
index 85be0eb..76adee4 100644
--- a/src/packages/plg_system_mokojoomhero/src/Extension/MokoJoomHero.php
+++ b/src/packages/plg_system_mokojoomhero/src/Extension/MokoJoomHero.php
@@ -13,7 +13,6 @@ namespace Joomla\Plugin\System\MokoJoomHero\Extension;
defined('_JEXEC') or die;
-use Joomla\CMS\Factory;
use Joomla\CMS\Plugin\CMSPlugin;
use Joomla\Event\SubscriberInterface;
@@ -21,74 +20,6 @@ class MokoJoomHero extends CMSPlugin implements SubscriberInterface
{
public static function getSubscribedEvents(): array
{
- return [
- 'onAfterRoute' => 'onAfterRoute',
- ];
- }
-
- public function onAfterRoute(): void
- {
- $app = $this->getApplication();
-
- if ($app->isClient('administrator')) {
- $this->warnMissingLicenseKey();
- }
- }
-
- /**
- * Warn administrators once per session when no license key is configured.
- *
- * @return void
- */
- private function warnMissingLicenseKey(): void
- {
- $session = Factory::getSession();
-
- if ($session->get('mokojoomhero.license_warned', false)) {
- return;
- }
-
- $user = Factory::getUser();
-
- if ($user->guest || !$user->authorise('core.manage')) {
- return;
- }
-
- $session->set('mokojoomhero.license_warned', true);
-
- try {
- $db = Factory::getDbo();
-
- $query = $db->getQuery(true)
- ->select($db->quoteName('extra_query'))
- ->from($db->quoteName('#__update_sites'))
- ->where($db->quoteName('name') . ' = ' . $db->quote('MokoJoomHero Updates'))
- ->setLimit(1);
- $db->setQuery($query);
- $extraQuery = (string) $db->loadResult();
-
- if (!empty($extraQuery)) {
- parse_str($extraQuery, $parsed);
-
- if (!empty($parsed['dlid']) && preg_match('/^MOKO-[A-Z0-9]{4}-[A-Z0-9]{4}-[A-Z0-9]{4}-[A-Z0-9]{4}$/', $parsed['dlid'])) {
- return;
- }
- }
-
- $this->getApplication()->enqueueMessage(
- '
Moko Consulting License Key Required — '
- . 'No download key is configured. Updates will not be available until a valid license key is entered. '
- . 'Go to
System → Update Sites '
- . 'and enter your license key (
MOKO-XXXX-XXXX-XXXX-XXXX) in the Download Key field '
- . 'for the MokoJoomHero update site.',
- 'warning'
- );
- } catch (\Exception $e) {
- // Don't break admin over a license check — log for diagnostics
- $this->getApplication()->getLogger()->warning(
- 'MokoJoomHero license check failed: ' . $e->getMessage(),
- ['exception' => $e]
- );
- }
+ return [];
}
}
--
2.52.0
From c3a4a1f28d56d7448c920f58bbda8353ea9b2e7b Mon Sep 17 00:00:00 2001
From: Jonathan Miller
Date: Thu, 4 Jun 2026 07:58:34 -0500
Subject: [PATCH 26/27] =?UTF-8?q?fix:=20final=20review=20=E2=80=94=20loggi?=
=?UTF-8?q?ng,=20null=20guards,=20XSS=20filter,=20stale=20descriptions?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Add Joomla Log::add for article query, DirectoryIterator, and JSON
decode failures. Filter article content through HTMLHelper content.prepare
to prevent XSS. Add null guards on scroll indicator and mute toggle
hero/icon elements. Add console.warn on slide content JSON parse failure.
Remove stale license key references from package and plugin descriptions.
Authored-by: Moko Consulting
Co-Authored-By: Claude Opus 4.6 (1M context)
---
.../media/js/mod_mokojoomhero.js | 17 +++++++++++--
.../mod_mokojoomhero/mod_mokojoomhero.php | 25 ++++++++++++++++---
.../en-GB/plg_system_mokojoomhero.sys.ini | 2 +-
.../en-US/plg_system_mokojoomhero.sys.ini | 2 +-
src/pkg_mokojoomhero.xml | 2 +-
5 files changed, 39 insertions(+), 9 deletions(-)
diff --git a/src/packages/mod_mokojoomhero/media/js/mod_mokojoomhero.js b/src/packages/mod_mokojoomhero/media/js/mod_mokojoomhero.js
index a208e55..2f4c5dd 100644
--- a/src/packages/mod_mokojoomhero/media/js/mod_mokojoomhero.js
+++ b/src/packages/mod_mokojoomhero/media/js/mod_mokojoomhero.js
@@ -37,6 +37,7 @@ document.addEventListener('DOMContentLoaded', function () {
try {
slideContentData = JSON.parse(hero.dataset.slideContent);
} catch (e) {
+ console.warn('MokoJoomHero: Failed to parse slide content data:', e.message);
slideContentData = null;
}
}
@@ -231,6 +232,10 @@ document.addEventListener('DOMContentLoaded', function () {
document.querySelectorAll('.mokojoomhero__scroll-indicator').forEach(function (btn) {
var hero = btn.closest('.mokojoomhero');
+ if (!hero) {
+ return;
+ }
+
btn.addEventListener('click', function () {
var nextEl = hero.nextElementSibling || hero.parentElement.nextElementSibling;
@@ -255,7 +260,12 @@ document.addEventListener('DOMContentLoaded', function () {
// ── Mute/unmute toggle ──
document.querySelectorAll('.mokojoomhero__mute-toggle').forEach(function (btn) {
- var hero = btn.closest('.mokojoomhero');
+ var hero = btn.closest('.mokojoomhero');
+
+ if (!hero) {
+ return;
+ }
+
var video = hero.querySelector('video.mokojoomhero__video');
var iframe = hero.querySelector('iframe.mokojoomhero__video');
var icon = btn.querySelector('.mokojoomhero__mute-icon');
@@ -279,7 +289,10 @@ document.addEventListener('DOMContentLoaded', function () {
btn.setAttribute('data-muted', muted ? 'false' : 'true');
btn.setAttribute('aria-label', muted ? 'Mute video' : 'Unmute video');
- icon.textContent = muted ? '\u{1F50A}' : '\u{1F507}';
+
+ if (icon) {
+ icon.textContent = muted ? '\u{1F50A}' : '\u{1F507}';
+ }
});
});
});
diff --git a/src/packages/mod_mokojoomhero/mod_mokojoomhero.php b/src/packages/mod_mokojoomhero/mod_mokojoomhero.php
index 853defa..075841b 100644
--- a/src/packages/mod_mokojoomhero/mod_mokojoomhero.php
+++ b/src/packages/mod_mokojoomhero/mod_mokojoomhero.php
@@ -144,7 +144,11 @@ if ($heroMode === 'images') {
}
}
} catch (\UnexpectedValueException $e) {
- // Folder not readable — hero renders without background
+ \Joomla\CMS\Log\Log::add(
+ 'MokoJoomHero: Cannot read image folder "' . $folderPath . '": ' . $e->getMessage(),
+ \Joomla\CMS\Log\Log::WARNING,
+ 'mod_mokojoomhero'
+ );
}
}
}
@@ -186,11 +190,16 @@ if ($contentSource === 'article' && $articleId > 0) {
$article = $db->loadObject();
if ($article) {
- $heroContent = $article->introtext ?: $article->fulltext;
+ $rawContent = $article->introtext ?: $article->fulltext;
+ $heroContent = \Joomla\CMS\HTML\HTMLHelper::_('content.prepare', $rawContent);
$articleTitle = $article->title;
}
- } catch (\Exception $e) {
- // Fall back to manual editor content
+ } catch (\RuntimeException $e) {
+ \Joomla\CMS\Log\Log::add(
+ 'MokoJoomHero: Failed to load article ID ' . $articleId . ': ' . $e->getMessage(),
+ \Joomla\CMS\Log\Log::WARNING,
+ 'mod_mokojoomhero'
+ );
}
}
@@ -200,6 +209,14 @@ $slides = [];
if ($heroMode === 'images' && !empty($slideContent)) {
$slideData = is_string($slideContent) ? json_decode($slideContent, true) : (array) $slideContent;
+ if ($slideData === null && json_last_error() !== JSON_ERROR_NONE) {
+ \Joomla\CMS\Log\Log::add(
+ 'MokoJoomHero: Failed to decode slideContent JSON: ' . json_last_error_msg(),
+ \Joomla\CMS\Log\Log::WARNING,
+ 'mod_mokojoomhero'
+ );
+ }
+
if (is_array($slideData)) {
foreach ($slideData as $item) {
$item = (array) $item;
diff --git a/src/packages/plg_system_mokojoomhero/language/en-GB/plg_system_mokojoomhero.sys.ini b/src/packages/plg_system_mokojoomhero/language/en-GB/plg_system_mokojoomhero.sys.ini
index 7dc0e9f..e8e1ade 100644
--- a/src/packages/plg_system_mokojoomhero/language/en-GB/plg_system_mokojoomhero.sys.ini
+++ b/src/packages/plg_system_mokojoomhero/language/en-GB/plg_system_mokojoomhero.sys.ini
@@ -2,4 +2,4 @@
; SPDX-License-Identifier: GPL-3.0-or-later
PLG_SYSTEM_MOKOJOOMHERO="System - MokoJoomHero"
-PLG_SYSTEM_MOKOJOOMHERO_DESCRIPTION="System plugin for MokoJoomHero — license key validation"
+PLG_SYSTEM_MOKOJOOMHERO_DESCRIPTION="System plugin for MokoJoomHero"
diff --git a/src/packages/plg_system_mokojoomhero/language/en-US/plg_system_mokojoomhero.sys.ini b/src/packages/plg_system_mokojoomhero/language/en-US/plg_system_mokojoomhero.sys.ini
index 7dc0e9f..e8e1ade 100644
--- a/src/packages/plg_system_mokojoomhero/language/en-US/plg_system_mokojoomhero.sys.ini
+++ b/src/packages/plg_system_mokojoomhero/language/en-US/plg_system_mokojoomhero.sys.ini
@@ -2,4 +2,4 @@
; SPDX-License-Identifier: GPL-3.0-or-later
PLG_SYSTEM_MOKOJOOMHERO="System - MokoJoomHero"
-PLG_SYSTEM_MOKOJOOMHERO_DESCRIPTION="System plugin for MokoJoomHero — license key validation"
+PLG_SYSTEM_MOKOJOOMHERO_DESCRIPTION="System plugin for MokoJoomHero"
diff --git a/src/pkg_mokojoomhero.xml b/src/pkg_mokojoomhero.xml
index 1149b1e..a95d66b 100644
--- a/src/pkg_mokojoomhero.xml
+++ b/src/pkg_mokojoomhero.xml
@@ -15,7 +15,7 @@
https://mokoconsulting.tech
Copyright (C) 2026 Moko Consulting. All rights reserved.
GPL-3.0-or-later
- Random hero image slideshow or background video with content overlay. Includes the hero module and system plugin for license key validation. By Moko Consulting.
+ Random hero image slideshow or background video with content overlay. Includes the hero module and system plugin. By Moko Consulting.
pkg_script.php
--
2.52.0
From c38307f98b9c423b7999a2a5c59fec2867cbbed5 Mon Sep 17 00:00:00 2001
From: Jonathan Miller <1+jmiller@noreply.git.mokoconsulting.tech>
Date: Thu, 4 Jun 2026 13:02:21 +0000
Subject: [PATCH 27/27] chore: sync updates.xml 01.08.00-rc from rc [skip ci]
---
updates.xml | 33 +++++++++++++++------------------
1 file changed, 15 insertions(+), 18 deletions(-)
diff --git a/updates.xml b/updates.xml
index e53d9ba..8e97f05 100644
--- a/updates.xml
+++ b/updates.xml
@@ -1,11 +1,10 @@
-
Package - MokoJoomHero
Package - MokoJoomHero development build.
@@ -17,14 +16,12 @@
https://git.mokoconsulting.tech/MokoConsulting/MokoJoomHero/releases/download/development/pkg_mokojoomhero-01.07.00-dev.zip
-
+
dev
Moko Consulting
https://mokoconsulting.tech
-
-
Module - MokoJoomHero
Module - MokoJoomHero dev build.
@@ -83,23 +80,23 @@
- Module - MokoJoomHero
- Module - MokoJoomHero rc build.
- mod_mokojoomhero
- module
+ Package - MokoJoomHero
+ Package - MokoJoomHero rc build.
+ pkg_mokojoomhero
+ package
site
- 01.07.00-rc
- 2026-05-30
- https://git.mokoconsulting.tech/MokoConsulting/MokoJoomHero/releases/tag/release-candidate
+ 01.08.00-rc
+ 2026-06-04
+ https://git.mokoconsulting.tech/MokoConsulting/MokoJoomHero/releases/tag/release-candidate
- https://git.mokoconsulting.tech/MokoConsulting/MokoJoomHero/releases/download/release-candidate/mod_mokojoomhero-01.07.00-rc.zip
+ https://git.mokoconsulting.tech/MokoConsulting/MokoJoomHero/releases/download/release-candidate/pkg_mokojoomhero-01.08.00-rc.zip
- 56ae99ad18e12ee52c60298adef5983aef788fe867d3e3a36957b314ad7eb386
+ 2667e2c0c9b610288232dbb2d9d9ce7aba0c58174b32eb023a4349905cee635a
rc
https://git.mokoconsulting.tech/MokoConsulting/MokoJoomHero/raw/branch/main/CHANGELOG.md
Moko Consulting
https://mokoconsulting.tech
-
+
Module - MokoJoomHero
@@ -109,15 +106,15 @@
site
01.07.00
2026-05-30
- https://git.mokoconsulting.tech/MokoConsulting/MokoJoomHero/releases/tag/stable
+ https://git.mokoconsulting.tech/MokoConsulting/MokoJoomHero/releases/tag/stable
- https://git.mokoconsulting.tech/MokoConsulting/MokoJoomHero/releases/download/stable/mod_mokojoomhero-01.07.00.zip
+ https://git.mokoconsulting.tech/MokoConsulting/MokoJoomHero/releases/download/stable/mod_mokojoomhero-01.07.00.zip
56ae99ad18e12ee52c60298adef5983aef788fe867d3e3a36957b314ad7eb386
stable
https://git.mokoconsulting.tech/MokoConsulting/MokoJoomHero/raw/branch/main/CHANGELOG.md
Moko Consulting
https://mokoconsulting.tech
-
+
--
2.52.0