Skip to content

Commit

Permalink
Merge pull request #8423 from google/enhancement/#8273-analytics-gtag…
Browse files Browse the repository at this point in the history
…-infra
  • Loading branch information
aaemnnosttv committed Mar 28, 2024
2 parents d6c58d6 + 1ee2a8a commit e0232dd
Show file tree
Hide file tree
Showing 4 changed files with 82 additions and 75 deletions.
31 changes: 24 additions & 7 deletions includes/Core/Tags/GTag.php
Expand Up @@ -116,27 +116,26 @@ protected function enqueue_gtag_script() {
return;
}

// Load the GTag scripts using the first tag ID - it doesn't matter which is used, all registered tags will be set up with a
// config command regardless of which is used to load the source.
$gtag_src = 'https://www.googletagmanager.com/gtag/js?id=' . rawurlencode( $this->tags[0]['tag_id'] );
$gtag_src = $this->get_gtag_src();

// phpcs:ignore WordPress.WP.EnqueuedResourceParameters.MissingVersion
wp_enqueue_script( self::HANDLE, $gtag_src, false, null, false );
wp_script_add_data( self::HANDLE, 'script_execution', 'async' );

// Note that `gtag()` may already be defined via the `Consent_Mode` output, but this is safe to call multiple times.
wp_add_inline_script( self::HANDLE, 'window.dataLayer = window.dataLayer || [];function gtag(){dataLayer.push(arguments);}' );

foreach ( $this->commands as $command ) {
wp_add_inline_script( self::HANDLE, $this->get_gtag_call_for_command( $command ), $command['position'] );
}

wp_add_inline_script( self::HANDLE, 'gtag("js", new Date());' );
wp_add_inline_script( self::HANDLE, 'gtag("set", "developer_id.dZTNiMT", true);' ); // Site Kit developer ID.

foreach ( $this->tags as $tag ) {
wp_add_inline_script( self::HANDLE, $this->get_gtag_call_for_tag( $tag ) );
}

foreach ( $this->commands as $command ) {
wp_add_inline_script( self::HANDLE, $this->get_gtag_call_for_command( $command ), $command['position'] );
}

