Add tagged events support for revenue goals (#3038)

* Add tagged events support for revenue goals

This commit adds two special classes for tracking revenue with tagged
events. The following example sends an event with revenue data when the
tracker script has revenue and tagged-events script extensions:

```html
<button class="plausible-event-revenue-amount=10.29 plausible-event-revenue-currency=EUR"></button>
```

* Rename special revenue tracking class name
This commit is contained in:
Vini Brasil 2023-06-19 12:59:47 +01:00 committed by GitHub
parent 94591a5a20
commit 67be43b6e6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 59 additions and 16 deletions

View File

@ -58,11 +58,19 @@ function sendLinkClickEvent(event, link, eventAttrs) {
} }
if (shouldFollowLink(event, link)) { if (shouldFollowLink(event, link)) {
plausible(eventAttrs.name, { props: eventAttrs.props, callback: followLink }) var attrs = { props: eventAttrs.props, callback: followLink }
{{#if revenue}}
attrs.revenue = eventAttrs.revenue
{{/if}}
plausible(eventAttrs.name, attrs)
setTimeout(followLink, 5000) setTimeout(followLink, 5000)
event.preventDefault() event.preventDefault()
} else { } else {
plausible(eventAttrs.name, { props: eventAttrs.props }) var attrs = { props: eventAttrs.props }
{{#if revenue}}
attrs.revenue = eventAttrs.revenue
{{/if}}
plausible(eventAttrs.name, attrs)
} }
} }
@ -97,6 +105,9 @@ function isDownloadToTrack(url) {
function getTaggedEventAttributes(htmlElement) { function getTaggedEventAttributes(htmlElement) {
var taggedElement = isTagged(htmlElement) ? htmlElement : htmlElement && htmlElement.parentNode var taggedElement = isTagged(htmlElement) ? htmlElement : htmlElement && htmlElement.parentNode
var eventAttrs = { name: null, props: {} } var eventAttrs = { name: null, props: {} }
{{#if revenue}}
eventAttrs.revenue = {}
{{/if}}
var classList = taggedElement && taggedElement.classList var classList = taggedElement && taggedElement.classList
if (!classList) { return eventAttrs } if (!classList) { return eventAttrs }
@ -105,18 +116,27 @@ function getTaggedEventAttributes(htmlElement) {
var className = classList.item(i) var className = classList.item(i)
var matchList = className.match(/plausible-event-(.+)(=|--)(.+)/) var matchList = className.match(/plausible-event-(.+)(=|--)(.+)/)
if (!matchList) { continue } if (matchList) {
var key = matchList[1] var key = matchList[1]
var value = matchList[3].replace(/\+/g, ' ') var value = matchList[3].replace(/\+/g, ' ')
if (key.toLowerCase() === 'name') { if (key.toLowerCase() == 'name') {
eventAttrs.name = value eventAttrs.name = value
} else { } else {
eventAttrs.props[key] = value eventAttrs.props[key] = value
} }
} }
{{#if revenue}}
var revenueMatchList = className.match(/plausible-revenue-(.+)(=|--)(.+)/)
if (revenueMatchList) {
var key = revenueMatchList[1]
var value = revenueMatchList[3]
eventAttrs.revenue[key] = value
}
{{/if}}
}
return eventAttrs return eventAttrs
} }
@ -136,7 +156,12 @@ function handleTaggedFormSubmitEvent(event) {
} }
setTimeout(submitForm, 5000) setTimeout(submitForm, 5000)
plausible(eventAttrs.name, { props: eventAttrs.props, callback: submitForm })
var attrs = { props: eventAttrs.props, callback: submitForm }
{{#if revenue}}
attrs.revenue = eventAttrs.revenue
{{/if}}
plausible(eventAttrs.name, attrs)
} }
function isForm(element) { function isForm(element) {
@ -171,7 +196,12 @@ function handleTaggedElementClickEvent(event) {
eventAttrs.props.url = clickedLink.href eventAttrs.props.url = clickedLink.href
sendLinkClickEvent(event, clickedLink, eventAttrs) sendLinkClickEvent(event, clickedLink, eventAttrs)
} else { } else {
plausible(eventAttrs.name, { props: eventAttrs.props }) var attrs = {}
attrs.props = eventAttrs.props
{{#if revenue}}
attrs.revenue = eventAttrs.revenue
{{/if}}
plausible(eventAttrs.name, attrs)
} }
} }
} }

View File

@ -7,11 +7,15 @@
<meta http-equiv="X-UA-Compatible" content="ie=edge"> <meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Plausible Playwright tests</title> <title>Plausible Playwright tests</title>
<script defer src="/tracker/js/plausible.local.manual.revenue.js"></script> <script defer src="/tracker/js/plausible.local.manual.revenue.tagged-events.js"></script>
</head> </head>
<body> <body>
<button id="purchase" onclick="window.plausible('Purchase', {revenue: {amount: 15.99, currency: 'USD'}})"> <button id="manual-purchase" onclick="window.plausible('Purchase', {revenue: {amount: 15.99, currency: 'USD'}})">
Click me
</button>
<button id="tagged-purchase" class="plausible-event-name=Purchase plausible-revenue-currency=EUR plausible-revenue-amount=13.32">
Click me Click me
</button> </button>
</body> </body>

View File

@ -2,12 +2,21 @@ const { mockRequest, expectCustomEvent } = require('./support/test-utils');
const { expect, test } = require('@playwright/test'); const { expect, test } = require('@playwright/test');
test.describe('with revenue script extension', () => { test.describe('with revenue script extension', () => {
test('sends revenue currency and amount', async ({ page }) => { test('sends revenue currency and amount in manual mode', async ({ page }) => {
const plausibleRequestMock = mockRequest(page, '/api/event') const plausibleRequestMock = mockRequest(page, '/api/event')
await page.goto('/revenue.html'); await page.goto('/revenue.html');
await page.click('#purchase') await page.click('#manual-purchase')
const plausibleRequest = await plausibleRequestMock const plausibleRequest = await plausibleRequestMock
expect(plausibleRequest.postDataJSON()["$"]).toEqual({amount: 15.99, currency: "USD"}) expect(plausibleRequest.postDataJSON()["$"]).toEqual({amount: 15.99, currency: "USD"})
}); });
test('sends revenue currency and amount with tagged class name', async ({ page }) => {
const plausibleRequestMock = mockRequest(page, '/api/event')
await page.goto('/revenue.html');
await page.click('#tagged-purchase')
const plausibleRequest = await plausibleRequestMock
expect(plausibleRequest.postDataJSON()["$"]).toEqual({amount: "13.32", currency: "EUR"})
});
}); });