From a87a19e33155ec3d003018b4f289c8c5963c92ec Mon Sep 17 00:00:00 2001 From: Chardonneaur Date: Thu, 29 Jan 2026 12:13:36 +0100 Subject: [PATCH] Add Regex Event Trigger A new trigger that fires on custom events matching a regex pattern. Features: - Configurable regex pattern field (default: .* matches all events) - Skips internal Matomo events (mtm.*) - Replays missed events from before container load - Use {{Event Name}} variable to access the triggering event Example patterns: - .* (all events) - ^form_ (events starting with 'form_') - click|submit (events containing 'click' or 'submit') - ^(purchase|checkout)$ (exactly 'purchase' or 'checkout') Co-Authored-By: Claude Opus 4.5 --- Template/Trigger/RegexEventTrigger.php | 58 +++++++++++++++++ Template/Trigger/RegexEventTrigger.web.js | 76 +++++++++++++++++++++++ images/RegexEventTrigger.svg | 4 ++ lang/en.json | 8 ++- 4 files changed, 145 insertions(+), 1 deletion(-) create mode 100644 Template/Trigger/RegexEventTrigger.php create mode 100644 Template/Trigger/RegexEventTrigger.web.js create mode 100644 images/RegexEventTrigger.svg diff --git a/Template/Trigger/RegexEventTrigger.php b/Template/Trigger/RegexEventTrigger.php new file mode 100644 index 0000000..8469706 --- /dev/null +++ b/Template/Trigger/RegexEventTrigger.php @@ -0,0 +1,58 @@ +makeSetting('eventNamePattern', '.*', FieldConfig::TYPE_STRING, function (FieldConfig $field) { + $field->title = Piwik::translate('TagManagerExtended_RegexEventTriggerPatternTitle'); + $field->description = Piwik::translate('TagManagerExtended_RegexEventTriggerPatternDescription'); + $field->uiControl = FieldConfig::UI_CONTROL_TEXT; + $field->inlineHelp = Piwik::translate('TagManagerExtended_RegexEventTriggerPatternHelp'); + }), + ]; + } + + public function getOrder() + { + return 50; + } +} diff --git a/Template/Trigger/RegexEventTrigger.web.js b/Template/Trigger/RegexEventTrigger.web.js new file mode 100644 index 0000000..b329643 --- /dev/null +++ b/Template/Trigger/RegexEventTrigger.web.js @@ -0,0 +1,76 @@ +(function () { + return function (parameters, TagManager) { + + var pattern = parameters.get('eventNamePattern') || '.*'; + var regex; + + try { + regex = new RegExp(pattern); + } catch (e) { + // Invalid regex, fall back to match all + regex = new RegExp('.*'); + } + + /** + * Check if the dataLayer push matches our regex pattern. + * We match any object with an 'event' property that: + * 1. Is not a Matomo internal event (mtm.*) + * 2. Matches the user-defined regex pattern + */ + function isMatchingEvent(value) { + if (!TagManager.utils.isObject(value)) { + return false; + } + + if (!('event' in value)) { + return false; + } + + var eventName = value.event; + + // Must be a string + if (typeof eventName !== 'string') { + return false; + } + + // Skip Matomo Tag Manager internal events (they start with 'mtm.') + if (eventName.indexOf('mtm.') === 0) { + return false; + } + + // Test against the regex pattern + return regex.test(eventName); + } + + // Catch all events that were triggered before the container was fully set up + var missedEvents = []; + var index = parameters.container.dataLayer.on(function (value) { + if (isMatchingEvent(value)) { + missedEvents.push(value.event); + } + }); + + this.setUp = function (triggerEvent) { + // Stop listening to the initial listener + parameters.container.dataLayer.off(index); + + // Replay any missed events + for (var i = 0; i < missedEvents.length; i++) { + triggerEvent({ + event: 'mtm.RegexEvent', + 'mtm.customEventMatch': missedEvents[i] + }); + } + + // Listen for all future dataLayer pushes + parameters.container.dataLayer.on(function (value) { + if (isMatchingEvent(value)) { + triggerEvent({ + event: 'mtm.RegexEvent', + 'mtm.customEventMatch': value.event + }); + } + }); + }; + }; +})(); diff --git a/images/RegexEventTrigger.svg b/images/RegexEventTrigger.svg new file mode 100644 index 0000000..4ccba2f --- /dev/null +++ b/images/RegexEventTrigger.svg @@ -0,0 +1,4 @@ + + + .* + diff --git a/lang/en.json b/lang/en.json index a0a8eee..2b411eb 100644 --- a/lang/en.json +++ b/lang/en.json @@ -205,6 +205,12 @@ "GoogleUserProvidedDataTagAddressPostalCodeTitle": "address.postal_code", "GoogleUserProvidedDataTagAddressPostalCodeDescription": "User post code. Example: 'SO99 9XX'", "GoogleUserProvidedDataTagAddressCountryTitle": "address.country", - "GoogleUserProvidedDataTagAddressCountryDescription": "User country code. Example: 'UK'. Use 2-letter country codes, per the ISO 3166-1 alpha-2 standard." + "GoogleUserProvidedDataTagAddressCountryDescription": "User country code. Example: 'UK'. Use 2-letter country codes, per the ISO 3166-1 alpha-2 standard.", + "RegexEventTriggerName": "Regex Event", + "RegexEventTriggerDescription": "Fires on custom events matching a regex pattern. Use .* to match all events.", + "RegexEventTriggerHelp": "This trigger fires when an event name matches your regex pattern. Use the built-in variable 'Event Name' in your tags to access the name of the event that triggered it.", + "RegexEventTriggerPatternTitle": "Event Name Pattern (Regex)", + "RegexEventTriggerPatternDescription": "Regular expression pattern to match event names. Use .* to match all events.", + "RegexEventTriggerPatternHelp": "Examples: .* (all events), ^form_ (events starting with 'form_'), click|submit (events containing 'click' or 'submit'), ^(purchase|checkout)$ (exactly 'purchase' or 'checkout')" } }