0
Fork 0
mirror of https://github.com/TryGhost/Ghost.git synced 2025-02-03 23:00:14 -05:00

Added attribution to recommendation clicks (#18077)

fixes https://github.com/TryGhost/Product/issues/3865
This commit is contained in:
Simon Backx 2023-09-12 11:21:37 +02:00 committed by GitHub
parent 6475895f9e
commit 562123f06a
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 28 additions and 7 deletions

View file

@ -1,6 +1,6 @@
import setupGhostApi from './utils/api';
import {HumanReadableError} from './utils/errors';
import {createPopupNotification, getMemberEmail, getMemberName, getProductCadenceFromPrice, removePortalLinkFromUrl} from './utils/helpers';
import {createPopupNotification, getMemberEmail, getMemberName, getProductCadenceFromPrice, removePortalLinkFromUrl, getRefDomain} from './utils/helpers';
function switchPage({data, state}) {
return {
@ -480,7 +480,7 @@ async function oneClickSubscribe({data: {siteUrl}, state}) {
const {t, member} = state;
const referrerUrl = window.location.href;
const referrerSource = window.location.hostname.replace(/^www\./, '');
const referrerSource = getRefDomain();
await externalSiteApi.member.sendMagicLink({
emailType: 'signup',

View file

@ -1,10 +1,11 @@
import AppContext from '../../AppContext';
import {useContext, useState, useEffect, useCallback} from 'react';
import {useContext, useState, useEffect, useCallback, useMemo} from 'react';
import CloseButton from '../common/CloseButton';
import {clearURLParams} from '../../utils/notifications';
import LoadingPage from './LoadingPage';
import {ReactComponent as CheckmarkIcon} from '../../images/icons/checkmark-fill.svg';
import {ReactComponent as LoaderIcon} from '../../images/icons/loader.svg';
import {getRefDomain} from '../../utils/helpers';
export const RecommendationsPageStyles = `
.gh-portal-recommendation-item .gh-portal-list-detail {
@ -95,10 +96,25 @@ const RecommendationItem = (recommendation) => {
const [subscribed, setSubscribed] = useState(false);
const [loading, setLoading] = useState(false);
const refUrl = useMemo(() => {
try {
const ref = new URL(url);
if (ref.searchParams.has('ref') || ref.searchParams.has('utm_source') || ref.searchParams.has('source')) {
// Don't overwrite + keep existing source attribution
return url;
}
ref.searchParams.set('ref', getRefDomain());
return ref.toString();
} catch (_) {
return url;
}
}, [url]);
const visitHandler = useCallback(() => {
// Open url in a new tab
openTab(url);
}, [url]);
openTab(refUrl);
}, [refUrl]);
const oneClickSubscribeHandler = useCallback(async () => {
try {
@ -110,13 +126,13 @@ const RecommendationItem = (recommendation) => {
setSubscribed(true);
} catch (_) {
// Open portal signup page
const signupUrl = new URL('#/portal/signup', url);
const signupUrl = new URL('#/portal/signup', refUrl);
// Trigger a visit
openTab(signupUrl);
}
setLoading(false);
}, [setSubscribed, url]);
}, [setSubscribed, url, refUrl]);
const clickHandler = useCallback((e) => {
if (loading) {

View file

@ -259,6 +259,11 @@ export function hasMultipleProducts({site}) {
return false;
}
export function getRefDomain() {
const referrerSource = window.location.hostname.replace(/^www\./, '');
return referrerSource;
}
export function hasMultipleProductsFeature({site}) {
const {portal_products: portalProducts} = site || {};
return !!portalProducts;