diff --git a/assets/js/src/index.js b/assets/js/src/index.js index 1ef34fb8..006e30b4 100644 --- a/assets/js/src/index.js +++ b/assets/js/src/index.js @@ -1,6 +1,10 @@ import { setupEventHandlers } from './tracker'; import { classicTracking } from './integrations/classic'; import { blocksTracking } from './integrations/blocks'; +import { + setCurrentConsentState, + addConsentStateChangeEventListener, +} from './integrations/wp-consent-api'; // Wait for 'ga4w:ready' event if `window.ga4w` is not there yet. if ( window.ga4w ) { @@ -15,7 +19,11 @@ if ( window.ga4w ) { window.addEventListener( 'load', warnIfDataMissing ); } } + function initializeTracking() { + setCurrentConsentState( window.ga4w.settings ); + addConsentStateChangeEventListener( window.ga4w.settings ); + const getEventHandler = setupEventHandlers( window.ga4w.settings ); classicTracking( getEventHandler, window.ga4w.data ); diff --git a/assets/js/src/integrations/wp-consent-api.js b/assets/js/src/integrations/wp-consent-api.js new file mode 100644 index 00000000..d2176eb2 --- /dev/null +++ b/assets/js/src/integrations/wp-consent-api.js @@ -0,0 +1,67 @@ +const consentMap = { + statistics: [ 'analytics_storage' ], + marketing: [ 'ad_storage', 'ad_user_data', 'ad_personalization' ], +}; + +export const setCurrentConsentState = ( { + tracker_function_name: trackerFunctionName, +} ) => { + // eslint-disable-next-line camelcase -- `wp_has_consent` is defined by the WP Consent API plugin. + if ( typeof wp_has_consent === 'function' ) { + if ( window.wp_consent_type === undefined ) { + window.wp_consent_type = 'optin'; + } + + const consentState = {}; + + for ( const [ category, types ] of Object.entries( consentMap ) ) { + if ( + // eslint-disable-next-line camelcase, no-undef -- `consent_api_get_cookie` is defined by the WP Consent API plugin. + consent_api_get_cookie( + window.consent_api.cookie_prefix + '_' + category + ) !== '' + ) { + // eslint-disable-next-line camelcase, no-undef -- `wp_has_consent` is defined by the WP Consent API plugin. + const hasConsent = wp_has_consent( category ) + ? 'granted' + : 'denied'; + + types.forEach( ( type ) => { + consentState[ type ] = hasConsent; + } ); + } + } + + if ( Object.keys( consentState ).length > 0 ) { + window[ trackerFunctionName ]( 'consent', 'update', consentState ); + } + } +}; + +export const addConsentStateChangeEventListener = ( { + tracker_function_name: trackerFunctionName, +} ) => { + document.addEventListener( 'wp_listen_for_consent_change', ( event ) => { + const consentUpdate = {}; + + const types = consentMap[ Object.keys( event.detail )[ 0 ] ]; + const state = + Object.values( event.detail )[ 0 ] === 'allow' + ? 'granted' + : 'denied'; + + if ( types !== undefined ) { + types.forEach( ( type ) => { + consentUpdate[ type ] = state; + } ); + + if ( Object.keys( consentUpdate ).length > 0 ) { + window[ trackerFunctionName ]( + 'consent', + 'update', + consentUpdate + ); + } + } + } ); +}; diff --git a/includes/class-wc-google-analytics.php b/includes/class-wc-google-analytics.php index 7bd02f58..59c9d141 100644 --- a/includes/class-wc-google-analytics.php +++ b/includes/class-wc-google-analytics.php @@ -58,6 +58,9 @@ public function __construct() { // utm_nooverride parameter for Google AdWords add_filter( 'woocommerce_get_return_url', array( $this, 'utm_nooverride' ) ); + // Mark extension as compatible with WP Consent API + add_filter( 'wp_consent_api_registered_' . plugin_basename( __FILE__ ), '__return_true' ); + // Dequeue the WooCommerce Blocks Google Analytics integration, // not to let it register its `gtag` function so that we could provide a more detailed configuration. add_action( diff --git a/includes/class-wc-google-gtag-js.php b/includes/class-wc-google-gtag-js.php index 3a95a49e..dbb52028 100644 --- a/includes/class-wc-google-gtag-js.php +++ b/includes/class-wc-google-gtag-js.php @@ -94,7 +94,7 @@ private function register_scripts(): void { function %2$s(){dataLayer.push(arguments);} // Set up default consent state. for ( const mode of %4$s || [] ) { - %2$s( "consent", "default", mode ); + %2$s( "consent", "default", { "wait_for_update": 500, ...mode } ); } %2$s("js", new Date()); %2$s("set", "developer_id.%3$s", true);