$filter_google_gtagjs = function ( $tag, $handle ) {
if ( self::HANDLE !== $handle ) {
return $tag;
Expand Down Expand Up @@ -188,4 +187,22 @@ function( $arg ) {

return sprintf( 'gtag(%s);', implode( ',', $gtag_args ) );
}

/**
* Returns the gtag source URL.
*
* @since n.e.x.t
*
* @return string|false The gtag source URL. False if no tags are added.
*/
public function get_gtag_src() {
if ( empty( $this->tags ) ) {
return false;
}

// Load the GTag scripts using the first tag ID - it doesn't matter which is used,
// all registered tags will be set up with a config command regardless
// of which is used to load the source.
return 'https://www.googletagmanager.com/gtag/js?id=' . rawurlencode( $this->tags[0]['tag_id'] );
}
}
79 changes: 23 additions & 56 deletions includes/Modules/Analytics_4/Web_Tag.php
Expand Up @@ -11,6 +11,7 @@
namespace Google\Site_Kit\Modules\Analytics_4;

use Google\Site_Kit\Core\Modules\Tags\Module_Web_Tag;
use Google\Site_Kit\Core\Tags\GTag;
use Google\Site_Kit\Core\Tags\Tag_With_DNS_Prefetch_Trait;
use Google\Site_Kit\Core\Util\Method_Proxy_Trait;

Expand Down Expand Up @@ -101,13 +102,8 @@ protected function get_tag_blocked_on_consent_deprecated_args() {
* @since 1.31.0
*/
public function register() {
add_action( 'wp_enqueue_scripts', $this->get_method_proxy( 'enqueue_gtag_script' ), 20 );
add_filter(
'wp_resource_hints',
$this->get_dns_prefetch_hints_callback( '//www.googletagmanager.com' ),
10,
2
);
add_action( 'googlesitekit_setup_gtag', $this->get_method_proxy( 'setup_gtag' ) );

$this->do_init_tag_action();
}

Expand All @@ -121,18 +117,15 @@ protected function render() {
}

/**
* Enqueues gtag script.
* Configures gtag script.
*
* @since 1.24.0
* @since n.e.x.t Renamed and refactored to use new GTag infrastructure.
*
* @param GTag $gtag GTag instance.
*/
protected function enqueue_gtag_script() {
protected function setup_gtag( GTag $gtag ) {
$gtag_opt = $this->get_tag_config();
$gtag_src = 'https://www.googletagmanager.com/gtag/js?id=' . rawurlencode( $this->tag_id );

// phpcs:ignore WordPress.WP.EnqueuedResourceParameters.MissingVersion
wp_enqueue_script( 'google_gtagjs', $gtag_src, false, null, false );
wp_script_add_data( 'google_gtagjs', 'script_execution', 'async' );
wp_add_inline_script( 'google_gtagjs', 'window.dataLayer = window.dataLayer || [];function gtag(){dataLayer.push(arguments);}' );

/**
* Filters the gtag configuration options for the Analytics snippet.
Expand All @@ -148,66 +141,40 @@ protected function enqueue_gtag_script() {
$gtag_opt = apply_filters( 'googlesitekit_gtag_opt', $gtag_opt );

if ( ! empty( $gtag_opt['linker'] ) ) {
$linker = wp_json_encode( $gtag_opt['linker'] );
$linker = sprintf( "gtag('set', 'linker', %s );", $linker );
wp_add_inline_script( 'google_gtagjs', $linker );
}
$gtag->add_command( 'set', array( 'linker', $gtag_opt['linker'] ) );

unset( $gtag_opt['linker'] );
unset( $gtag_opt['linker'] );
}

wp_add_inline_script( 'google_gtagjs', 'gtag("js", new Date());' );
wp_add_inline_script( 'google_gtagjs', 'gtag("set", "developer_id.dZTNiMT", true);' ); // Site Kit developer ID.
$gtag->add_tag( $this->tag_id, $gtag_opt );

$this->add_inline_config( $this->tag_id, $gtag_opt );
$this->add_inline_ads_conversion_id_config();
// TODO: Lift this out to the Ads module when it's ready.
if ( $this->ads_conversion_id ) {
$gtag->add_tag( $this->ads_conversion_id );
}

$filter_google_gtagjs = function ( $tag, $handle ) use ( $gtag_src ) {
if ( 'google_gtagjs' !== $handle ) {
$filter_google_gtagjs = function ( $tag, $handle ) use ( $gtag ) {
if ( GTag::HANDLE !== $handle ) {
return $tag;
}

$snippet_comment_begin = sprintf( "\n<!-- %s -->\n", esc_html__( 'Google Analytics snippet added by Site Kit', 'google-site-kit' ) );
$snippet_comment_end = sprintf( "\n<!-- %s -->\n", esc_html__( 'End Google Analytics snippet added by Site Kit', 'google-site-kit' ) );
// Retain this comment for detection of Site Kit placed tag.
$snippet_comment = sprintf( "\n<!-- %s -->\n", esc_html__( 'Google Analytics snippet added by Site Kit', 'google-site-kit' ) );

$block_on_consent_attrs = $this->get_tag_blocked_on_consent_attribute();

if ( $block_on_consent_attrs ) {
$gtag_src = $gtag->get_gtag_src();

$tag = $this->add_legacy_block_on_consent_attributes( $tag, $gtag_src, $block_on_consent_attrs );
}

return $snippet_comment_begin . $tag . $snippet_comment_end;
return $snippet_comment . $tag;
};

add_filter( 'script_loader_tag', $filter_google_gtagjs, 10, 2 );
}

/**
* Adds an inline script to configure ads conversion tracking.
*
* @since 1.32.0
*/
protected function add_inline_ads_conversion_id_config() {
if ( $this->ads_conversion_id ) {
$this->add_inline_config( $this->ads_conversion_id, array() );
}
}

/**
* Adds an inline script to configure provided tag including configuration options.
*
* @since 1.113.0
*
* @param string $tag_id The tag ID to add config for.
* @param array $gtag_opt The gtag configuration.
*/
protected function add_inline_config( $tag_id, $gtag_opt ) {
$config = ! empty( $gtag_opt )
? sprintf( 'gtag("config", "%s", %s);', esc_js( $tag_id ), wp_json_encode( $gtag_opt ) )
: sprintf( 'gtag("config", "%s");', esc_js( $tag_id ) );

wp_add_inline_script( 'google_gtagjs', $config );
}

/**
* Gets the tag config as used in the gtag data vars.
*
Expand Down
27 changes: 22 additions & 5 deletions tests/phpunit/integration/Core/Tags/GTagTest.php
Expand Up @@ -71,8 +71,8 @@ public function test_gtag_script_contains_gtag_call() {
$script = $scripts->registered[ GTag::HANDLE ];

// Assert the array of inline script data contains the necessary gtag config line.
// Should be in index 4, the first registered gtag.
$this->assertEquals( 'gtag("config", "' . static::TEST_TAG_ID_1 . '");', $script->extra['after'][4] );
// Should be in index 5, the first registered gtag.
$this->assertEquals( 'gtag("config", "' . static::TEST_TAG_ID_1 . '");', $script->extra['after'][5] );
}

public function test_gtag_script_commands() {
Expand All @@ -83,7 +83,7 @@ public function test_gtag_script_commands() {
$this->assertEquals( sprintf( 'gtag(%s");', '"' . static::TEST_COMMAND_1 . '","' . implode( '","', static::TEST_COMMAND_1_PARAMS ) ), $script->extra['before'][1] );

// Test commands in the after position.
$this->assertEquals( sprintf( 'gtag(%s);', '"' . static::TEST_COMMAND_2 . '",' . json_encode( static::TEST_COMMAND_2_PARAMS[0] ) ), $script->extra['after'][5] );
$this->assertEquals( sprintf( 'gtag(%s);', '"' . static::TEST_COMMAND_2 . '",' . json_encode( static::TEST_COMMAND_2_PARAMS[0] ) ), $script->extra['after'][2] );
}

public function test_gtag_with_tag_config() {
Expand All @@ -99,8 +99,25 @@ public function test_gtag_with_tag_config() {
$script = $scripts->registered[ GTag::HANDLE ];

// Assert the array of inline script data contains the necessary gtag entry for the second script.
// Should be in index 5, immediately after the first registered gtag.
$this->assertEquals( 'gtag("config", "' . static::TEST_TAG_ID_2 . '", ' . json_encode( self::TEST_TAG_ID_2_CONFIG ) . ');', $script->extra['after'][5] );
// Should be in index 6, immediately after the first registered gtag.
$this->assertEquals( 'gtag("config", "' . static::TEST_TAG_ID_2 . '", ' . json_encode( self::TEST_TAG_ID_2_CONFIG ) . ');', $script->extra['after'][6] );
}

public function test_get_gtag_src() {
$this->assertEquals( 'https://www.googletagmanager.com/gtag/js?id=' . static::TEST_TAG_ID_1, $this->gtag->get_gtag_src() );

// Reset the GTag instance.
$this->gtag = new GTag();
$this->gtag->register();

// Verify that this returns `false` when no tags are added.
$this->assertFalse( $this->gtag->get_gtag_src() );

// Add a different tag ID.
$this->gtag->add_tag( static::TEST_TAG_ID_2 );

// Verify that this returns the correct URL for the different tag ID.
$this->assertEquals( 'https://www.googletagmanager.com/gtag/js?id=' . static::TEST_TAG_ID_2, $this->gtag->get_gtag_src() );
}

}
20 changes: 13 additions & 7 deletions tests/phpunit/integration/Modules/Analytics_4Test.php
Expand Up @@ -26,6 +26,7 @@
use Google\Site_Kit\Core\Storage\Options;
use Google\Site_Kit\Core\Storage\Transients;
use Google\Site_Kit\Core\Storage\User_Options;
use Google\Site_Kit\Core\Tags\GTag;
use Google\Site_Kit\Modules\AdSense\Settings as AdSense_Settings;
use Google\Site_Kit\Modules\Analytics_4;
use Google\Site_Kit\Modules\Analytics_4\Custom_Dimensions_Data_Available;
Expand Down Expand Up @@ -136,6 +137,8 @@ public function set_up() {
$this->authentication = new Authentication( $this->context, $this->options, $this->user_options );
$this->analytics = new Analytics_4( $this->context, $this->options, $this->user_options, $this->authentication );
wp_set_current_user( $this->user->ID );
remove_all_actions( 'wp_enqueue_scripts' );
( new GTag() )->register();
}

public function test_register() {
Expand Down Expand Up @@ -2792,6 +2795,9 @@ public function test_tracking_opt_out_snippet( $settings, $logged_in, $is_tracki
// Remove irrelevant script from throwing errors in CI from readfile().
remove_action( 'wp_head', 'print_emoji_detection_script', 7 );

// Prevent test from failing in CI with deprecation notice.
remove_action( 'wp_print_styles', 'print_emoji_styles' );

// Set the current user (can be 0 for no user)
$role = $is_content_creator ? 'administrator' : 'subscriber';
$user = $logged_in ?
Expand All @@ -2803,6 +2809,7 @@ public function test_tracking_opt_out_snippet( $settings, $logged_in, $is_tracki
$analytics->get_settings()->set( $settings );

remove_all_actions( 'template_redirect' );
remove_all_actions( 'googlesitekit_setup_gtag' );
$analytics->register();
do_action( 'template_redirect' );

Expand Down Expand Up @@ -3501,10 +3508,10 @@ public function test_register_template_redirect_non_amp() {
remove_all_actions( 'template_redirect' );
$analytics->register();

remove_all_actions( 'wp_enqueue_scripts' );
remove_all_actions( 'googlesitekit_setup_gtag' );

do_action( 'template_redirect' );
$this->assertFalse( has_action( 'wp_enqueue_scripts' ) );
$this->assertFalse( has_action( 'googlesitekit_setup_gtag' ) );

$analytics->get_settings()->merge(
array(
Expand All @@ -3516,19 +3523,19 @@ public function test_register_template_redirect_non_amp() {
);

do_action( 'template_redirect' );
$this->assertTrue( has_action( 'wp_enqueue_scripts' ) );
$this->assertTrue( has_action( 'googlesitekit_setup_gtag' ) );

// Tag not hooked when blocked.
remove_all_actions( 'wp_enqueue_scripts' );
remove_all_actions( 'googlesitekit_setup_gtag' );
add_filter( 'googlesitekit_analytics-4_tag_blocked', '__return_true' );
do_action( 'template_redirect' );
$this->assertFalse( has_action( 'wp_enqueue_scripts' ) );
$this->assertFalse( has_action( 'googlesitekit_setup_gtag' ) );

// Tag hooked when only AMP blocked.
add_filter( 'googlesitekit_analytics-4_tag_blocked', '__return_false' );
add_filter( 'googlesitekit_analytics-4_tag_amp_blocked', '__return_true' );
do_action( 'template_redirect' );
$this->assertTrue( has_action( 'wp_enqueue_scripts' ) );
$this->assertTrue( has_action( 'googlesitekit_setup_gtag' ) );
}

/**
Expand All @@ -3555,7 +3562,6 @@ public function test_block_on_consent_non_amp( $test_parameters ) {
wp_scripts()->queue = array();
wp_scripts()->done = array();
remove_all_actions( 'template_redirect' );
remove_all_actions( 'wp_enqueue_scripts' );
$analytics->register();

// Hook `wp_print_head_scripts` on placeholder action for capturing.
Expand Down

0 comments on commit e0232dd

Please sign in to comment.