From 8fe9497c852420d63e344d82e99ab5b3b929013d Mon Sep 17 00:00:00 2001 From: Jonathan Miller Date: Sat, 16 May 2026 09:34:53 -0500 Subject: [PATCH 01/21] feat(plugin): add services/provider.php for Joomla 5 DI registration Joomla 5 requires a service provider to register namespaced plugins with the dependency injection container. Without this file, the plugin does not appear in the plugin manager. Co-Authored-By: Claude Opus 4.6 (1M context) --- src/mokojoomtos.xml | 1 + src/services/provider.php | 44 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 45 insertions(+) create mode 100644 src/services/provider.php diff --git a/src/mokojoomtos.xml b/src/mokojoomtos.xml index 8cb1807..16c5132 100644 --- a/src/mokojoomtos.xml +++ b/src/mokojoomtos.xml @@ -47,6 +47,7 @@ mokojoomtos.php src + services language administrator diff --git a/src/services/provider.php b/src/services/provider.php new file mode 100644 index 0000000..0adb2a9 --- /dev/null +++ b/src/services/provider.php @@ -0,0 +1,44 @@ +set( + PluginInterface::class, + function (Container $container) { + $plugin = new MokoJoomTOS( + $container->get(DispatcherInterface::class), + (array) PluginHelper::getPlugin('system', 'mokojoomtos') + ); + $plugin->setApplication(Factory::getApplication()); + + return $plugin; + } + ); + } +}; -- 2.52.0 From 1092de762f1de0ea18cefd77566c55e4a6e7d998 Mon Sep 17 00:00:00 2001 From: Jonathan Miller Date: Sat, 16 May 2026 09:34:58 -0500 Subject: [PATCH 02/21] fix(lang): update pretty name to Joomla convention [skip ci] Co-Authored-By: Claude Opus 4.6 (1M context) --- src/administrator/language/en-GB/plg_system_mokojoomtos.ini | 2 +- src/administrator/language/en-GB/plg_system_mokojoomtos.sys.ini | 2 +- src/language/en-GB/plg_system_mokojoomtos.ini | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/administrator/language/en-GB/plg_system_mokojoomtos.ini b/src/administrator/language/en-GB/plg_system_mokojoomtos.ini index 21f5649..ef4f17b 100644 --- a/src/administrator/language/en-GB/plg_system_mokojoomtos.ini +++ b/src/administrator/language/en-GB/plg_system_mokojoomtos.ini @@ -3,7 +3,7 @@ ; License GNU General Public License version 3 or later; see LICENSE ; Note: All ini files need to be saved as UTF-8 -PLG_SYSTEM_MOKOJOOMTOS="System - Offline Terms of Service" +PLG_SYSTEM_MOKOJOOMTOS="System - Moko Terms of Service" PLG_SYSTEM_MOKOJOOMTOS_XML_DESCRIPTION="Allows Terms of Service to be accessible via menu slug when the site is in offline mode. Simply configure the menu slug (e.g., 'terms-of-service') and that page will remain accessible even when the site is offline." ; Configuration diff --git a/src/administrator/language/en-GB/plg_system_mokojoomtos.sys.ini b/src/administrator/language/en-GB/plg_system_mokojoomtos.sys.ini index 1a8348e..6c66479 100644 --- a/src/administrator/language/en-GB/plg_system_mokojoomtos.sys.ini +++ b/src/administrator/language/en-GB/plg_system_mokojoomtos.sys.ini @@ -3,5 +3,5 @@ ; License GNU General Public License version 3 or later; see LICENSE ; Note: All ini files need to be saved as UTF-8 -PLG_SYSTEM_MOKOJOOMTOS="System - Offline Terms of Service" +PLG_SYSTEM_MOKOJOOMTOS="System - Moko Terms of Service" PLG_SYSTEM_MOKOJOOMTOS_XML_DESCRIPTION="Allows Terms of Service to be accessible via menu slug when site is offline" diff --git a/src/language/en-GB/plg_system_mokojoomtos.ini b/src/language/en-GB/plg_system_mokojoomtos.ini index 736f3a6..c6848a4 100644 --- a/src/language/en-GB/plg_system_mokojoomtos.ini +++ b/src/language/en-GB/plg_system_mokojoomtos.ini @@ -3,7 +3,7 @@ ; License GNU General Public License version 3 or later; see LICENSE ; Note: All ini files need to be saved as UTF-8 -PLG_SYSTEM_MOKOJOOMTOS="System - Offline Terms of Service" +PLG_SYSTEM_MOKOJOOMTOS="System - Moko Terms of Service" PLG_SYSTEM_MOKOJOOMTOS_XML_DESCRIPTION="Allows Terms of Service to be accessible via menu slug when the site is in offline mode. Simply configure the menu slug (e.g., 'terms-of-service') and that page will remain accessible even when the site is offline." ; Configuration -- 2.52.0 From 6da271b7b26f69aaff8714c5bc76dd2269c69bfe Mon Sep 17 00:00:00 2001 From: Jonathan Miller Date: Sat, 16 May 2026 09:42:36 -0500 Subject: [PATCH 03/21] chore: rename .mokogitea to .gitea Gitea expects .gitea/ as the standard directory for workflows and issue templates. Co-Authored-By: Claude Opus 4.6 (1M context) --- {.mokogitea => .gitea}/ISSUE_TEMPLATE/adr.md | 0 {.mokogitea => .gitea}/ISSUE_TEMPLATE/bug_report.md | 0 {.mokogitea => .gitea}/ISSUE_TEMPLATE/config.yml | 0 {.mokogitea => .gitea}/ISSUE_TEMPLATE/documentation.md | 0 {.mokogitea => .gitea}/ISSUE_TEMPLATE/feature_request.md | 0 {.mokogitea => .gitea}/ISSUE_TEMPLATE/joomla_issue.md | 0 {.mokogitea => .gitea}/ISSUE_TEMPLATE/question.md | 0 {.mokogitea => .gitea}/ISSUE_TEMPLATE/rfc.md | 0 {.mokogitea => .gitea}/ISSUE_TEMPLATE/security.md | 0 {.mokogitea => .gitea}/ISSUE_TEMPLATE/version.md | 0 {.mokogitea => .gitea}/auto-release.yml | 0 {.mokogitea => .gitea}/cascade-dev.yml | 0 {.mokogitea => .gitea}/ci-joomla.yml | 0 {.mokogitea => .gitea}/cleanup.yml | 0 {.mokogitea => .gitea}/deploy-manual.yml | 0 {.mokogitea => .gitea}/gitleaks.yml | 0 {.mokogitea => .gitea}/manifest.xml | 0 {.mokogitea => .gitea}/notify.yml | 0 {.mokogitea => .gitea}/pr-branch-check.yml | 0 {.mokogitea => .gitea}/pr-check.yml | 0 {.mokogitea => .gitea}/pre-release.yml | 0 {.mokogitea => .gitea}/repo-health.yml | 0 {.mokogitea => .gitea}/security-audit.yml | 0 {.mokogitea => .gitea}/update-server.yml | 0 {.mokogitea => .gitea}/workflows/auto-release.yml | 0 {.mokogitea => .gitea}/workflows/cascade-dev.yml | 0 {.mokogitea => .gitea}/workflows/ci-joomla.yml | 0 {.mokogitea => .gitea}/workflows/cleanup.yml | 0 {.mokogitea => .gitea}/workflows/deploy-manual.yml | 0 {.mokogitea => .gitea}/workflows/gitleaks.yml | 0 {.mokogitea => .gitea}/workflows/notify.yml | 0 {.mokogitea => .gitea}/workflows/pr-check.yml | 0 {.mokogitea => .gitea}/workflows/pre-release.yml | 0 {.mokogitea => .gitea}/workflows/repo-health.yml | 0 {.mokogitea => .gitea}/workflows/security-audit.yml | 0 {.mokogitea => .gitea}/workflows/update-server.yml | 0 36 files changed, 0 insertions(+), 0 deletions(-) rename {.mokogitea => .gitea}/ISSUE_TEMPLATE/adr.md (100%) rename {.mokogitea => .gitea}/ISSUE_TEMPLATE/bug_report.md (100%) rename {.mokogitea => .gitea}/ISSUE_TEMPLATE/config.yml (100%) rename {.mokogitea => .gitea}/ISSUE_TEMPLATE/documentation.md (100%) rename {.mokogitea => .gitea}/ISSUE_TEMPLATE/feature_request.md (100%) rename {.mokogitea => .gitea}/ISSUE_TEMPLATE/joomla_issue.md (100%) rename {.mokogitea => .gitea}/ISSUE_TEMPLATE/question.md (100%) rename {.mokogitea => .gitea}/ISSUE_TEMPLATE/rfc.md (100%) rename {.mokogitea => .gitea}/ISSUE_TEMPLATE/security.md (100%) rename {.mokogitea => .gitea}/ISSUE_TEMPLATE/version.md (100%) rename {.mokogitea => .gitea}/auto-release.yml (100%) rename {.mokogitea => .gitea}/cascade-dev.yml (100%) rename {.mokogitea => .gitea}/ci-joomla.yml (100%) rename {.mokogitea => .gitea}/cleanup.yml (100%) rename {.mokogitea => .gitea}/deploy-manual.yml (100%) rename {.mokogitea => .gitea}/gitleaks.yml (100%) rename {.mokogitea => .gitea}/manifest.xml (100%) rename {.mokogitea => .gitea}/notify.yml (100%) rename {.mokogitea => .gitea}/pr-branch-check.yml (100%) rename {.mokogitea => .gitea}/pr-check.yml (100%) rename {.mokogitea => .gitea}/pre-release.yml (100%) rename {.mokogitea => .gitea}/repo-health.yml (100%) rename {.mokogitea => .gitea}/security-audit.yml (100%) rename {.mokogitea => .gitea}/update-server.yml (100%) rename {.mokogitea => .gitea}/workflows/auto-release.yml (100%) rename {.mokogitea => .gitea}/workflows/cascade-dev.yml (100%) rename {.mokogitea => .gitea}/workflows/ci-joomla.yml (100%) rename {.mokogitea => .gitea}/workflows/cleanup.yml (100%) rename {.mokogitea => .gitea}/workflows/deploy-manual.yml (100%) rename {.mokogitea => .gitea}/workflows/gitleaks.yml (100%) rename {.mokogitea => .gitea}/workflows/notify.yml (100%) rename {.mokogitea => .gitea}/workflows/pr-check.yml (100%) rename {.mokogitea => .gitea}/workflows/pre-release.yml (100%) rename {.mokogitea => .gitea}/workflows/repo-health.yml (100%) rename {.mokogitea => .gitea}/workflows/security-audit.yml (100%) rename {.mokogitea => .gitea}/workflows/update-server.yml (100%) diff --git a/.mokogitea/ISSUE_TEMPLATE/adr.md b/.gitea/ISSUE_TEMPLATE/adr.md similarity index 100% rename from .mokogitea/ISSUE_TEMPLATE/adr.md rename to .gitea/ISSUE_TEMPLATE/adr.md diff --git a/.mokogitea/ISSUE_TEMPLATE/bug_report.md b/.gitea/ISSUE_TEMPLATE/bug_report.md similarity index 100% rename from .mokogitea/ISSUE_TEMPLATE/bug_report.md rename to .gitea/ISSUE_TEMPLATE/bug_report.md diff --git a/.mokogitea/ISSUE_TEMPLATE/config.yml b/.gitea/ISSUE_TEMPLATE/config.yml similarity index 100% rename from .mokogitea/ISSUE_TEMPLATE/config.yml rename to .gitea/ISSUE_TEMPLATE/config.yml diff --git a/.mokogitea/ISSUE_TEMPLATE/documentation.md b/.gitea/ISSUE_TEMPLATE/documentation.md similarity index 100% rename from .mokogitea/ISSUE_TEMPLATE/documentation.md rename to .gitea/ISSUE_TEMPLATE/documentation.md diff --git a/.mokogitea/ISSUE_TEMPLATE/feature_request.md b/.gitea/ISSUE_TEMPLATE/feature_request.md similarity index 100% rename from .mokogitea/ISSUE_TEMPLATE/feature_request.md rename to .gitea/ISSUE_TEMPLATE/feature_request.md diff --git a/.mokogitea/ISSUE_TEMPLATE/joomla_issue.md b/.gitea/ISSUE_TEMPLATE/joomla_issue.md similarity index 100% rename from .mokogitea/ISSUE_TEMPLATE/joomla_issue.md rename to .gitea/ISSUE_TEMPLATE/joomla_issue.md diff --git a/.mokogitea/ISSUE_TEMPLATE/question.md b/.gitea/ISSUE_TEMPLATE/question.md similarity index 100% rename from .mokogitea/ISSUE_TEMPLATE/question.md rename to .gitea/ISSUE_TEMPLATE/question.md diff --git a/.mokogitea/ISSUE_TEMPLATE/rfc.md b/.gitea/ISSUE_TEMPLATE/rfc.md similarity index 100% rename from .mokogitea/ISSUE_TEMPLATE/rfc.md rename to .gitea/ISSUE_TEMPLATE/rfc.md diff --git a/.mokogitea/ISSUE_TEMPLATE/security.md b/.gitea/ISSUE_TEMPLATE/security.md similarity index 100% rename from .mokogitea/ISSUE_TEMPLATE/security.md rename to .gitea/ISSUE_TEMPLATE/security.md diff --git a/.mokogitea/ISSUE_TEMPLATE/version.md b/.gitea/ISSUE_TEMPLATE/version.md similarity index 100% rename from .mokogitea/ISSUE_TEMPLATE/version.md rename to .gitea/ISSUE_TEMPLATE/version.md diff --git a/.mokogitea/auto-release.yml b/.gitea/auto-release.yml similarity index 100% rename from .mokogitea/auto-release.yml rename to .gitea/auto-release.yml diff --git a/.mokogitea/cascade-dev.yml b/.gitea/cascade-dev.yml similarity index 100% rename from .mokogitea/cascade-dev.yml rename to .gitea/cascade-dev.yml diff --git a/.mokogitea/ci-joomla.yml b/.gitea/ci-joomla.yml similarity index 100% rename from .mokogitea/ci-joomla.yml rename to .gitea/ci-joomla.yml diff --git a/.mokogitea/cleanup.yml b/.gitea/cleanup.yml similarity index 100% rename from .mokogitea/cleanup.yml rename to .gitea/cleanup.yml diff --git a/.mokogitea/deploy-manual.yml b/.gitea/deploy-manual.yml similarity index 100% rename from .mokogitea/deploy-manual.yml rename to .gitea/deploy-manual.yml diff --git a/.mokogitea/gitleaks.yml b/.gitea/gitleaks.yml similarity index 100% rename from .mokogitea/gitleaks.yml rename to .gitea/gitleaks.yml diff --git a/.mokogitea/manifest.xml b/.gitea/manifest.xml similarity index 100% rename from .mokogitea/manifest.xml rename to .gitea/manifest.xml diff --git a/.mokogitea/notify.yml b/.gitea/notify.yml similarity index 100% rename from .mokogitea/notify.yml rename to .gitea/notify.yml diff --git a/.mokogitea/pr-branch-check.yml b/.gitea/pr-branch-check.yml similarity index 100% rename from .mokogitea/pr-branch-check.yml rename to .gitea/pr-branch-check.yml diff --git a/.mokogitea/pr-check.yml b/.gitea/pr-check.yml similarity index 100% rename from .mokogitea/pr-check.yml rename to .gitea/pr-check.yml diff --git a/.mokogitea/pre-release.yml b/.gitea/pre-release.yml similarity index 100% rename from .mokogitea/pre-release.yml rename to .gitea/pre-release.yml diff --git a/.mokogitea/repo-health.yml b/.gitea/repo-health.yml similarity index 100% rename from .mokogitea/repo-health.yml rename to .gitea/repo-health.yml diff --git a/.mokogitea/security-audit.yml b/.gitea/security-audit.yml similarity index 100% rename from .mokogitea/security-audit.yml rename to .gitea/security-audit.yml diff --git a/.mokogitea/update-server.yml b/.gitea/update-server.yml similarity index 100% rename from .mokogitea/update-server.yml rename to .gitea/update-server.yml diff --git a/.mokogitea/workflows/auto-release.yml b/.gitea/workflows/auto-release.yml similarity index 100% rename from .mokogitea/workflows/auto-release.yml rename to .gitea/workflows/auto-release.yml diff --git a/.mokogitea/workflows/cascade-dev.yml b/.gitea/workflows/cascade-dev.yml similarity index 100% rename from .mokogitea/workflows/cascade-dev.yml rename to .gitea/workflows/cascade-dev.yml diff --git a/.mokogitea/workflows/ci-joomla.yml b/.gitea/workflows/ci-joomla.yml similarity index 100% rename from .mokogitea/workflows/ci-joomla.yml rename to .gitea/workflows/ci-joomla.yml diff --git a/.mokogitea/workflows/cleanup.yml b/.gitea/workflows/cleanup.yml similarity index 100% rename from .mokogitea/workflows/cleanup.yml rename to .gitea/workflows/cleanup.yml diff --git a/.mokogitea/workflows/deploy-manual.yml b/.gitea/workflows/deploy-manual.yml similarity index 100% rename from .mokogitea/workflows/deploy-manual.yml rename to .gitea/workflows/deploy-manual.yml diff --git a/.mokogitea/workflows/gitleaks.yml b/.gitea/workflows/gitleaks.yml similarity index 100% rename from .mokogitea/workflows/gitleaks.yml rename to .gitea/workflows/gitleaks.yml diff --git a/.mokogitea/workflows/notify.yml b/.gitea/workflows/notify.yml similarity index 100% rename from .mokogitea/workflows/notify.yml rename to .gitea/workflows/notify.yml diff --git a/.mokogitea/workflows/pr-check.yml b/.gitea/workflows/pr-check.yml similarity index 100% rename from .mokogitea/workflows/pr-check.yml rename to .gitea/workflows/pr-check.yml diff --git a/.mokogitea/workflows/pre-release.yml b/.gitea/workflows/pre-release.yml similarity index 100% rename from .mokogitea/workflows/pre-release.yml rename to .gitea/workflows/pre-release.yml diff --git a/.mokogitea/workflows/repo-health.yml b/.gitea/workflows/repo-health.yml similarity index 100% rename from .mokogitea/workflows/repo-health.yml rename to .gitea/workflows/repo-health.yml diff --git a/.mokogitea/workflows/security-audit.yml b/.gitea/workflows/security-audit.yml similarity index 100% rename from .mokogitea/workflows/security-audit.yml rename to .gitea/workflows/security-audit.yml diff --git a/.mokogitea/workflows/update-server.yml b/.gitea/workflows/update-server.yml similarity index 100% rename from .mokogitea/workflows/update-server.yml rename to .gitea/workflows/update-server.yml -- 2.52.0 From 2fa69c6a2f58c5310334ab398c01aa8b465c3c80 Mon Sep 17 00:00:00 2001 From: Jonathan Miller Date: Sat, 16 May 2026 12:24:47 -0500 Subject: [PATCH 04/21] fix(plugin): match full route path, support multi-select, update pretty name - Match against menu item path (e.g., legal/terms-of-service) instead of just the alias, fixing offline mode bypass for nested routes - Support multiple menu items via multi-select dropdown - Handle legacy single-value string format for backward compatibility - Use Joomla convention pretty name "System - Moko Terms of Service" - Update field labels and descriptions for multi-select UX Co-Authored-By: Claude Opus 4.6 (1M context) --- .../language/en-GB/plg_system_mokojoomtos.ini | 4 +- .../language/en-US/plg_system_mokojoomtos.ini | 6 +- .../en-US/plg_system_mokojoomtos.sys.ini | 2 +- src/language/en-GB/plg_system_mokojoomtos.ini | 4 +- src/language/en-US/plg_system_mokojoomtos.ini | 6 +- src/mokojoomtos.php | 153 +++++++------- src/mokojoomtos.xml | 3 +- src/src/Extension/MokoJoomTOS.php | 187 +++++++++--------- src/src/Field/MenuslugField.php | 134 +++++++------ 9 files changed, 256 insertions(+), 243 deletions(-) diff --git a/src/administrator/language/en-GB/plg_system_mokojoomtos.ini b/src/administrator/language/en-GB/plg_system_mokojoomtos.ini index ef4f17b..8b6459e 100644 --- a/src/administrator/language/en-GB/plg_system_mokojoomtos.ini +++ b/src/administrator/language/en-GB/plg_system_mokojoomtos.ini @@ -8,8 +8,8 @@ PLG_SYSTEM_MOKOJOOMTOS_XML_DESCRIPTION="Allows Terms of Service to be accessible ; Configuration PLG_SYSTEM_MOKOJOOMTOS_FIELDSET_BASIC="Basic Settings" -PLG_SYSTEM_MOKOJOOMTOS_FIELD_TOS_SLUG_LABEL="Terms of Service Menu Slug" -PLG_SYSTEM_MOKOJOOMTOS_FIELD_TOS_SLUG_DESC="Enter the menu slug for your Terms of Service page (e.g., 'terms-of-service'). This page will be accessible even when the site is offline. The slug must match the menu item alias exactly." +PLG_SYSTEM_MOKOJOOMTOS_FIELD_TOS_SLUG_LABEL="Offline-Accessible Menu Items" +PLG_SYSTEM_MOKOJOOMTOS_FIELD_TOS_SLUG_DESC="Select one or more menu items that should remain accessible when the site is in offline mode. Hold Ctrl/Cmd to select multiple items." ; Help PLG_SYSTEM_MOKOJOOMTOS_HELP_LABEL="How to Use This Plugin" diff --git a/src/administrator/language/en-US/plg_system_mokojoomtos.ini b/src/administrator/language/en-US/plg_system_mokojoomtos.ini index 21f5649..8b6459e 100644 --- a/src/administrator/language/en-US/plg_system_mokojoomtos.ini +++ b/src/administrator/language/en-US/plg_system_mokojoomtos.ini @@ -3,13 +3,13 @@ ; License GNU General Public License version 3 or later; see LICENSE ; Note: All ini files need to be saved as UTF-8 -PLG_SYSTEM_MOKOJOOMTOS="System - Offline Terms of Service" +PLG_SYSTEM_MOKOJOOMTOS="System - Moko Terms of Service" PLG_SYSTEM_MOKOJOOMTOS_XML_DESCRIPTION="Allows Terms of Service to be accessible via menu slug when the site is in offline mode. Simply configure the menu slug (e.g., 'terms-of-service') and that page will remain accessible even when the site is offline." ; Configuration PLG_SYSTEM_MOKOJOOMTOS_FIELDSET_BASIC="Basic Settings" -PLG_SYSTEM_MOKOJOOMTOS_FIELD_TOS_SLUG_LABEL="Terms of Service Menu Slug" -PLG_SYSTEM_MOKOJOOMTOS_FIELD_TOS_SLUG_DESC="Enter the menu slug for your Terms of Service page (e.g., 'terms-of-service'). This page will be accessible even when the site is offline. The slug must match the menu item alias exactly." +PLG_SYSTEM_MOKOJOOMTOS_FIELD_TOS_SLUG_LABEL="Offline-Accessible Menu Items" +PLG_SYSTEM_MOKOJOOMTOS_FIELD_TOS_SLUG_DESC="Select one or more menu items that should remain accessible when the site is in offline mode. Hold Ctrl/Cmd to select multiple items." ; Help PLG_SYSTEM_MOKOJOOMTOS_HELP_LABEL="How to Use This Plugin" diff --git a/src/administrator/language/en-US/plg_system_mokojoomtos.sys.ini b/src/administrator/language/en-US/plg_system_mokojoomtos.sys.ini index 1a8348e..6c66479 100644 --- a/src/administrator/language/en-US/plg_system_mokojoomtos.sys.ini +++ b/src/administrator/language/en-US/plg_system_mokojoomtos.sys.ini @@ -3,5 +3,5 @@ ; License GNU General Public License version 3 or later; see LICENSE ; Note: All ini files need to be saved as UTF-8 -PLG_SYSTEM_MOKOJOOMTOS="System - Offline Terms of Service" +PLG_SYSTEM_MOKOJOOMTOS="System - Moko Terms of Service" PLG_SYSTEM_MOKOJOOMTOS_XML_DESCRIPTION="Allows Terms of Service to be accessible via menu slug when site is offline" diff --git a/src/language/en-GB/plg_system_mokojoomtos.ini b/src/language/en-GB/plg_system_mokojoomtos.ini index c6848a4..46a65cc 100644 --- a/src/language/en-GB/plg_system_mokojoomtos.ini +++ b/src/language/en-GB/plg_system_mokojoomtos.ini @@ -8,8 +8,8 @@ PLG_SYSTEM_MOKOJOOMTOS_XML_DESCRIPTION="Allows Terms of Service to be accessible ; Configuration PLG_SYSTEM_MOKOJOOMTOS_FIELDSET_BASIC="Basic Settings" -PLG_SYSTEM_MOKOJOOMTOS_FIELD_TOS_SLUG_LABEL="Terms of Service Menu Slug" -PLG_SYSTEM_MOKOJOOMTOS_FIELD_TOS_SLUG_DESC="Enter the menu slug for your Terms of Service page (e.g., 'terms-of-service'). This page will be accessible even when the site is offline. The slug must match the menu item alias exactly." +PLG_SYSTEM_MOKOJOOMTOS_FIELD_TOS_SLUG_LABEL="Offline-Accessible Menu Items" +PLG_SYSTEM_MOKOJOOMTOS_FIELD_TOS_SLUG_DESC="Select one or more menu items that should remain accessible when the site is in offline mode. Hold Ctrl/Cmd to select multiple items." ; Help PLG_SYSTEM_MOKOJOOMTOS_HELP_LABEL="How to Use This Plugin" diff --git a/src/language/en-US/plg_system_mokojoomtos.ini b/src/language/en-US/plg_system_mokojoomtos.ini index 736f3a6..46a65cc 100644 --- a/src/language/en-US/plg_system_mokojoomtos.ini +++ b/src/language/en-US/plg_system_mokojoomtos.ini @@ -3,13 +3,13 @@ ; License GNU General Public License version 3 or later; see LICENSE ; Note: All ini files need to be saved as UTF-8 -PLG_SYSTEM_MOKOJOOMTOS="System - Offline Terms of Service" +PLG_SYSTEM_MOKOJOOMTOS="System - Moko Terms of Service" PLG_SYSTEM_MOKOJOOMTOS_XML_DESCRIPTION="Allows Terms of Service to be accessible via menu slug when the site is in offline mode. Simply configure the menu slug (e.g., 'terms-of-service') and that page will remain accessible even when the site is offline." ; Configuration PLG_SYSTEM_MOKOJOOMTOS_FIELDSET_BASIC="Basic Settings" -PLG_SYSTEM_MOKOJOOMTOS_FIELD_TOS_SLUG_LABEL="Terms of Service Menu Slug" -PLG_SYSTEM_MOKOJOOMTOS_FIELD_TOS_SLUG_DESC="Enter the menu slug for your Terms of Service page (e.g., 'terms-of-service'). This page will be accessible even when the site is offline. The slug must match the menu item alias exactly." +PLG_SYSTEM_MOKOJOOMTOS_FIELD_TOS_SLUG_LABEL="Offline-Accessible Menu Items" +PLG_SYSTEM_MOKOJOOMTOS_FIELD_TOS_SLUG_DESC="Select one or more menu items that should remain accessible when the site is in offline mode. Hold Ctrl/Cmd to select multiple items." ; Help PLG_SYSTEM_MOKOJOOMTOS_HELP_LABEL="How to Use This Plugin" diff --git a/src/mokojoomtos.php b/src/mokojoomtos.php index 74906f3..3bf9927 100644 --- a/src/mokojoomtos.php +++ b/src/mokojoomtos.php @@ -8,98 +8,107 @@ defined('_JEXEC') or die; -use Joomla\CMS\Factory; use Joomla\CMS\Plugin\CMSPlugin; use Joomla\CMS\Uri\Uri; /** - * MokoJoomTOS Offline Mode Bypass Plugin + * MokoJoomTOS Offline Mode Bypass Plugin (Legacy) * - * Allows Terms of Service menu to be accessible via slug when the site + * Allows configured menu items to remain accessible when the site * is in offline mode. * * @since 1.0.0 */ class PlgSystemMokojoomtos extends CMSPlugin { - /** - * Load the language file on instantiation. - * - * @var boolean - * @since 1.0.0 - */ - protected $autoloadLanguage = true; + /** + * Load the language file on instantiation. + * + * @var boolean + * @since 1.0.0 + */ + protected $autoloadLanguage = true; - /** - * Application object - * - * @var \Joomla\CMS\Application\CMSApplication - * @since 1.0.0 - */ - protected $app; + /** + * Application object + * + * @var \Joomla\CMS\Application\CMSApplication + * @since 1.0.0 + */ + protected $app; - /** - * After route event handler - * - * Checks if the current request is for the Terms of Service slug and if - * the site is in offline mode. If both conditions are met, temporarily - * disables offline mode and sets component-only view for this request. - * - * This event fires after routing but before template selection, making it - * the correct place to set tmpl=component to prevent template chrome loading. - * - * @return void - * - * @since 03.09.00 - */ - public function onAfterRoute() - { - // Only process for site application - if (!$this->app->isClient('site')) - { - return; - } + /** + * After route event handler + * + * @return void + * + * @since 03.09.00 + */ + public function onAfterRoute() + { + // Only process for site application + if (!$this->app->isClient('site')) + { + return; + } - // Get the global configuration - $config = $this->app->getConfig(); + // Get the global configuration + $config = $this->app->getConfig(); - // Only proceed if site is offline - if (!$config->get('offline')) - { - return; - } + // Only proceed if site is offline + if (!$config->get('offline')) + { + return; + } - // Get the configured Terms of Service slug - $tosSlug = trim($this->params->get('tos_slug', 'terms-of-service')); + // Get the configured slugs (stored as array for multi-select) + $slugs = $this->params->get('tos_slug', []); - if (empty($tosSlug)) - { - return; - } + // Handle legacy single-value string format + if (is_string($slugs)) + { + $slugs = array_filter([trim($slugs)]); + } - // Get the current URI path - $uri = Uri::getInstance(); - $path = trim($uri->getPath(), '/'); + if (empty($slugs)) + { + return; + } - // Remove the base path if present - $base = trim(Uri::base(true), '/'); - if (!empty($base) && strpos($path, $base) === 0) - { - $path = trim(substr($path, strlen($base)), '/'); - } + // Get the current URI path + $uri = Uri::getInstance(); + $path = trim($uri->getPath(), '/'); - // Check if the path matches the Terms of Service slug - if ($path === $tosSlug || strpos($path, $tosSlug . '/') === 0) - { - // Temporarily disable offline mode for this request - $config->set('offline', 0); + // Remove the base path if present + $base = trim(Uri::base(true), '/'); + if (!empty($base) && strpos($path, $base) === 0) + { + $path = trim(substr($path, strlen($base)), '/'); + } - // Set component-only view (no template chrome) - $input = $this->app->input; - $input->set('tmpl', 'component'); + // Check if the path matches any configured slug + foreach ($slugs as $slug) + { + $slug = trim($slug); + if (empty($slug)) + { + continue; + } - // Also set in GET superglobal to ensure recognition - $_GET['tmpl'] = 'component'; - } - } + if ($path === $slug || strpos($path, $slug . '/') === 0) + { + // Temporarily disable offline mode for this request + $config->set('offline', 0); + + // Set component-only view (no template chrome) + $input = $this->app->input; + $input->set('tmpl', 'component'); + + // Also set in GET superglobal to ensure recognition + $_GET['tmpl'] = 'component'; + + return; + } + } + } } diff --git a/src/mokojoomtos.xml b/src/mokojoomtos.xml index 16c5132..abbc517 100644 --- a/src/mokojoomtos.xml +++ b/src/mokojoomtos.xml @@ -69,8 +69,7 @@ type="menuslug" label="PLG_SYSTEM_MOKOJOOMTOS_FIELD_TOS_SLUG_LABEL" description="PLG_SYSTEM_MOKOJOOMTOS_FIELD_TOS_SLUG_DESC" - default="terms-of-service" - required="true" + multiple="true" /> 'onAfterRoute', + ]; + } - /** - * Returns an array of events this subscriber will listen to. - * - * @return array - * - * @since 1.0.0 - */ - public static function getSubscribedEvents(): array - { - return [ - 'onAfterRoute' => 'onAfterRoute', - ]; - } + /** + * After route event handler + * + * Checks if the current request matches any configured menu slug and if + * the site is in offline mode. If both conditions are met, temporarily + * disables offline mode and sets component-only view for this request. + * + * This event fires after routing but before template selection, making it + * the correct place to set tmpl=component to prevent template chrome loading. + * + * @return void + * + * @since 1.0.0 + */ + public function onAfterRoute() + { + // Only process for site application + if (!$this->getApplication()->isClient('site')) + { + return; + } - /** - * After route event handler - * - * Checks if the current request is for the Terms of Service slug and if - * the site is in offline mode. If both conditions are met, temporarily - * disables offline mode and sets component-only view for this request. - * - * This event fires after routing but before template selection, making it - * the correct place to set tmpl=component to prevent template chrome loading. - * - * @return void - * - * @since 1.0.0 - */ - public function onAfterRoute() - { - // Only process for site application - if (!$this->app->isClient('site')) - { - return; - } + // Get the global configuration + $config = $this->getApplication()->getConfig(); - // Get the global configuration - $config = $this->app->getConfig(); - - // Only proceed if site is offline - if (!$config->get('offline')) - { - return; - } + // Only proceed if site is offline + if (!$config->get('offline')) + { + return; + } - // Get the configured Terms of Service slug - $tosSlug = trim($this->params->get('tos_slug', 'terms-of-service')); - - if (empty($tosSlug)) - { - return; - } + // Get the configured slugs (stored as array for multi-select) + $slugs = $this->params->get('tos_slug', []); - // Get the current URI path - $uri = Uri::getInstance(); - $path = trim($uri->getPath(), '/'); - - // Remove the base path if present - $base = trim(Uri::base(true), '/'); - if (!empty($base) && strpos($path, $base) === 0) - { - $path = trim(substr($path, strlen($base)), '/'); - } + // Handle legacy single-value string format + if (is_string($slugs)) + { + $slugs = array_filter([trim($slugs)]); + } - // Check if the path matches the Terms of Service slug - if ($path === $tosSlug || strpos($path, $tosSlug . '/') === 0) - { - // Temporarily disable offline mode for this request - $config->set('offline', 0); - - // Set component-only view (no template chrome) - // This ensures clean display without full site template - $input = $this->app->input; - $input->set('tmpl', 'component'); - - // Also set it in the GET superglobal to ensure it's recognized - $_GET['tmpl'] = 'component'; - } - } + if (empty($slugs)) + { + return; + } + + // Get the current URI path + $uri = Uri::getInstance(); + $path = trim($uri->getPath(), '/'); + + // Remove the base path if present + $base = trim(Uri::base(true), '/'); + if (!empty($base) && strpos($path, $base) === 0) + { + $path = trim(substr($path, strlen($base)), '/'); + } + + // Check if the path matches any configured slug + foreach ($slugs as $slug) + { + $slug = trim($slug); + if (empty($slug)) + { + continue; + } + + if ($path === $slug || strpos($path, $slug . '/') === 0) + { + // Temporarily disable offline mode for this request + $config->set('offline', 0); + + // Set component-only view (no template chrome) + $input = $this->getApplication()->input; + $input->set('tmpl', 'component'); + + // Also set in GET superglobal to ensure recognition + $_GET['tmpl'] = 'component'; + + return; + } + } + } } diff --git a/src/src/Field/MenuslugField.php b/src/src/Field/MenuslugField.php index a53833f..03e295a 100644 --- a/src/src/Field/MenuslugField.php +++ b/src/src/Field/MenuslugField.php @@ -17,83 +17,81 @@ use Joomla\CMS\Language\Text; /** * Menu Slug Field * - * Provides a dropdown list of menu items with their aliases (slugs) + * Provides a multi-select dropdown of menu items with their full route paths * * @since 1.0.0 */ class MenuslugField extends ListField { - /** - * The form field type. - * - * @var string - * @since 1.0.0 - */ - protected $type = 'Menuslug'; + /** + * The form field type. + * + * @var string + * @since 1.0.0 + */ + protected $type = 'Menuslug'; - /** - * Method to get the field options. - * - * @return array The field option objects. - * - * @since 1.0.0 - */ - protected function getOptions() - { - $options = parent::getOptions(); + /** + * Method to get the field options. + * + * @return array The field option objects. + * + * @since 1.0.0 + */ + protected function getOptions() + { + $options = parent::getOptions(); - try - { - $db = Factory::getDbo(); - $query = $db->getQuery(true) - ->select($db->quoteName(['alias', 'title', 'menutype'])) - ->from($db->quoteName('#__menu')) - ->where($db->quoteName('published') . ' = 1') - ->where($db->quoteName('client_id') . ' = 0') - ->where($db->quoteName('alias') . ' != ' . $db->quote('')) - ->order($db->quoteName('menutype') . ', ' . $db->quoteName('title')); + try + { + $db = Factory::getDbo(); + $query = $db->getQuery(true) + ->select($db->quoteName(['path', 'alias', 'title', 'menutype'])) + ->from($db->quoteName('#__menu')) + ->where($db->quoteName('published') . ' = 1') + ->where($db->quoteName('client_id') . ' = 0') + ->where($db->quoteName('alias') . ' != ' . $db->quote('')) + ->order($db->quoteName('menutype') . ', ' . $db->quoteName('title')); - $db->setQuery($query); - $menuItems = $db->loadObjectList(); + $db->setQuery($query); + $menuItems = $db->loadObjectList(); - if ($menuItems) - { - $lastMenuType = ''; - - foreach ($menuItems as $item) - { - // Add menu type separator for better organization - if ($item->menutype !== $lastMenuType) - { - if ($lastMenuType !== '') - { - // Add a separator between menu types - $options[] = (object) [ - 'value' => '', - 'text' => '──────────────', - 'disable' => true - ]; - } - $lastMenuType = $item->menutype; - } + if ($menuItems) + { + $lastMenuType = ''; - $displayText = $item->title !== '' ? $item->title : ucwords(str_replace(['-', '_'], ' ', $item->alias)); - $options[] = (object) [ - 'value' => $item->alias, - 'text' => $displayText . ' (' . $item->alias . ')' - ]; - } - } - } - catch (\Exception $e) - { - // Log error but don't break the form - Factory::getApplication()->enqueueMessage( - Text::sprintf('PLG_SYSTEM_MOKOJOOMTOS_ERROR_LOADING_MENU_ITEMS', $e->getMessage()), - 'warning' - ); - } + foreach ($menuItems as $item) + { + // Add menu type separator for better organization + if ($item->menutype !== $lastMenuType) + { + if ($lastMenuType !== '') + { + $options[] = (object) [ + 'value' => '', + 'text' => '──────────────', + 'disable' => true + ]; + } + $lastMenuType = $item->menutype; + } - return $options; - } + $displayText = $item->title !== '' ? $item->title : ucwords(str_replace(['-', '_'], ' ', $item->alias)); + $options[] = (object) [ + 'value' => $item->path, + 'text' => $displayText . ' (/' . $item->path . ')' + ]; + } + } + } + catch (\Exception $e) + { + Factory::getApplication()->enqueueMessage( + Text::sprintf('PLG_SYSTEM_MOKOJOOMTOS_ERROR_LOADING_MENU_ITEMS', $e->getMessage()), + 'warning' + ); + } + + return $options; + } } -- 2.52.0 From 61ba7f2cd0dcb763608b1ac1ef31b3b5e57e49dd Mon Sep 17 00:00:00 2001 From: "gitea-actions[bot]" Date: Sat, 16 May 2026 17:25:31 +0000 Subject: [PATCH 05/21] chore: update updates.xml (development: 03.09.00-dev) [skip ci] --- updates.xml | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/updates.xml b/updates.xml index ec039cd..5372fba 100644 --- a/updates.xml +++ b/updates.xml @@ -41,4 +41,25 @@ 8.1 + + + plg_system_mokojoomtos + plg_system_mokojoomtos development build. + mokojoomtos + plugin + site + system + 03.09.00 + 2026-05-16 + https://git.mokoconsulting.tech/MokoConsulting/MokoJoomTOS/releases/tag/development + + https://git.mokoconsulting.tech/MokoConsulting/MokoJoomTOS/releases/download/development/mokojoomtos-03.09.00-dev.zip + + 7bff0a6a899cd6f148080e56b9f435aae269c26f757bd0043263cf3dc63ee9f1 + development + Moko Consulting + https://mokoconsulting.tech + + + -- 2.52.0 From 05bcbd8169252ea27680fbb695dea5ee600a63bf Mon Sep 17 00:00:00 2001 From: Jonathan Miller Date: Sat, 16 May 2026 12:33:39 -0500 Subject: [PATCH 06/21] fix(ci): update pre-release workflow to reference .gitea/manifest.xml Co-Authored-By: Claude Opus 4.6 (1M context) --- .gitea/workflows/pre-release.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.gitea/workflows/pre-release.yml b/.gitea/workflows/pre-release.yml index c70ea7d..c03c239 100644 --- a/.gitea/workflows/pre-release.yml +++ b/.gitea/workflows/pre-release.yml @@ -56,8 +56,8 @@ jobs: id: platform run: | # Read platform from XML manifest ( tag) or plain text fallback - PLATFORM=$(sed -n 's/.*\([^<]*\)<\/platform>.*/\1/p' .mokogitea/manifest.xml 2>/dev/null | head -1) - [ -z "$PLATFORM" ] && PLATFORM=$(cat .mokogitea/manifest.xml 2>/dev/null | tr -d '[:space:]') + PLATFORM=$(sed -n 's/.*\([^<]*\)<\/platform>.*/\1/p' .gitea/manifest.xml 2>/dev/null | head -1) + [ -z "$PLATFORM" ] && PLATFORM=$(cat .gitea/manifest.xml 2>/dev/null | tr -d '[:space:]') [ -z "$PLATFORM" ] && PLATFORM="generic" echo "platform=$PLATFORM" >> "$GITHUB_OUTPUT" MANIFEST=$(find . -maxdepth 3 -name "*.xml" ! -path "./.git/*" -exec grep -l '/dev/null | head -1) -- 2.52.0 From 3a366e7956e3b2cb8fb1da4287fb88b6a5a3be9f Mon Sep 17 00:00:00 2001 From: "gitea-actions[bot]" Date: Sat, 16 May 2026 17:34:17 +0000 Subject: [PATCH 07/21] =?UTF-8?q?chore(version):=20bump=2000.00.00=20?= =?UTF-8?q?=E2=86=92=2000.00.01=20[skip=20ci]?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/mokojoomtos.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/mokojoomtos.xml b/src/mokojoomtos.xml index abbc517..b578b7c 100644 --- a/src/mokojoomtos.xml +++ b/src/mokojoomtos.xml @@ -32,12 +32,12 @@ plg_system_mokojoomtos Moko Consulting - 2026-01-01 + 2026-05-16 Copyright (C) 2026 Moko Consulting. All rights reserved. GNU General Public License version 3 or later; see LICENSE hello@mokoconsulting.tech https://mokoconsulting.tech - 03.09.00 + 00.00.01 PLG_SYSTEM_MOKOJOOMTOS_XML_DESCRIPTION Joomla\Plugin\System\MokoJoomTOS -- 2.52.0 From 25c6778871fb93e3d466882f51ac571420ab23b2 Mon Sep 17 00:00:00 2001 From: "gitea-actions[bot]" Date: Sat, 16 May 2026 17:34:18 +0000 Subject: [PATCH 08/21] chore: update development channel 00.00.01 [skip ci] --- updates.xml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/updates.xml b/updates.xml index 5372fba..aa47b78 100644 --- a/updates.xml +++ b/updates.xml @@ -49,13 +49,13 @@ plugin site system - 03.09.00 + 00.00.01 2026-05-16 https://git.mokoconsulting.tech/MokoConsulting/MokoJoomTOS/releases/tag/development - https://git.mokoconsulting.tech/MokoConsulting/MokoJoomTOS/releases/download/development/mokojoomtos-03.09.00-dev.zip + https://git.mokoconsulting.tech/MokoConsulting/MokoJoomTOS/releases/download/development/mokojoomtos-00.00.01-dev.zip - 7bff0a6a899cd6f148080e56b9f435aae269c26f757bd0043263cf3dc63ee9f1 + c59de0e3a0e04c1fc0042fd27f90123f8bcae86ed2376c3465199da9a10bd1cc development Moko Consulting https://mokoconsulting.tech -- 2.52.0 From 4886090575d8e181e9c6cbdd677dd50966c96f2a Mon Sep 17 00:00:00 2001 From: "gitea-actions[bot]" Date: Sat, 16 May 2026 17:50:47 +0000 Subject: [PATCH 09/21] chore: update development channel 00.00.01 [skip ci] --- updates.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/updates.xml b/updates.xml index aa47b78..780ca7c 100644 --- a/updates.xml +++ b/updates.xml @@ -55,7 +55,7 @@ https://git.mokoconsulting.tech/MokoConsulting/MokoJoomTOS/releases/download/development/mokojoomtos-00.00.01-dev.zip - c59de0e3a0e04c1fc0042fd27f90123f8bcae86ed2376c3465199da9a10bd1cc + 6e2c9e139ded626fdafcfaaf7fb9cfffd58e3e8909bf68c68e78cf8156923f3a development Moko Consulting https://mokoconsulting.tech -- 2.52.0 From 13e5f07951dae562c584b88724f5a7948d67c163 Mon Sep 17 00:00:00 2001 From: Jonathan Miller Date: Sat, 16 May 2026 13:28:26 -0500 Subject: [PATCH 10/21] chore: remove GitHub update server references from updates.xml Co-Authored-By: Claude Opus 4.6 (1M context) --- updates.xml | 17 ++--------------- 1 file changed, 2 insertions(+), 15 deletions(-) diff --git a/updates.xml b/updates.xml index 780ca7c..f5e738f 100644 --- a/updates.xml +++ b/updates.xml @@ -9,18 +9,8 @@ This file is the update server manifest for MokoJoomTOS. The Joomla installer polls this URL to check for new versions. - The manifest.xml in this repository must reference BOTH update servers: - - - https://git.mokoconsulting.tech/MokoConsulting/MokoJoomTOS/raw/branch/main/updates.xml - - - https://raw.githubusercontent.com/mokoconsulting-tech/MokoJoomTOS/main/updates.xml - - - - When a new release is made, run `make release` or the release workflow to - prepend a new entry to this file automatically. + When a new release is made, the release workflow prepends a new + entry to this file automatically. --> @@ -34,9 +24,6 @@ https://git.mokoconsulting.tech/MokoConsulting/MokoJoomTOS/releases/download/v03/plg_system_mokojoomtos-03.09.00.zip - - https://github.com/mokoconsulting-tech/MokoJoomTOS/releases/download/v03/plg_system_mokojoomtos-03.09.00.zip - 8.1 -- 2.52.0 From 396a3e811593e28e3e87ef4323b3c01ad09f5567 Mon Sep 17 00:00:00 2001 From: Jonathan Miller Date: Sat, 16 May 2026 18:58:36 +0000 Subject: [PATCH 11/21] feat(ci): CB plugin detection + platform auto-sense + remove GitHub mirror [skip ci] --- .gitea/workflows/auto-release.yml | 302 ++++++++++++++++-------------- 1 file changed, 161 insertions(+), 141 deletions(-) diff --git a/.gitea/workflows/auto-release.yml b/.gitea/workflows/auto-release.yml index dbaf151..3b254a7 100644 --- a/.gitea/workflows/auto-release.yml +++ b/.gitea/workflows/auto-release.yml @@ -70,33 +70,74 @@ jobs: fi git clone --depth 1 --branch main --quiet \ "https://x-access-token:${MOKO_CLONE_TOKEN}@${MOKO_CLONE_HOST}/MokoStandards-API.git" \ - /tmp/mokostandards-api - cd /tmp/mokostandards-api - composer install --no-dev --no-interaction --quiet + /tmp/mokostandards-api 2>/dev/null || true + if [ -d /tmp/mokostandards-api ]; then + cd /tmp/mokostandards-api + composer install --no-dev --no-interaction --quiet 2>/dev/null || true + fi + echo "MokoStandards tools: $([ -d /tmp/mokostandards-api ] && echo 'available' || echo 'unavailable (using fallback)')" # -- PLATFORM DETECTION --------------------------------------------------- - name: Detect platform id: platform run: | - # Parse .manifest.xml via manifest_read.php — outputs all fields to GITHUB_OUTPUT - php /tmp/mokostandards-api/cli/manifest_read.php --path . --github-output 2>/dev/null || true - PLATFORM=$(php /tmp/mokostandards-api/cli/manifest_read.php --path . --field platform 2>/dev/null) - [ -z "$PLATFORM" ] && PLATFORM="generic" + # 1. Try explicit platform from manifest (.mokogitea takes precedence) + if [ -f ".mokogitea/manifest.xml" ]; then + PLATFORM=$(sed -n 's/.*\([^<]*\)<\/platform>.*/\1/p' .mokogitea/manifest.xml 2>/dev/null | head -1) + elif [ -f ".gitea/manifest.xml" ]; then + PLATFORM=$(sed -n 's/.*\([^<]*\)<\/platform>.*/\1/p' .gitea/manifest.xml 2>/dev/null | head -1) + fi + + # 2. Auto-sense from file structure if no manifest + MANIFEST=$(find . -maxdepth 3 -name "*.xml" ! -path "./.git/*" -exec grep -l '/dev/null | head -1) + CB_MANIFEST=$(find . -maxdepth 3 -name "*.xml" ! -path "./.git/*" -exec grep -l '/dev/null | head -1) + MOD_FILE=$(find . -maxdepth 4 -name "mod*.class.php" ! -path "./.git/*" -exec grep -l 'extends DolibarrModules' {} \; 2>/dev/null | head -1) + + if [ -z "$PLATFORM" ]; then + if [ -n "$CB_MANIFEST" ]; then + PLATFORM="joomla" + MANIFEST="$CB_MANIFEST" + elif [ -n "$MANIFEST" ]; then + PLATFORM="joomla" + elif [ -n "$MOD_FILE" ]; then + PLATFORM="dolibarr" + else + PLATFORM="generic" + fi + fi + echo "platform=$PLATFORM" >> "$GITHUB_OUTPUT" echo "Platform detected: ${PLATFORM}" - # entry-point from manifest, find as fallback - MOD_FILE=$(php /tmp/mokostandards-api/cli/manifest_read.php --path . --field entry-point 2>/dev/null) - [ -z "$MOD_FILE" ] && MOD_FILE=$(find . -maxdepth 4 -name "mod*.class.php" ! -path "./.git/*" -exec grep -l 'extends DolibarrModules' {} \; 2>/dev/null | head -1) - MANIFEST=$(find . -maxdepth 3 -name "*.xml" ! -path "./.git/*" -exec grep -l '/dev/null | head -1) echo "manifest=${MANIFEST}" >> "$GITHUB_OUTPUT" echo "mod_file=${MOD_FILE}" >> "$GITHUB_OUTPUT" + # Detect update file methodology + if [ "$PLATFORM" = "joomla" ]; then + echo "update_method=updates.xml" >> "$GITHUB_OUTPUT" + echo "Update method: Joomla updates.xml" + elif [ "$PLATFORM" = "dolibarr" ]; then + echo "update_method=update.txt" >> "$GITHUB_OUTPUT" + echo "Update method: Dolibarr update.txt" + else + echo "update_method=none" >> "$GITHUB_OUTPUT" + echo "Update method: none (generic)" + fi + # -- STEP 1: Read version ----------------------------------------------- - name: "Step 1: Read version from README.md" id: version run: | - VERSION=$(php /tmp/mokostandards-api/cli/version_read.php --path . 2>/dev/null) + # Try MokoStandards PHP tool first, fall back to direct parsing + VERSION=$(php /tmp/mokostandards-api/cli/version_read.php --path . 2>/dev/null || true) + if [ -z "$VERSION" ]; then + # Fallback: read from README table format "| **Version** | XX.YY.ZZ |" + VERSION=$(sed -n 's/.*\*\*Version\*\*[[:space:]]*|[[:space:]]*\([0-9][0-9]\.[0-9][0-9]\.[0-9][0-9]\).*/\1/p' README.md 2>/dev/null | head -1) + fi + if [ -z "$VERSION" ]; then + # Fallback: read VERSION: XX.YY.ZZ pattern from any file + VERSION=$(grep -rh "VERSION:[[:space:]]*[0-9]" README.md CHANGELOG.md 2>/dev/null | sed -n 's/.*VERSION:[[:space:]]*\([0-9][0-9]\.[0-9][0-9]\.[0-9][0-9]\).*/\1/p' | head -1) + fi if [ -z "$VERSION" ]; then echo "No VERSION in README.md — skipping release" echo "skip=true" >> "$GITHUB_OUTPUT" @@ -124,54 +165,15 @@ jobs: echo "Version: $VERSION (patch — platform version + badges only)" fi - # -- STEP 1b: Bump minor version (stable = minor bump, reset patch) ------ - - name: "Step 1b: Bump minor version for stable release" + # -- STEP 1b: Promote CHANGELOG [Unreleased] to current version ----------- + - name: "Step 1b: Promote CHANGELOG for release" if: steps.version.outputs.skip != 'true' id: bump run: | - CURRENT=$(sed -n 's/.*VERSION:[[:space:]]*\([0-9][0-9]\.[0-9][0-9]\.[0-9][0-9]\).*/\1/p' README.md 2>/dev/null | head -1) - [ -z "$CURRENT" ] && { echo "skip=true" >> "$GITHUB_OUTPUT"; exit 0; } - - MAJOR=$((10#$(echo "$CURRENT" | cut -d. -f1))) - MINOR=$((10#$(echo "$CURRENT" | cut -d. -f2))) - - # Minor bump, reset patch. Rollover if minor > 99 - MINOR=$((MINOR + 1)) - if [ $MINOR -gt 99 ]; then - MINOR=0 - MAJOR=$((MAJOR + 1)) - fi - - VERSION=$(printf "%02d.%02d.00" $MAJOR $MINOR) + VERSION="${{ steps.version.outputs.version }}" TODAY=$(date +%Y-%m-%d) - echo "Stable bump: ${CURRENT} → ${VERSION} (minor)" - - # Update README.md - sed -i "s/VERSION:[[:space:]]*${CURRENT}/VERSION: ${VERSION}/" README.md - - # Update platform-specific manifest - PLATFORM="${{ steps.platform.outputs.platform }}" - MANIFEST="${{ steps.platform.outputs.manifest }}" - MOD_FILE="${{ steps.platform.outputs.mod_file }}" - case "$PLATFORM" in - joomla) - if [ -n "$MANIFEST" ]; then - MANIFEST_VER=$(sed -n 's/.*\([^<]*\)<\/version>.*/\1/p' "$MANIFEST" | head -1) - [ -n "$MANIFEST_VER" ] && sed -i "s|${MANIFEST_VER}|${VERSION}|" "$MANIFEST" - sed -i "s|[^<]*|${TODAY}|" "$MANIFEST" - fi - ;; - dolibarr) - if [ -n "$MOD_FILE" ]; then - sed -i "s/\$this->version = '[^']*'/\$this->version = '${VERSION}'/" "$MOD_FILE" - fi - echo "${VERSION}" > update.txt - ;; - *) ;; - esac - - # Promote [Unreleased] section in CHANGELOG.md to new version + # Promote [Unreleased] section in CHANGELOG.md to release version if [ -f "CHANGELOG.md" ] && grep -qi "Unreleased" CHANGELOG.md; then sed -i "s|## \[Unreleased\]|## [${VERSION}] --- ${TODAY}|" CHANGELOG.md sed -i "s|## Unreleased|## [${VERSION}] --- ${TODAY}|" CHANGELOG.md @@ -180,19 +182,19 @@ jobs: echo "CHANGELOG promoted to [${VERSION}]" fi - # Commit and push + # Commit changelog promotion if changed git config --local user.email "gitea-actions[bot]@mokoconsulting.tech" git config --local user.name "gitea-actions[bot]" git remote set-url origin "https://jmiller:${{ secrets.GA_TOKEN }}@git.mokoconsulting.tech/${{ github.repository }}.git" git add -A git diff --cached --quiet || { - git commit -m "chore(version): bump ${CURRENT} → ${VERSION} [skip ci]" - git push origin HEAD:dev 2>&1 || git push origin HEAD:main 2>&1 + git commit -m "chore(release): promote CHANGELOG ${VERSION} [skip ci]" + git push origin HEAD:main 2>&1 } - # Override version output for rest of pipeline + # Pass through version (no bump — release uses version as-is from dev) echo "version=${VERSION}" >> "$GITHUB_OUTPUT" - echo "major=$(printf "%02d" $MAJOR)" >> "$GITHUB_OUTPUT" + echo "major=${{ steps.version.outputs.major }}" >> "$GITHUB_OUTPUT" - name: Check if already released if: steps.version.outputs.skip != 'true' @@ -337,8 +339,19 @@ jobs: steps.check.outputs.already_released != 'true' run: | VERSION="${{ steps.bump.outputs.version || steps.version.outputs.version }}" - php /tmp/mokostandards-api/cli/version_set_platform.php \ - --path . --version "$VERSION" --branch main + if [ -f /tmp/mokostandards-api/cli/version_set_platform.php ]; then + php /tmp/mokostandards-api/cli/version_set_platform.php \ + --path . --version "$VERSION" --branch main + else + # Fallback: update version in templateDetails.xml directly + MANIFEST=$(find . -maxdepth 3 -name "*.xml" ! -path "./.git/*" -exec grep -l '/dev/null | head -1) + if [ -n "$MANIFEST" ]; then + sed -i "s|[^<]*|${VERSION}|" "$MANIFEST" + sed -i "s|[^<]*|$(date +%Y-%m-%d)|" "$MANIFEST" + fi + # Update README version table + sed -i "s/|\s*\*\*Version\*\*\s*|[^|]*/| **Version** | ${VERSION} /" README.md 2>/dev/null || true + fi # -- STEP 4: Update version badges ---------------------------------------- - name: "Step 4: Update version badges" @@ -364,18 +377,35 @@ jobs: REPO="${{ github.repository }}" # -- Parse extension metadata from XML manifest ---------------- + # Check for Joomla or Community Builder MANIFEST=$(find . -maxdepth 2 -name "*.xml" -exec grep -l '/dev/null | head -1) - if [ -z "$MANIFEST" ]; then - echo "Warning: No Joomla XML manifest found — skipping updates.xml" >> $GITHUB_STEP_SUMMARY + CB_MANIFEST=$(find . -maxdepth 2 -name "*.xml" -exec grep -l '/dev/null | head -1) + IS_CB="false" + + if [ -z "$MANIFEST" ] && [ -z "$CB_MANIFEST" ]; then + echo "Warning: No Joomla/CB XML manifest found — skipping updates.xml" >> $GITHUB_STEP_SUMMARY exit 0 fi + # CB plugin takes precedence if no standard manifest + if [ -z "$MANIFEST" ] && [ -n "$CB_MANIFEST" ]; then + MANIFEST="$CB_MANIFEST" + IS_CB="true" + fi + # Extract fields using sed (portable — no grep -P) EXT_NAME=$(sed -n 's/.*\([^<]*\)<\/name>.*/\1/p' "$MANIFEST" | head -1) - EXT_TYPE=$(sed -n 's/.*]*type="\([^"]*\)".*/\1/p' "$MANIFEST" | head -1) - EXT_ELEMENT=$(sed -n 's/.*\([^<]*\)<\/element>.*/\1/p' "$MANIFEST" | head -1) - EXT_CLIENT=$(sed -n 's/.*]*client="\([^"]*\)".*/\1/p' "$MANIFEST" | head -1) - EXT_FOLDER=$(sed -n 's/.*]*group="\([^"]*\)".*/\1/p' "$MANIFEST" | head -1) + if [ "$IS_CB" = "true" ]; then + EXT_TYPE="cb_plugin" + EXT_ELEMENT=$(sed -n 's/.*]*plugin="\([^"]*\)".*/\1/p' "$MANIFEST" | head -1) + EXT_CLIENT="" + EXT_FOLDER="cb" + else + EXT_TYPE=$(sed -n 's/.*]*type="\([^"]*\)".*/\1/p' "$MANIFEST" | head -1) + EXT_ELEMENT=$(sed -n 's/.*\([^<]*\)<\/element>.*/\1/p' "$MANIFEST" | head -1) + EXT_CLIENT=$(sed -n 's/.*]*client="\([^"]*\)".*/\1/p' "$MANIFEST" | head -1) + EXT_FOLDER=$(sed -n 's/.*]*group="\([^"]*\)".*/\1/p' "$MANIFEST" | head -1) + fi TARGET_PLATFORM=$(sed -n 's/.*\(\).*/\1/p' "$MANIFEST" | head -1) PHP_MINIMUM=$(sed -n 's/.*\([^<]*\)<\/php_minimum>.*/\1/p' "$MANIFEST" | head -1) @@ -452,6 +482,7 @@ jobs: template) TYPE_PREFIX="tpl_" ;; library) TYPE_PREFIX="lib_" ;; package) TYPE_PREFIX="pkg_" ;; + cb_plugin) TYPE_PREFIX="cb_" ;; esac DOWNLOAD_URL="${GITEA_URL}/${GITEA_ORG}/${GITEA_REPO}/releases/download/stable/${TYPE_PREFIX}${EXT_ELEMENT}-${VERSION}.zip" @@ -561,7 +592,7 @@ jobs: fi [ -z "$EXT_NAME" ] && EXT_NAME="${GITEA_REPO}" - NOTES=$(php /tmp/mokostandards-api/cli/release_notes.php --path . --version "$VERSION" 2>/dev/null) + NOTES=$(php /tmp/mokostandards-api/cli/release_notes.php --path . --version "$VERSION" 2>/dev/null || true) [ -z "$NOTES" ] && NOTES="Release ${VERSION}" # Build release name: "Pretty Name VERSION (type_element-VERSION)" @@ -573,6 +604,7 @@ jobs: template) TYPE_PREFIX="tpl_" ;; library) TYPE_PREFIX="lib_" ;; package) TYPE_PREFIX="pkg_" ;; + cb_plugin) TYPE_PREFIX="cb_" ;; esac RELEASE_NAME="${EXT_NAME} ${VERSION} (${TYPE_PREFIX}${EXT_ELEMENT}-${VERSION})" @@ -643,6 +675,7 @@ jobs: template) TYPE_PREFIX="tpl_" ;; library) TYPE_PREFIX="lib_" ;; package) TYPE_PREFIX="pkg_" ;; + cb_plugin) TYPE_PREFIX="cb_" ;; esac ZIP_NAME="${TYPE_PREFIX}${EXT_ELEMENT}-${VERSION}.zip" TAR_NAME="${TYPE_PREFIX}${EXT_ELEMENT}-${VERSION}.tar.gz" @@ -805,6 +838,7 @@ jobs: template) TYPE_PREFIX="tpl_" ;; library) TYPE_PREFIX="lib_" ;; package) TYPE_PREFIX="pkg_" ;; + cb_plugin) TYPE_PREFIX="cb_" ;; esac ZIP_NAME="${TYPE_PREFIX}${EXT_ELEMENT}-${VERSION}.zip" TAR_NAME="${TYPE_PREFIX}${EXT_ELEMENT}-${VERSION}.tar.gz" @@ -852,65 +886,7 @@ jobs: " 2>/dev/null && echo "Release body updated with changelog + SHA" >> $GITHUB_STEP_SUMMARY fi - # -- STEP 9: Mirror to GitHub (stable only) -------------------------------- - - name: "Step 9: Mirror release to GitHub" - if: >- - steps.version.outputs.skip != 'true' && - steps.version.outputs.stability == 'stable' && - secrets.GH_TOKEN != '' - continue-on-error: true - env: - GH_TOKEN: ${{ secrets.GH_TOKEN }} - run: | - VERSION="${{ steps.bump.outputs.version || steps.version.outputs.version }}" - RELEASE_TAG="${{ steps.version.outputs.release_tag }}" - MAJOR="${{ steps.version.outputs.major }}" - BRANCH="${{ steps.version.outputs.branch }}" - GH_REPO="${{ vars.GH_MIRROR_REPO || github.repository }}" - - NOTES=$(php /tmp/mokostandards-api/cli/release_notes.php --path . --version "$VERSION" 2>/dev/null || true) - [ -z "$NOTES" ] && NOTES="Release ${VERSION}" - echo "$NOTES" > /tmp/release_notes.md - - EXISTING=$(curl -sf -H "Authorization: token ${{ secrets.GA_TOKEN }}" "${GITEA_URL:-https://git.mokoconsulting.tech}/api/v1/repos/${{ github.repository }}/releases/tags/$RELEASE_TAG" 2>/dev/null | jq -r ".tag_name // empty" || true) - - if [ -z "$EXISTING" ]; then - gh release create "$RELEASE_TAG" \ - --repo "$GH_REPO" \ - --title "v${MAJOR} (latest: ${VERSION})" \ - --notes-file /tmp/release_notes.md \ - --target "$BRANCH" || true - else - gh release edit "$RELEASE_TAG" \ - --repo "$GH_REPO" \ - --title "v${MAJOR} (latest: ${VERSION})" || true - fi - - # Upload assets to GitHub mirror - for PKG in /tmp/${EXT_ELEMENT:-pkg}-${VERSION}.*; do - if [ -f "$PKG" ]; then - _RELID=$(curl -sf -H "Authorization: token ${{ secrets.GA_TOKEN }}" "${GITEA_URL:-https://git.mokoconsulting.tech}/api/v1/repos/${{ github.repository }}/releases/tags/$RELEASE_TAG" 2>/dev/null | jq -r ".id // empty") - [ -n "$_RELID" ] && curl -sf -X POST -H "Authorization: token ${{ secrets.GA_TOKEN }}" -H "Content-Type: application/octet-stream" "${GITEA_URL:-https://git.mokoconsulting.tech}/api/v1/repos/${{ github.repository }}/releases/${_RELID}/assets?name=$(basename $PKG)" --data-binary "@$PKG" > /dev/null 2>&1 || true - fi - done - echo "GitHub mirror updated: ${GH_REPO} ${RELEASE_TAG}" >> $GITHUB_STEP_SUMMARY - - # -- STEP 10: Sync main branch to GitHub mirror ---------------------------- - - name: "Step 10: Push main to GitHub mirror" - if: >- - steps.version.outputs.skip != 'true' && - secrets.GH_TOKEN != '' - continue-on-error: true - run: | - GH_REPO="${{ vars.GH_MIRROR_REPO || github.repository }}" - GH_ORG=$(echo "$GH_REPO" | cut -d/ -f1) - GH_NAME=$(echo "$GH_REPO" | cut -d/ -f2) - git remote add github "https://x-access-token:${{ secrets.GH_TOKEN }}@github.com/${GH_ORG}/${GH_NAME}.git" 2>/dev/null || \ - git remote set-url github "https://x-access-token:${{ secrets.GH_TOKEN }}@github.com/${GH_ORG}/${GH_NAME}.git" - git fetch origin main --depth=1 - git push github origin/main:refs/heads/main --force 2>/dev/null \ - && echo "main branch pushed to GitHub mirror" \ - || echo "WARNING: GitHub mirror push failed" + # -- (GitHub mirror removed — Gitea is the sole release platform) ---------- # -- Clean up lesser pre-releases (cascade) --------------------------------- # stable → deletes all | rc → beta,alpha,dev | beta → alpha,dev | alpha → dev @@ -941,30 +917,74 @@ jobs: done echo "Cleaned up ${DELETED} pre-release channel(s)" >> $GITHUB_STEP_SUMMARY - # -- STEP 11: Sync dev branch with main + version bump ---------------------- - - name: "Step 11: Merge main into dev (version bump lands on dev)" + # -- STEP 11: Reset dev branch and bump to next minor ------------------------- + - name: "Step 11: Reset dev and bump to next minor" if: steps.version.outputs.skip != 'true' continue-on-error: true run: | API_BASE="${GITEA_URL}/api/v1/repos/${GITEA_ORG}/${GITEA_REPO}" TOKEN="${{ secrets.GA_TOKEN }}" + VERSION="${{ steps.bump.outputs.version || steps.version.outputs.version }}" + PLATFORM="${{ steps.platform.outputs.platform }}" - # Merge main into dev so dev has the release + version bump + # Delete dev branch + curl -sf -X DELETE -H "Authorization: token ${TOKEN}" \ + "${API_BASE}/branches/dev" 2>/dev/null && echo "Deleted dev branch" + + # Recreate dev from main curl -sf -X POST -H "Authorization: token ${TOKEN}" \ -H "Content-Type: application/json" \ - "${API_BASE}/merges" \ - -d "{\"base\":\"dev\",\"head\":\"main\",\"message\":\"chore: sync main into dev after release [skip ci]\"}" \ - 2>/dev/null && echo "Merged main into dev" + "${API_BASE}/branches" \ + -d '{"new_branch_name":"dev","old_branch_name":"main"}' 2>/dev/null && echo "Recreated dev from main" - # If dev doesn't exist, create it from main - if [ $? -ne 0 ]; then - curl -sf -X POST -H "Authorization: token ${TOKEN}" \ - -H "Content-Type: application/json" \ - "${API_BASE}/branches" \ - -d '{"new_branch_name":"dev","old_branch_name":"main"}' 2>/dev/null && echo "Created dev from main" + # Calculate next minor version for dev + MAJOR=$((10#$(echo "$VERSION" | cut -d. -f1))) + MINOR=$((10#$(echo "$VERSION" | cut -d. -f2))) + MINOR=$((MINOR + 1)) + if [ $MINOR -gt 99 ]; then + MINOR=0 + MAJOR=$((MAJOR + 1)) + fi + NEXT=$(printf "%02d.%02d.00" $MAJOR $MINOR) + + # Bump version on dev via API (README + manifest) + # Update README.md on dev + README_RESP=$(curl -sf -H "Authorization: token ${TOKEN}" "${API_BASE}/contents/README.md?ref=dev" 2>/dev/null || true) + README_SHA=$(echo "$README_RESP" | python3 -c "import sys,json; print(json.load(sys.stdin).get('sha',''))" 2>/dev/null || true) + README_CONTENT=$(echo "$README_RESP" | python3 -c "import sys,json,base64; print(base64.b64decode(json.load(sys.stdin).get('content','')).decode())" 2>/dev/null || true) + if [ -n "$README_SHA" ] && [ -n "$README_CONTENT" ]; then + UPDATED=$(echo "$README_CONTENT" | sed "s/${VERSION}/${NEXT}/g") + ENCODED=$(echo "$UPDATED" | base64 -w0) + curl -sf -X PUT -H "Authorization: token ${TOKEN}" -H "Content-Type: application/json" \ + "${API_BASE}/contents/README.md" \ + -d "$(python3 -c "import json; print(json.dumps({'content':'${ENCODED}','sha':'${README_SHA}','message':'chore(version): bump ${VERSION} → ${NEXT} (dev) [skip ci]','branch':'dev'}))")" > /dev/null 2>&1 || true fi - echo "Dev branch synced with main (version bump on dev)" >> $GITHUB_STEP_SUMMARY + # Update manifest on dev (Joomla or Dolibarr) + case "$PLATFORM" in + joomla) + MANIFEST_PATH="${{ steps.platform.outputs.manifest }}" + [ -n "$MANIFEST_PATH" ] && MANIFEST_PATH=$(echo "$MANIFEST_PATH" | sed 's|^\./||') + if [ -n "$MANIFEST_PATH" ]; then + ENCODED_PATH=$(python3 -c "import urllib.parse; print(urllib.parse.quote('${MANIFEST_PATH}'))") + MF_RESP=$(curl -sf -H "Authorization: token ${TOKEN}" "${API_BASE}/contents/${ENCODED_PATH}?ref=dev" 2>/dev/null || true) + MF_SHA=$(echo "$MF_RESP" | python3 -c "import sys,json; print(json.load(sys.stdin).get('sha',''))" 2>/dev/null || true) + MF_CONTENT=$(echo "$MF_RESP" | python3 -c "import sys,json,base64; print(base64.b64decode(json.load(sys.stdin).get('content','')).decode())" 2>/dev/null || true) + if [ -n "$MF_SHA" ] && [ -n "$MF_CONTENT" ]; then + UPDATED=$(echo "$MF_CONTENT" | sed "s|${VERSION}|${NEXT}|") + ENCODED=$(echo "$UPDATED" | base64 -w0) + curl -sf -X PUT -H "Authorization: token ${TOKEN}" -H "Content-Type: application/json" \ + "${API_BASE}/contents/${ENCODED_PATH}" \ + -d "$(python3 -c "import json; print(json.dumps({'content':'${ENCODED}','sha':'${MF_SHA}','message':'chore(version): bump ${VERSION} → ${NEXT} (dev) [skip ci]','branch':'dev'}))")" > /dev/null 2>&1 || true + fi + fi + ;; + dolibarr) + # Dolibarr handled by separate step below + ;; + esac + + echo "Dev branch bumped to ${NEXT}" >> $GITHUB_STEP_SUMMARY # -- Dolibarr post-release: Reset dev version ----------------------------- -- 2.52.0 From 09f80ccbe6cfb79320e451cb31663641e2437c16 Mon Sep 17 00:00:00 2001 From: Jonathan Miller Date: Sat, 16 May 2026 14:01:53 -0500 Subject: [PATCH 12/21] chore: sync workflows from Template-Joomla Co-Authored-By: Claude Opus 4.6 (1M context) --- .gitea/workflows/pre-release.yml | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/.gitea/workflows/pre-release.yml b/.gitea/workflows/pre-release.yml index c03c239..c51bea8 100644 --- a/.gitea/workflows/pre-release.yml +++ b/.gitea/workflows/pre-release.yml @@ -55,13 +55,15 @@ jobs: - name: Detect platform id: platform run: | - # Read platform from XML manifest ( tag) or plain text fallback - PLATFORM=$(sed -n 's/.*\([^<]*\)<\/platform>.*/\1/p' .gitea/manifest.xml 2>/dev/null | head -1) - [ -z "$PLATFORM" ] && PLATFORM=$(cat .gitea/manifest.xml 2>/dev/null | tr -d '[:space:]') + # Parse .manifest.xml via manifest_read.php — outputs all fields to GITHUB_OUTPUT + php /tmp/mokostandards-api/cli/manifest_read.php --path . --github-output 2>/dev/null || true + PLATFORM=$(php /tmp/mokostandards-api/cli/manifest_read.php --path . --field platform 2>/dev/null) [ -z "$PLATFORM" ] && PLATFORM="generic" echo "platform=$PLATFORM" >> "$GITHUB_OUTPUT" + # entry-point from manifest, find as fallback + MOD_FILE=$(php /tmp/mokostandards-api/cli/manifest_read.php --path . --field entry-point 2>/dev/null) + [ -z "$MOD_FILE" ] && MOD_FILE=$(find . -maxdepth 4 -name "mod*.class.php" ! -path "./.git/*" -exec grep -l 'extends DolibarrModules' {} \; 2>/dev/null | head -1) MANIFEST=$(find . -maxdepth 3 -name "*.xml" ! -path "./.git/*" -exec grep -l '/dev/null | head -1) - MOD_FILE=$(find . -maxdepth 4 -name "mod*.class.php" ! -path "./.git/*" -exec grep -l 'extends DolibarrModules' {} \; 2>/dev/null | head -1) echo "manifest=${MANIFEST}" >> "$GITHUB_OUTPUT" echo "mod_file=${MOD_FILE}" >> "$GITHUB_OUTPUT" -- 2.52.0 From 302329ad778085f8c90748e66229fddadb614e71 Mon Sep 17 00:00:00 2001 From: Jonathan Miller Date: Sat, 16 May 2026 14:07:38 -0500 Subject: [PATCH 13/21] chore: update .gitea/manifest.xml to match MokoStandards v05 Co-Authored-By: Claude Opus 4.6 (1M context) --- .gitea/manifest.xml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.gitea/manifest.xml b/.gitea/manifest.xml index ae12952..6ead97c 100644 --- a/.gitea/manifest.xml +++ b/.gitea/manifest.xml @@ -8,18 +8,18 @@ MokoJoomTOS MokoConsulting - A component to present a sites Term of Service and privacy policy even through offline. + Joomla system plugin to keep legal pages accessible during offline mode GNU General Public License v3 joomla - 04.07.00 + 05.00.00 https://git.mokoconsulting.tech/MokoConsulting/moko-platform - 2026-05-10T19:51:05+00:00 + 2026-05-16T17:30:00+00:00 PHP - joomla + joomla-extension src/ -- 2.52.0 From 06d846c38a68fde5e2e13a595e90e58304574e12 Mon Sep 17 00:00:00 2001 From: Jonathan Miller Date: Sat, 16 May 2026 22:19:21 +0000 Subject: [PATCH 14/21] chore: rename Setup step to moko-platform [skip ci] --- .gitea/workflows/auto-release.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitea/workflows/auto-release.yml b/.gitea/workflows/auto-release.yml index 3b254a7..99679ad 100644 --- a/.gitea/workflows/auto-release.yml +++ b/.gitea/workflows/auto-release.yml @@ -58,7 +58,7 @@ jobs: token: ${{ secrets.GA_TOKEN }} fetch-depth: 0 - - name: Setup MokoStandards tools + - name: Setup moko-platform env: MOKO_CLONE_TOKEN: ${{ secrets.GA_TOKEN }} MOKO_CLONE_HOST: git.mokoconsulting.tech/MokoConsulting -- 2.52.0 From b308de6bf259f4e889039b69e8e4dd9b36122f8d Mon Sep 17 00:00:00 2001 From: Jonathan Miller Date: Sat, 16 May 2026 22:19:52 +0000 Subject: [PATCH 15/21] =?UTF-8?q?chore:=20remove=20docs/=20=E2=80=94=20doc?= =?UTF-8?q?umentation=20lives=20in=20wiki=20[skip=20ci]?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/!.gitkeep | 0 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 docs/!.gitkeep diff --git a/docs/!.gitkeep b/docs/!.gitkeep deleted file mode 100644 index e69de29..0000000 -- 2.52.0 From 17cd29c663d0a301eb7a54bb2aa1bfa56bb5a92b Mon Sep 17 00:00:00 2001 From: Jonathan Miller Date: Sat, 16 May 2026 22:19:52 +0000 Subject: [PATCH 16/21] =?UTF-8?q?chore:=20remove=20docs/=20=E2=80=94=20doc?= =?UTF-8?q?umentation=20lives=20in=20wiki=20[skip=20ci]?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/index.md | 16 ---------------- 1 file changed, 16 deletions(-) delete mode 100644 docs/index.md diff --git a/docs/index.md b/docs/index.md deleted file mode 100644 index 03330e6..0000000 --- a/docs/index.md +++ /dev/null @@ -1,16 +0,0 @@ -# Docs Index: /templates/repos/joomla/component/docs - -## Purpose - -This index provides navigation to documentation within this folder. - -## Metadata - -- **Document Type:** index -- **Auto-generated:** This file is automatically generated by rebuild_indexes.py - -## Revision History - -| Change | Notes | Author | -| --- | --- | --- | -| Automated update | Generated by documentation index automation | rebuild_indexes.py | -- 2.52.0 From 350a365a842f87596ef25eabd179e8404b8ede41 Mon Sep 17 00:00:00 2001 From: Jonathan Miller Date: Sat, 16 May 2026 22:19:53 +0000 Subject: [PATCH 17/21] =?UTF-8?q?chore:=20remove=20docs/=20=E2=80=94=20doc?= =?UTF-8?q?umentation=20lives=20in=20wiki=20[skip=20ci]?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/update-server.md | 119 ------------------------------------------ 1 file changed, 119 deletions(-) delete mode 100644 docs/update-server.md diff --git a/docs/update-server.md b/docs/update-server.md deleted file mode 100644 index 5cde998..0000000 --- a/docs/update-server.md +++ /dev/null @@ -1,119 +0,0 @@ - - -# Joomla Update Server - -[![MokoStandards](https://img.shields.io/badge/MokoStandards-04.04.00-blue)](https://github.com/mokoconsulting-tech/MokoStandards) - -This document explains how `update.xml` is automatically managed for this Joomla extension following the [Joomla Update Server specification](https://docs.joomla.org/Deploying_an_Update_Server). - -## How It Works - -Joomla checks for extension updates by fetching an XML file from the URL defined in the `` tag in the extension's XML manifest. MokoStandards generates this file automatically. - -### Automatic Generation - -| Event | Workflow | `` | `` | -|-------|----------|---------|-------------| -| Merge to `main` | `auto-release.yml` | `stable` | `XX.YY.ZZ` | -| Push to `dev/**` | `deploy-dev.yml` | `development` | `development` | -| Push to `rc/**` | `deploy-dev.yml` | `rc` | `XX.YY.ZZ-rc` | - -### Generated XML Structure - -```xml - - - - Extension Name - Extension Name update - com_extensionname - component - 01.02.03 - site - system - - stable - - https://github.com/.../releases/tag/v01.02.03 - - https://github.com/.../releases/download/v01.02.03/com_ext-01.02.03.zip - - - 8.2 - Moko Consulting - https://mokoconsulting.tech - - -``` - -### Metadata Source - -All metadata is extracted from the extension's XML manifest (`src/*.xml`) at build time: - -| XML Element | Source | Notes | -|-------------|--------|-------| -| `` | `` in manifest | Extension display name | -| `` | `` in manifest | Must match installed extension identifier | -| `` | `type` attribute on `` | `component`, `module`, `plugin`, `library`, `package`, `template` | -| `` | `client` attribute on `` | `site` or `administrator` — **required for plugins and modules** | -| `` | `group` attribute on `` | Plugin group (e.g., `system`, `content`) — **required for plugins** | -| `` | `` in manifest | Falls back to Joomla 5.x / 6.x if not specified | -| `` | `` in manifest | Included only if present | - -### Extension Manifest Setup - -Your XML manifest must include an `` tag pointing to the `update.xml` on the `main` branch: - -```xml - - My Extension - com_myextension - - - - https://raw.githubusercontent.com/mokoconsulting-tech/MokoJoomTOS/main/update.xml - - - -``` - -### Branch Lifecycle - -``` -dev/XX.YY.ZZ → rc/XX.YY.ZZ → main → version/XX.YY -(development) (rc) (stable) (frozen snapshot) -``` - -1. **Development** (`dev/**`): `update.xml` with `development`, download points to branch archive -2. **Release Candidate** (`rc/**`): `update.xml` with `rc`, version set to `XX.YY.ZZ-rc` -3. **Stable Release** (merge to `main`): `update.xml` with `stable`, download points to GitHub Release asset -4. **Frozen Snapshot** (`version/XX.YY`): immutable, never force-pushed - -### Health Checks - -The `repo_health.yml` workflow verifies on every commit: - -- `update.xml` exists in the repository root -- XML manifest exists with `` tag -- ``, ``, ``, `` tags present -- Extension `type` attribute is valid -- Language `.ini` files exist -- `index.html` directory listing protection in `src/`, `src/admin/`, `src/site/` - ---- - -*Managed by [MokoStandards](https://github.com/mokoconsulting-tech/MokoStandards). See [docs/workflows/update-server.md](https://github.com/mokoconsulting-tech/MokoStandards/blob/main/docs/workflows/update-server.md) for the full specification.* -- 2.52.0 From 62f72ae215bd431b4396ecfcda80cefcb91d607d Mon Sep 17 00:00:00 2001 From: Jonathan Miller Date: Sat, 16 May 2026 17:22:10 -0500 Subject: [PATCH 18/21] fix(ci): add MokoStandards-API clone step before platform detection Co-Authored-By: Claude Opus 4.6 (1M context) --- .gitea/workflows/pre-release.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.gitea/workflows/pre-release.yml b/.gitea/workflows/pre-release.yml index c51bea8..a68e151 100644 --- a/.gitea/workflows/pre-release.yml +++ b/.gitea/workflows/pre-release.yml @@ -52,6 +52,10 @@ jobs: sudo apt-get install -y -qq php-cli php-mbstring php-xml php-zip >/dev/null 2>&1 fi + - name: Clone MokoStandards API + run: | + git clone --depth 1 https://${{ secrets.GA_TOKEN }}@git.mokoconsulting.tech/MokoConsulting/MokoStandards-API.git /tmp/mokostandards-api 2>/dev/null || true + - name: Detect platform id: platform run: | -- 2.52.0 From 6a457d2924415e861e03430b6916b7e9d29d9e1c Mon Sep 17 00:00:00 2001 From: Jonathan Miller Date: Sat, 16 May 2026 17:25:51 -0500 Subject: [PATCH 19/21] fix(ci): use direct XML parsing for platform detection The release runner doesn't have MokoStandards-API pre-installed. Fall back to sed-based manifest parsing. Co-Authored-By: Claude Opus 4.6 (1M context) --- .gitea/workflows/pre-release.yml | 15 ++++----------- 1 file changed, 4 insertions(+), 11 deletions(-) diff --git a/.gitea/workflows/pre-release.yml b/.gitea/workflows/pre-release.yml index a68e151..29453c3 100644 --- a/.gitea/workflows/pre-release.yml +++ b/.gitea/workflows/pre-release.yml @@ -52,22 +52,15 @@ jobs: sudo apt-get install -y -qq php-cli php-mbstring php-xml php-zip >/dev/null 2>&1 fi - - name: Clone MokoStandards API - run: | - git clone --depth 1 https://${{ secrets.GA_TOKEN }}@git.mokoconsulting.tech/MokoConsulting/MokoStandards-API.git /tmp/mokostandards-api 2>/dev/null || true - - name: Detect platform id: platform run: | - # Parse .manifest.xml via manifest_read.php — outputs all fields to GITHUB_OUTPUT - php /tmp/mokostandards-api/cli/manifest_read.php --path . --github-output 2>/dev/null || true - PLATFORM=$(php /tmp/mokostandards-api/cli/manifest_read.php --path . --field platform 2>/dev/null) + # Read platform from .gitea/manifest.xml + PLATFORM=$(sed -n 's/.*\([^<]*\)<\/platform>.*/\1/p' .gitea/manifest.xml 2>/dev/null | head -1) [ -z "$PLATFORM" ] && PLATFORM="generic" echo "platform=$PLATFORM" >> "$GITHUB_OUTPUT" - # entry-point from manifest, find as fallback - MOD_FILE=$(php /tmp/mokostandards-api/cli/manifest_read.php --path . --field entry-point 2>/dev/null) - [ -z "$MOD_FILE" ] && MOD_FILE=$(find . -maxdepth 4 -name "mod*.class.php" ! -path "./.git/*" -exec grep -l 'extends DolibarrModules' {} \; 2>/dev/null | head -1) - MANIFEST=$(find . -maxdepth 3 -name "*.xml" ! -path "./.git/*" -exec grep -l '/dev/null | head -1) + MANIFEST=$(find . -maxdepth 3 -name "*.xml" ! -path "./.git/*" ! -path "./.gitea/*" -exec grep -l '/dev/null | head -1) + MOD_FILE=$(find . -maxdepth 4 -name "mod*.class.php" ! -path "./.git/*" -exec grep -l 'extends DolibarrModules' {} \; 2>/dev/null | head -1) echo "manifest=${MANIFEST}" >> "$GITHUB_OUTPUT" echo "mod_file=${MOD_FILE}" >> "$GITHUB_OUTPUT" -- 2.52.0 From dda39e64ae5391fe5c3073bbd05ce2b713215122 Mon Sep 17 00:00:00 2001 From: "gitea-actions[bot]" Date: Sat, 16 May 2026 22:26:59 +0000 Subject: [PATCH 20/21] chore: update development channel 00.00.01 [skip ci] --- updates.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/updates.xml b/updates.xml index f5e738f..92197ca 100644 --- a/updates.xml +++ b/updates.xml @@ -42,7 +42,7 @@ https://git.mokoconsulting.tech/MokoConsulting/MokoJoomTOS/releases/download/development/mokojoomtos-00.00.01-dev.zip - 6e2c9e139ded626fdafcfaaf7fb9cfffd58e3e8909bf68c68e78cf8156923f3a + 965377a22517ce6fd2196029004f9ec8bcb1e4071f17111655ab7c4376403c7f development Moko Consulting https://mokoconsulting.tech -- 2.52.0 From 3bf89ed10d7013b5cfb3be61cac6b72df668e1ac Mon Sep 17 00:00:00 2001 From: Jonathan Miller Date: Sat, 16 May 2026 17:29:52 -0500 Subject: [PATCH 21/21] chore: bump version to 04.00.00 Major version bump for multi-select support, Joomla 5 DI registration, and full route path matching. Co-Authored-By: Claude Opus 4.6 (1M context) --- CHANGELOG.md | 22 +++++++++++++++++++++- CLAUDE.md | 8 ++++---- README.md | 4 ++-- src/mokojoomtos.php | 2 +- src/mokojoomtos.xml | 2 +- src/services/provider.php | 2 +- updates.xml | 6 +++--- 7 files changed, 33 insertions(+), 13 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index fe6645d..0b83699 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -22,7 +22,7 @@ DEFGROUP: MokoJoomTOS INGROUP: plg_system_mokojoomtos REPO: https://github.com/mokoconsulting-tech/MokoJoomTOS - VERSION: 03.09.00 + VERSION: 04.00.00 PATH: ./CHANGELOG.md BRIEF: Version history and release notes --> @@ -36,6 +36,26 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +## [04.00.00] - 2026-05-16 + +### Added + +- Multi-select support: configure multiple menu items to remain accessible during offline mode +- `services/provider.php` for Joomla 5 dependency injection container registration +- Gitea-hosted update server URL in plugin manifest + +### Changed + +- Match against full menu route path instead of alias only (fixes nested routes like `/legal/terms-of-service`) +- Plugin pretty name updated to Joomla convention: "System - Moko Terms of Service" +- Renamed `.mokogitea/` to `.gitea/` for standard Gitea compatibility +- MenuslugField now stores and displays full route paths (e.g., `legal/terms-of-service`) + +### Removed + +- GitHub update server references (fully migrated to Gitea) +- Legacy `src/plugins/` directory + ## [03.09.00] - 2026-05-16 ### Fixed diff --git a/CLAUDE.md b/CLAUDE.md index ad1a656..3d5ba17 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -75,7 +75,7 @@ XML files use the MokoStandard header format: DEFGROUP: MokoJoomTOS INGROUP: plg_system_mokojoomtos PATH: src/mokojoomtos.xml - VERSION: 03.09.00 + VERSION: 04.00.00 BRIEF: [Brief description of file purpose] ========================================================================= --> @@ -88,7 +88,7 @@ Markdown files use an HTML comment format with the same structure. - **DEFGROUP**: Top-level group (always `MokoJoomTOS` for this repo) - **INGROUP**: Subgroup/component (always `plg_system_mokojoomtos`) - **PATH**: Relative path from repository root (e.g., `src/mokojoomtos.xml`) -- **VERSION**: Current plugin version (currently `03.09.00`) +- **VERSION**: Current plugin version (currently `04.00.00`) - **BRIEF**: One-line description of file's purpose ### Exempt Files @@ -327,7 +327,7 @@ No automated test infrastructure exists in this repository. Manual testing requi ```bash # Manual packaging (build scripts being migrated to scripts/ directory) cd src/ -zip -r ../plg_system_mokojoomtos-03.09.00.zip . +zip -r ../plg_system_mokojoomtos-04.00.00.zip . ``` Package should contain: `mokojoomtos.php`, `mokojoomtos.xml`, `script.php`, `src/`, `language/`, `administrator/` @@ -397,7 +397,7 @@ Before opening a pull request, ensure: - [ ] CHANGELOG.md updated with changes under correct version - [ ] README.md updated if user-facing changes -- [ ] All markdown file headers include VERSION: 03.09.00 +- [ ] All markdown file headers include VERSION: 04.00.00 - [ ] XML file headers include complete FILE INFORMATION block ## Version Management diff --git a/README.md b/README.md index 4ad085d..d16754b 100644 --- a/README.md +++ b/README.md @@ -2,14 +2,14 @@ A Joomla system plugin that keeps your Terms of Service, Privacy Policy, or any legal page accessible to visitors -- even when the site is in offline (maintenance) mode. -![Joomla](https://img.shields.io/badge/Joomla-5.x%20%7C%206.x-blue?style=flat-square&logo=joomla&logoColor=white) ![PHP](https://img.shields.io/badge/PHP-%E2%89%A58.1-777BB4?style=flat-square&logo=php&logoColor=white) ![License](https://img.shields.io/badge/license-GPL--3.0--or--later-green?style=flat-square) ![Version](https://img.shields.io/badge/version-03.09.00-orange?style=flat-square) ![Type](https://img.shields.io/badge/type-system%20plugin-blueviolet?style=flat-square) +![Joomla](https://img.shields.io/badge/Joomla-5.x%20%7C%206.x-blue?style=flat-square&logo=joomla&logoColor=white) ![PHP](https://img.shields.io/badge/PHP-%E2%89%A58.1-777BB4?style=flat-square&logo=php&logoColor=white) ![License](https://img.shields.io/badge/license-GPL--3.0--or--later-green?style=flat-square) ![Version](https://img.shields.io/badge/version-04.00.00-orange?style=flat-square) ![Type](https://img.shields.io/badge/type-system%20plugin-blueviolet?style=flat-square) | Field | Value | |---|---| | **Author** | [Moko Consulting](https://mokoconsulting.tech) | | **License** | GPL-3.0-or-later | | **Platform** | [Gitea](https://git.mokoconsulting.tech/MokoConsulting/MokoJoomTOS) | -| **Version** | 03.09.00 | +| **Version** | 04.00.00 | --- diff --git a/src/mokojoomtos.php b/src/mokojoomtos.php index 3bf9927..f7e64a0 100644 --- a/src/mokojoomtos.php +++ b/src/mokojoomtos.php @@ -42,7 +42,7 @@ class PlgSystemMokojoomtos extends CMSPlugin * * @return void * - * @since 03.09.00 + * @since 04.00.00 */ public function onAfterRoute() { diff --git a/src/mokojoomtos.xml b/src/mokojoomtos.xml index b578b7c..4e46359 100644 --- a/src/mokojoomtos.xml +++ b/src/mokojoomtos.xml @@ -25,7 +25,7 @@ DEFGROUP: MokoJoomTOS INGROUP: plg_system_mokojoomtos PATH: src/mokojoomtos.xml - VERSION: 03.09.00 + VERSION: 04.00.00 BRIEF: Plugin manifest XML file for MokoJoomTOS system plugin ========================================================================= --> diff --git a/src/services/provider.php b/src/services/provider.php index 0adb2a9..105f820 100644 --- a/src/services/provider.php +++ b/src/services/provider.php @@ -24,7 +24,7 @@ return new class () implements ServiceProviderInterface { * * @return void * - * @since 03.09.00 + * @since 04.00.00 */ public function register(Container $container) { diff --git a/updates.xml b/updates.xml index 92197ca..fa8788b 100644 --- a/updates.xml +++ b/updates.xml @@ -1,7 +1,7 @@