Improve cross-domain tracking and add "Always" script category
Move linker config into gtag('config') call with accept_incoming and
decorate_forms for reliable cross-domain linking. Capture _gl parameter
in sessionStorage to preserve attribution across navigation. Add
referrer-based attribution replay fallback so GA4 reports source/medium
instead of (not set) when UTMs are absent. Add "Always" script category
that executes without waiting for consent.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -28,6 +28,7 @@
|
|||||||
color: #fff;
|
color: #fff;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.att-cc-badge--always { background: #4CAF50; }
|
||||||
.att-cc-badge--functional { background: #2196F3; }
|
.att-cc-badge--functional { background: #2196F3; }
|
||||||
.att-cc-badge--analytics { background: #FF9800; }
|
.att-cc-badge--analytics { background: #FF9800; }
|
||||||
.att-cc-badge--marketing { background: #9C27B0; }
|
.att-cc-badge--marketing { background: #9C27B0; }
|
||||||
|
|||||||
@@ -82,11 +82,12 @@ $scripts = ATT_Consent_Scripts_Manager::get_all_scripts();
|
|||||||
<th><label for="att-cc-script-category"><?php esc_html_e( 'Category', 'att-consent' ); ?></label></th>
|
<th><label for="att-cc-script-category"><?php esc_html_e( 'Category', 'att-consent' ); ?></label></th>
|
||||||
<td>
|
<td>
|
||||||
<select id="att-cc-script-category" name="category">
|
<select id="att-cc-script-category" name="category">
|
||||||
|
<option value="always"><?php esc_html_e( 'Always', 'att-consent' ); ?></option>
|
||||||
<option value="functional"><?php esc_html_e( 'Functional', 'att-consent' ); ?></option>
|
<option value="functional"><?php esc_html_e( 'Functional', 'att-consent' ); ?></option>
|
||||||
<option value="analytics" selected><?php esc_html_e( 'Analytics', 'att-consent' ); ?></option>
|
<option value="analytics" selected><?php esc_html_e( 'Analytics', 'att-consent' ); ?></option>
|
||||||
<option value="marketing"><?php esc_html_e( 'Marketing', 'att-consent' ); ?></option>
|
<option value="marketing"><?php esc_html_e( 'Marketing', 'att-consent' ); ?></option>
|
||||||
</select>
|
</select>
|
||||||
<p class="description"><?php esc_html_e( 'The script will only execute after the visitor consents to this category.', 'att-consent' ); ?></p>
|
<p class="description"><?php esc_html_e( '"Always" scripts run on every page load without waiting for consent. Other categories execute only after the visitor consents.', 'att-consent' ); ?></p>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
|
|||||||
@@ -115,7 +115,6 @@ wait_for_update:c.wait_for_update||500
|
|||||||
});
|
});
|
||||||
window.attCCHasConsent=false;
|
window.attCCHasConsent=false;
|
||||||
}
|
}
|
||||||
if(c.linker_domains&&c.linker_domains.length){g('set','linker',{'domains':c.linker_domains});}
|
|
||||||
if(!sessionStorage.getItem('att_cc_attr')){
|
if(!sessionStorage.getItem('att_cc_attr')){
|
||||||
var p=new URLSearchParams(window.location.search);
|
var p=new URLSearchParams(window.location.search);
|
||||||
var a={
|
var a={
|
||||||
@@ -128,9 +127,10 @@ ut:p.get('utm_term')||'',
|
|||||||
uo:p.get('utm_content')||'',
|
uo:p.get('utm_content')||'',
|
||||||
gc:p.get('gclid')||'',
|
gc:p.get('gclid')||'',
|
||||||
dc:p.get('dclid')||'',
|
dc:p.get('dclid')||'',
|
||||||
|
gl:p.get('_gl')||'',
|
||||||
t:Date.now()
|
t:Date.now()
|
||||||
};
|
};
|
||||||
if(a.r||a.us||a.gc){
|
if(a.r||a.us||a.gc||a.gl){
|
||||||
sessionStorage.setItem('att_cc_attr',JSON.stringify(a));
|
sessionStorage.setItem('att_cc_attr',JSON.stringify(a));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -176,7 +176,7 @@ j=d.createElement(s),dl=l!='dataLayer'?'&l='+l:'';j.async=true;j.src=
|
|||||||
if ( 'gtag' === $s['tracking_mode'] && ! empty( $s['ga4_measurement_id'] ) ) {
|
if ( 'gtag' === $s['tracking_mode'] && ! empty( $s['ga4_measurement_id'] ) ) {
|
||||||
$id = esc_attr( $s['ga4_measurement_id'] );
|
$id = esc_attr( $s['ga4_measurement_id'] );
|
||||||
return "<script async src=\"https://www.googletagmanager.com/gtag/js?id={$id}\"></script>
|
return "<script async src=\"https://www.googletagmanager.com/gtag/js?id={$id}\"></script>
|
||||||
<script>window.attCCGtag('config','{$id}');</script>";
|
<script>(function(){var o={};var c=window.attCCConfig||{};if(c.linker_domains&&c.linker_domains.length){o.linker={domains:c.linker_domains,accept_incoming:true,decorate_forms:true};}window.attCCGtag('config','{$id}',o);})();</script>";
|
||||||
}
|
}
|
||||||
|
|
||||||
return '';
|
return '';
|
||||||
|
|||||||
@@ -97,7 +97,7 @@ class ATT_Consent_Scripts_Manager {
|
|||||||
global $wpdb;
|
global $wpdb;
|
||||||
$table = self::table_name();
|
$table = self::table_name();
|
||||||
|
|
||||||
$allowed_categories = array( 'functional', 'analytics', 'marketing' );
|
$allowed_categories = array( 'always', 'functional', 'analytics', 'marketing' );
|
||||||
$allowed_placements = array( 'head', 'footer' );
|
$allowed_placements = array( 'head', 'footer' );
|
||||||
$allowed_statuses = array( 'active', 'inactive' );
|
$allowed_statuses = array( 'active', 'inactive' );
|
||||||
|
|
||||||
@@ -150,6 +150,7 @@ class ATT_Consent_Scripts_Manager {
|
|||||||
public static function get_scripts_for_frontend() {
|
public static function get_scripts_for_frontend() {
|
||||||
$scripts = self::get_scripts();
|
$scripts = self::get_scripts();
|
||||||
$grouped = array(
|
$grouped = array(
|
||||||
|
'always' => array( 'head' => array(), 'footer' => array() ),
|
||||||
'functional' => array( 'head' => array(), 'footer' => array() ),
|
'functional' => array( 'head' => array(), 'footer' => array() ),
|
||||||
'analytics' => array( 'head' => array(), 'footer' => array() ),
|
'analytics' => array( 'head' => array(), 'footer' => array() ),
|
||||||
'marketing' => array( 'head' => array(), 'footer' => array() ),
|
'marketing' => array( 'head' => array(), 'footer' => array() ),
|
||||||
@@ -193,6 +194,18 @@ class ATT_Consent_Scripts_Manager {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// "Always" scripts execute immediately without consent gating.
|
||||||
|
if ( 'always' === $script['category'] ) {
|
||||||
|
if ( preg_match( '/<script[\s>]/i', $snippet ) ) {
|
||||||
|
$output .= $snippet . "\n";
|
||||||
|
} elseif ( preg_match( '/^\s*</', $snippet ) ) {
|
||||||
|
$output .= $snippet . "\n";
|
||||||
|
} else {
|
||||||
|
$output .= '<script>' . $snippet . '</script>' . "\n";
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
// Check if snippet contains <script> tags.
|
// Check if snippet contains <script> tags.
|
||||||
if ( preg_match( '/<script[\s>]/i', $snippet ) ) {
|
if ( preg_match( '/<script[\s>]/i', $snippet ) ) {
|
||||||
// Rewrite each <script> tag to type="text/plain" with category attribute.
|
// Rewrite each <script> tag to type="text/plain" with category attribute.
|
||||||
|
|||||||
@@ -65,6 +65,7 @@ var AttConsent = (function() {
|
|||||||
wp_set_consent('statistics', categories.analytics ? 'allow' : 'deny');
|
wp_set_consent('statistics', categories.analytics ? 'allow' : 'deny');
|
||||||
wp_set_consent('marketing', categories.marketing ? 'allow' : 'deny');
|
wp_set_consent('marketing', categories.marketing ? 'allow' : 'deny');
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -88,6 +89,28 @@ var AttConsent = (function() {
|
|||||||
if (a.ut) { params.campaign_term = a.ut; }
|
if (a.ut) { params.campaign_term = a.ut; }
|
||||||
if (a.uo) { params.campaign_content = a.uo; }
|
if (a.uo) { params.campaign_content = a.uo; }
|
||||||
|
|
||||||
|
// If no UTMs/gclid, derive source/medium from referrer so GA4
|
||||||
|
// doesn't report (not set). Important for cross-domain tracking
|
||||||
|
// where the _gl param may have been lost before consent was granted.
|
||||||
|
if (!a.us && !a.gc && a.r) {
|
||||||
|
try {
|
||||||
|
var ref = new URL(a.r);
|
||||||
|
var linkerDomains = config.linker_domains || [];
|
||||||
|
var isLinkerDomain = linkerDomains.some(function(d) {
|
||||||
|
return ref.hostname === d || ref.hostname.endsWith('.' + d);
|
||||||
|
});
|
||||||
|
// Only set referral attribution if referrer is from a different
|
||||||
|
// host and NOT a configured cross-domain linker domain (those
|
||||||
|
// should be seamless continuations, not referrals).
|
||||||
|
if (ref.hostname !== window.location.hostname && !isLinkerDomain) {
|
||||||
|
params.campaign_source = ref.hostname;
|
||||||
|
params.campaign_medium = 'referral';
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
// Invalid referrer URL - skip.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (Object.keys(params).length > 0) {
|
if (Object.keys(params).length > 0) {
|
||||||
gtag('set', params);
|
gtag('set', params);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user