From f49f592cba6a593d569f8d0f58926b5f9c6a53eb Mon Sep 17 00:00:00 2001 From: Jonathan Miller Date: Tue, 5 May 2026 15:26:30 -0500 Subject: [PATCH] feat: smart visitor detection for Google Analytics / GTM Push anonymised visitor properties (login status, user group, page type) to the dataLayer before GTM/GA4 loads. Sets GA4 user_properties for persistent session-scoped dimensions. No PII is sent. Default enabled when GTM or GA4 is active. Co-Authored-By: Claude Opus 4.6 (1M context) --- CHANGELOG.md | 5 ++++ README.md | 2 +- docs/ROADMAP.md | 10 ++++++++ src/index.php | 38 +++++++++++++++++++++++++++++ src/language/en-GB/tpl_mokoonyx.ini | 2 ++ src/language/en-US/tpl_mokoonyx.ini | 2 ++ src/templateDetails.xml | 4 +++ 7 files changed, 62 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 727767a..641468a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -19,6 +19,11 @@ All notable changes to the MokoOnyx Joomla template are documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [Unreleased] + +### Added +- **Smart Visitor Detection** — Pushes anonymised visitor properties (login status, user group, page type) to the dataLayer for Google Analytics / Tag Manager. Sets GA4 `user_properties` for persistent session-scoped dimensions. No PII is sent. Default enabled when GTM or GA4 is active. + ## [03.10.00] - 2026-04-18 — Bridge Release (MokoOnyx → MokoOnyx) ### Important diff --git a/README.md b/README.md index f8c5709..007c789 100644 --- a/README.md +++ b/README.md @@ -33,7 +33,7 @@ MokoOnyx is a modern, lightweight enhancement layer built on top of Joomla's Cas - **Bootstrap 5**: Extended utility classes and responsive grid system - **Template Overrides**: Includes overrides for all core Joomla modules, Community Builder, and DPCalendar - **Dark Mode Support**: Built-in light/dark mode toggle with system preference detection -- **Google Tag Manager / GA4**: Optional analytics integrations +- **Google Tag Manager / GA4**: Optional analytics integrations with smart visitor detection (login status, user group, page type) - **Table of Contents**: Automatic TOC generation for long articles ## Requirements diff --git a/docs/ROADMAP.md b/docs/ROADMAP.md index b1ccdd1..9faa2f5 100644 --- a/docs/ROADMAP.md +++ b/docs/ROADMAP.md @@ -565,6 +565,15 @@ Users still running MokoCassiopeia must install MokoOnyx v01.x first to migrate - **Universal Analytics Fallback**: Legacy UA support - **Privacy-First**: Conditional loading based on settings +#### Smart Visitor Detection +- **Enable/Disable**: Admin toggle (default: enabled) +- **Visitor Type**: Pushes `logged_in` or `guest` to dataLayer +- **Visitor Group**: Pushes highest-privilege Joomla user group name (e.g., "Registered", "Author") +- **Page Type**: Pushes component + view (e.g., `com_content.article`) +- **GA4 User Properties**: Sets `visitor_type` and `visitor_group` as persistent user-scoped dimensions +- **Privacy-Safe**: No PII (usernames, emails, or user IDs) is ever sent +- **Dual Integration**: Works with both GTM (`moko.visitor_detect` event) and standalone GA4 (`user_properties`) + ### 🎛️ Customization & Developer Tools #### Custom Code Injection @@ -657,6 +666,7 @@ Users still running MokoCassiopeia must install MokoOnyx v01.x first to migrate - `googletagmanagerid` - GTM container ID - `googleanalytics` - Enable GA4 - `googleanalyticsid` - GA4 property ID +- `googlevisitordetection` - Smart Visitor Detection (default: enabled) #### Custom Code Tab - `custom_head_start` - Custom code at head start diff --git a/src/index.php b/src/index.php index bc7f584..00a1653 100644 --- a/src/index.php +++ b/src/index.php @@ -37,6 +37,7 @@ $params_googletagmanagerid = $this->params->get('googletagmanagerid', null); $params_googleanalytics = $this->params->get('googleanalytics', false); $params_googleanalyticsid = $this->params->get('googleanalyticsid', null); $params_googlesitekey = $this->params->get('googlesitekey', null); +$params_visitordetection = $this->params->get('googlevisitordetection', true); $params_custom_head_start = $this->params->get('custom_head_start', null); $params_custom_head_end = $this->params->get('custom_head_end', null); $params_developmentmode = $this->params->get('developmentmode', false) || $app->get('debug', false); @@ -349,6 +350,37 @@ $wa->useScript('user.js'); // js/user.js . $hasClass . ($this->direction == 'rtl' ? ' rtl' : ''); ?>"> +guest ? 'guest' : 'logged_in'; + $visitorGroup = 'none'; + if (!$user->guest) { + $groupIds = $user->getAuthorisedGroups(); + if (!empty($groupIds)) { + $db = Factory::getContainer()->get(\Joomla\Database\DatabaseInterface::class); + $query = $db->getQuery(true) + ->select($db->quoteName('title')) + ->from($db->quoteName('#__usergroups')) + ->where($db->quoteName('id') . ' = ' . (int) end($groupIds)); + $db->setQuery($query); + $visitorGroup = $db->loadResult() ?: 'unknown'; + } + } + $pageType = $option . ($view ? '.' . $view : ''); +?> + + + + + @@ -398,6 +430,12 @@ $wa->useScript('user.js'); // js/user.js console.warn('Unrecognized Google Analytics ID format:', id); } })(''); + + gtag('set', 'user_properties', { + 'visitor_type': 'guest ? 'guest' : 'logged_in'; ?>', + 'visitor_group': '' + }); + diff --git a/src/language/en-GB/tpl_mokoonyx.ini b/src/language/en-GB/tpl_mokoonyx.ini index 8c26548..aa2389e 100644 --- a/src/language/en-GB/tpl_mokoonyx.ini +++ b/src/language/en-GB/tpl_mokoonyx.ini @@ -46,6 +46,8 @@ TPL_MOKOONYX_GOOGLEANALYTICSID_LABEL="Google Analytics ID" TPL_MOKOONYX_GOOGLEANALYTICSID_DESC="Begins with 'G-'" TPL_MOKOONYX_GOOGLESITEKEY_LABEL="Google Search Console Verification" TPL_MOKOONYX_GOOGLESITEKEY_DESC="Paste the content value from the <meta name="google-site-verification"> tag. Find this in Google Search Console under Ownership Verification → HTML tag method." +TPL_MOKOONYX_GOOGLE_VISITOR_DETECTION_LABEL="Smart Visitor Detection" +TPL_MOKOONYX_GOOGLE_VISITOR_DETECTION_DESC="Push anonymised visitor properties (login status, user group, page type) to the dataLayer for use in Google Analytics / Tag Manager. No personally identifiable information is sent." ; ===== Branding & icons (Theme tab) ===== TPL_MOKOONYX_BRAND_LABEL="Brand" diff --git a/src/language/en-US/tpl_mokoonyx.ini b/src/language/en-US/tpl_mokoonyx.ini index 3bd4663..f83f78d 100644 --- a/src/language/en-US/tpl_mokoonyx.ini +++ b/src/language/en-US/tpl_mokoonyx.ini @@ -46,6 +46,8 @@ TPL_MOKOONYX_GOOGLEANALYTICSID_LABEL="Google Analytics ID" TPL_MOKOONYX_GOOGLEANALYTICSID_DESC="Begins with 'G-'" TPL_MOKOONYX_GOOGLESITEKEY_LABEL="Google Search Console Verification" TPL_MOKOONYX_GOOGLESITEKEY_DESC="Paste the content value from the <meta name="google-site-verification"> tag. Find this in Google Search Console under Ownership Verification → HTML tag method." +TPL_MOKOONYX_GOOGLE_VISITOR_DETECTION_LABEL="Smart Visitor Detection" +TPL_MOKOONYX_GOOGLE_VISITOR_DETECTION_DESC="Push anonymised visitor properties (login status, user group, page type) to the dataLayer for use in Google Analytics / Tag Manager. No personally identifiable information is sent." ; ===== Branding & icons (Theme tab) ===== TPL_MOKOONYX_BRAND_LABEL="Brand" diff --git a/src/templateDetails.xml b/src/templateDetails.xml index fff6dbf..d4acf3e 100644 --- a/src/templateDetails.xml +++ b/src/templateDetails.xml @@ -142,6 +142,10 @@ + + + + -- 2.52.0