Skip to content

Commit 2a9a1a3

Browse files
committed
Merge branch 'develop' into fix/1140-duplicate-dashboard-html
2 parents ea5c611 + bcfad53 commit 2a9a1a3

File tree

9 files changed

+334
-174
lines changed

9 files changed

+334
-174
lines changed

assets/js/modules/tagmanager/setup.js

Lines changed: 186 additions & 86 deletions
Large diffs are not rendered by default.
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
/**
2+
* Gets an object of utility functions for filtering the given list of containers.
3+
*
4+
* @param {Array} containers Containers to filter.
5+
* @return {Object} Object with keys mapping to utility functions to operate on given containers.
6+
*/
7+
export default function getContainers( containers ) {
8+
return {
9+
/**
10+
* Gets containers that include the given usage context.
11+
* @param {string} context The context to filter by.
12+
* @return {Array} Containers with the given usage context.
13+
*/
14+
byContext: ( context ) => containers.filter( ( c ) => c.usageContext.includes( context ) ),
15+
};
16+
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
export { default as getContainers } from './get-containers';
12
export { default as isValidAccountID } from './is-valid-account-id';
23
export { default as isValidContainerID } from './is-valid-container-id';
34
export { default as tagMatchers } from './tag-matchers';

includes/Core/Authentication/Clients/OAuth_Client.php

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -264,17 +264,15 @@ private function setup_client() {
264264

265265
// This is called when the client refreshes the access token on-the-fly.
266266
$client->setTokenCallback(
267-
function( $cache_key, $access_token ) {
267+
function( $cache_key, $access_token ) use ( $client ) {
268268
$expires_in = HOUR_IN_SECONDS; // Sane default, Google OAuth tokens are typically valid for an hour.
269269
$created = 0; // This will be replaced with the current timestamp when saving.
270270

271271
// Try looking up the real values if possible.
272-
if ( isset( $client ) ) {
273-
$token = $client->getAccessToken();
274-
if ( isset( $token['access_token'], $token['expires_in'], $token['created'] ) && $access_token === $token['access_token'] ) {
275-
$expires_in = $token['expires_in'];
276-
$created = $token['created'];
277-
}
272+
$token = $client->getAccessToken();
273+
if ( isset( $token['access_token'], $token['expires_in'], $token['created'] ) && $access_token === $token['access_token'] ) {
274+
$expires_in = $token['expires_in'];
275+
$created = $token['created'];
278276
}
279277

280278
$this->set_access_token( $access_token, $expires_in, $created );

includes/Core/Modules/Module.php

Lines changed: 1 addition & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -706,27 +706,12 @@ private function parse_info( array $info ) {
706706
* @param string $datapoint Datapoint originally requested.
707707
* @return WP_Error WordPress error object.
708708
*/
709-
private function exception_to_error( Exception $e, $datapoint ) {
709+
protected function exception_to_error( Exception $e, $datapoint ) {
710710
$code = $e->getCode();
711711
if ( empty( $code ) ) {
712712
$code = 'unknown';
713713
}
714714

715-
// This is not great to have here, but is completely internal so it can be improved/removed at any time.
716-
if ( $this instanceof \Google\Site_Kit\Modules\AdSense ) {
717-
switch ( $datapoint ) {
718-
case 'accounts':
719-
case 'alerts':
720-
case 'clients':
721-
case 'urlchannels':
722-
$errors = json_decode( $e->getMessage() );
723-
if ( $errors ) {
724-
return new \WP_Error( $e->getCode(), $errors, array( 'status' => 500 ) );
725-
}
726-
break;
727-
}
728-
}
729-
730715
$reason = '';
731716

732717
if ( $e instanceof Google_Service_Exception ) {

includes/Modules/AdSense.php

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010

1111
namespace Google\Site_Kit\Modules;
1212

13+
use Exception;
1314
use Google\Site_Kit\Core\Modules\Module;
1415
use Google\Site_Kit\Core\Modules\Module_Settings;
1516
use Google\Site_Kit\Core\Modules\Module_With_Screen;
@@ -747,4 +748,24 @@ protected function setup_services( Google_Site_Kit_Client $client ) {
747748
protected function setup_settings() {
748749
return new Settings( $this->options );
749750
}
751+
752+
/**
753+
* Transforms an exception into a WP_Error object.
754+
*
755+
* @since n.e.x.t
756+
*
757+
* @param Exception $e Exception object.
758+
* @param string $datapoint Datapoint originally requested.
759+
* @return WP_Error WordPress error object.
760+
*/
761+
protected function exception_to_error( Exception $e, $datapoint ) {
762+
if ( in_array( $datapoint, array( 'accounts', 'alerts', 'clients', 'urlchannels' ), true ) ) {
763+
$errors = json_decode( $e->getMessage() );
764+
if ( $errors ) {
765+
return new WP_Error( $e->getCode(), $errors, array( 'status' => 500 ) );
766+
}
767+
}
768+
769+
return parent::exception_to_error( $e, $datapoint );
770+
}
750771
}

includes/Modules/Tag_Manager.php

Lines changed: 44 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -493,40 +493,40 @@ protected function create_data_request( Data_Request $data ) {
493493
}
494494
return $this->get_tagmanager_service()->accounts_containers->listAccountsContainers( "accounts/{$data['accountID']}" );
495495
case 'POST:settings':
496-
if ( ! isset( $data['accountID'] ) ) {
497-
/* translators: %s: Missing parameter name */
498-
return new WP_Error( 'missing_required_param', sprintf( __( 'Request parameter is empty: %s.', 'google-site-kit' ), 'accountID' ), array( 'status' => 400 ) );
496+
$required_params = array( 'accountID', 'usageContext' );
497+
498+
if ( self::USAGE_CONTEXT_WEB === $data['usageContext'] ) { // No AMP.
499+
$required_params[] = $this->context_map[ self::USAGE_CONTEXT_WEB ];
500+
} elseif ( self::USAGE_CONTEXT_AMP === $data['usageContext'] ) { // Primary AMP.
501+
$required_params[] = $this->context_map[ self::USAGE_CONTEXT_AMP ];
502+
} else { // Secondary AMP.
503+
array_push( $required_params, ...array_values( $this->context_map ) );
499504
}
500505

501-
$usage_context = $data['usageContext'] ?: self::USAGE_CONTEXT_WEB;
502-
503-
if ( self::USAGE_CONTEXT_WEB === $usage_context && ! isset( $data['containerID'] ) ) {
504-
/* translators: %s: Missing parameter name */
505-
return new WP_Error( 'missing_required_param', sprintf( __( 'Request parameter is empty: %s.', 'google-site-kit' ), 'containerID' ), array( 'status' => 400 ) );
506-
}
507-
if ( self::USAGE_CONTEXT_AMP === $usage_context && ! isset( $data['ampContainerID'] ) ) {
508-
/* translators: %s: Missing parameter name */
509-
return new WP_Error( 'missing_required_param', sprintf( __( 'Request parameter is empty: %s.', 'google-site-kit' ), 'ampContainerID' ), array( 'status' => 400 ) );
506+
foreach ( $required_params as $required_param ) {
507+
if ( ! isset( $data[ $required_param ] ) ) {
508+
/* translators: %s: Missing parameter name */
509+
return new WP_Error( 'missing_required_param', sprintf( __( 'Request parameter is empty: %s.', 'google-site-kit' ), $required_param ), array( 'status' => 400 ) );
510+
}
510511
}
511512

512-
return function() use ( $data, $usage_context ) {
513-
$option = $data->data;
514-
$container_key = $this->context_map[ $usage_context ];
515-
$container_id = $data[ $container_key ];
516-
517-
if ( 'container_create' === $container_id ) {
518-
$create_container_response = $this->create_container( $data['accountID'], $usage_context );
513+
return function() use ( $data ) {
514+
$option = $data->data;
519515

520-
if ( is_wp_error( $create_container_response ) ) {
521-
return $create_container_response;
516+
try {
517+
if ( 'container_create' === $data['containerID'] ) {
518+
$option['containerID'] = $this->create_container( $data['accountID'], self::USAGE_CONTEXT_WEB );
522519
}
523-
524-
$option[ $container_key ] = $create_container_response;
520+
if ( 'container_create' === $data['ampContainerID'] ) {
521+
$option['ampContainerID'] = $this->create_container( $data['accountID'], self::USAGE_CONTEXT_AMP );
522+
}
523+
} catch ( Exception $e ) {
524+
return $this->exception_to_error( $e, $data->datapoint );
525525
}
526526

527527
$this->get_settings()->merge( $option );
528528

529-
return $option;
529+
return $this->get_settings()->get();
530530
};
531531
case 'GET:tag-permission':
532532
return function () use ( $data ) {
@@ -566,38 +566,37 @@ protected function create_data_request( Data_Request $data ) {
566566
* Creates GTM Container.
567567
*
568568
* @since 1.0.0
569-
* @param string $account_id The account ID.
569+
* @param string $account_id The account ID.
570570
* @param string|array $usage_context The container usage context(s).
571571
*
572-
* @return mixed Container ID on success, or WP_Error on failure.
572+
* @return string Container public ID.
573+
* @throws Exception Throws an exception if raised during container creation.
573574
*/
574575
protected function create_container( $account_id, $usage_context = self::USAGE_CONTEXT_WEB ) {
575576
$restore_defer = $this->with_client_defer( false );
576577

577578
// Use site name for container, fallback to domain of reference URL.
578579
$container_name = get_bloginfo( 'name' ) ?: wp_parse_url( $this->context->get_reference_site_url(), PHP_URL_HOST );
580+
// Prevent naming conflict (Tag Manager does not allow more than one with same name).
581+
if ( self::USAGE_CONTEXT_AMP === $usage_context ) {
582+
$container_name .= ' AMP';
583+
}
579584
$container_name = self::sanitize_container_name( $container_name );
580585

581586
$container = new Google_Service_TagManager_Container();
582587
$container->setName( $container_name );
583588
$container->setUsageContext( (array) $usage_context );
584589

585590
try {
586-
$container = $this->get_tagmanager_service()->accounts_containers->create( "accounts/{$account_id}", $container );
587-
} catch ( Google_Service_Exception $e ) {
588-
$restore_defer();
589-
$message = $e->getErrors();
590-
if ( isset( $message[0]['message'] ) ) {
591-
$message = $message[0]['message'];
592-
}
593-
return new WP_Error( $e->getCode(), $message );
594-
} catch ( Exception $e ) {
591+
$new_container = $this->get_tagmanager_service()->accounts_containers->create( "accounts/{$account_id}", $container );
592+
} catch ( Exception $exception ) {
595593
$restore_defer();
596-
return new WP_Error( $e->getCode(), $e->getMessage() );
594+
throw $exception;
597595
}
598596

599597
$restore_defer();
600-
return $container->getPublicId();
598+
599+
return $new_container->getPublicId();
601600
}
602601

603602
/**
@@ -646,27 +645,15 @@ protected function parse_data_response( Data_Request $data, $response ) {
646645
return array_merge( $response, compact( 'containers' ) );
647646
case 'GET:containers':
648647
/* @var Google_Service_TagManager_ListContainersResponse $response Response object. */
649-
$account_id = $data['accountID'];
650648
$usage_context = $data['usageContext'] ?: self::USAGE_CONTEXT_WEB;
651649
/* @var Google_Service_TagManager_Container[] $containers Filtered containers. */
652650
$containers = array_filter(
653651
(array) $response->getContainer(),
654652
function ( Google_Service_TagManager_Container $container ) use ( $usage_context ) {
655-
return in_array( $usage_context, $container->getUsageContext(), true );
653+
return array_intersect( (array) $usage_context, $container->getUsageContext() );
656654
}
657655
);
658656

659-
if ( ! $containers && $account_id ) {
660-
// If no containers, attempt to create a new container.
661-
$new_container = $this->create_container( $account_id, $usage_context );
662-
663-
if ( is_wp_error( $new_container ) ) {
664-
return $new_container;
665-
}
666-
667-
return $this->get_data( 'containers', array( 'accountID' => $account_id ) );
668-
}
669-
670657
return array_values( $containers );
671658
}
672659

@@ -693,7 +680,13 @@ function ( Google_Service_TagManager_Container $container ) use ( $usage_context
693680
private function get_account_for_container( $container_id, $accounts ) {
694681
foreach ( (array) $accounts as $account ) {
695682
/* @var Google_Service_TagManager_Account $account Tag manager account */
696-
$containers = $this->get_data( 'containers', array( 'accountID' => $account->getAccountId() ) );
683+
$containers = $this->get_data(
684+
'containers',
685+
array(
686+
'accountID' => $account->getAccountId(),
687+
'usageContext' => array_keys( $this->context_map ),
688+
)
689+
);
697690

698691
if ( is_wp_error( $containers ) ) {
699692
break;

tests/e2e/plugins/module-setup-tagmanager.php

Lines changed: 46 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -19,11 +19,15 @@
1919
const ACCOUNT_ID_A = '100';
2020
const ACCOUNT_ID_B = '101';
2121

22-
const PUBLIC_ID_X = 'GTM-ABCXYZ';
23-
const PUBLIC_ID_Y = 'GTM-BCDWXY';
22+
const PUBLIC_ID_X = 'GTM-ABCXYZ';
23+
const PUBLIC_ID_Y = 'GTM-BCDWXY';
24+
const PUBLIC_ID_AX = 'GTM-AMPXYZ';
25+
const PUBLIC_ID_AY = 'GTM-AMPWXY';
2426

25-
const CONTAINER_ID_X = '200';
26-
const CONTAINER_ID_Y = '201';
27+
const CONTAINER_ID_X = '200';
28+
const CONTAINER_ID_Y = '201';
29+
const CONTAINER_ID_AX = '210';
30+
const CONTAINER_ID_AY = '211';
2731

2832
function filter_by_account_id( $items, $account_id ) {
2933
return array_values(
@@ -36,6 +40,17 @@ function ( $item ) use ( $account_id ) {
3640
);
3741
}
3842

43+
function filter_by_context( $items, $context ) {
44+
return array_values(
45+
array_filter(
46+
$items,
47+
function ( $item ) use ( $context ) {
48+
return (bool) array_intersect( (array) $context, $item['usageContext'] );
49+
}
50+
)
51+
);
52+
}
53+
3954
add_action(
4055
'rest_api_init',
4156
function () {
@@ -52,16 +67,32 @@ function () {
5267
);
5368
$containers = array(
5469
array(
55-
'accountId' => ACCOUNT_ID_A,
56-
'publicId' => PUBLIC_ID_X,
57-
'containerId' => CONTAINER_ID_X,
58-
'name' => 'Test Container X',
70+
'accountId' => ACCOUNT_ID_A,
71+
'publicId' => PUBLIC_ID_X,
72+
'containerId' => CONTAINER_ID_X,
73+
'name' => 'Test Container X',
74+
'usageContext' => array( 'web' ),
75+
),
76+
array(
77+
'accountId' => ACCOUNT_ID_B,
78+
'publicId' => PUBLIC_ID_Y,
79+
'containerId' => CONTAINER_ID_Y,
80+
'name' => 'Test Container Y',
81+
'usageContext' => array( 'web' ),
5982
),
6083
array(
61-
'accountId' => ACCOUNT_ID_B,
62-
'publicId' => PUBLIC_ID_Y,
63-
'containerId' => CONTAINER_ID_Y,
64-
'name' => 'Test Container Y',
84+
'accountId' => ACCOUNT_ID_A,
85+
'publicId' => PUBLIC_ID_AX,
86+
'containerId' => CONTAINER_ID_AX,
87+
'name' => 'Test AMP Container AX',
88+
'usageContext' => array( 'amp' ),
89+
),
90+
array(
91+
'accountId' => ACCOUNT_ID_B,
92+
'publicId' => PUBLIC_ID_AY,
93+
'containerId' => CONTAINER_ID_AY,
94+
'name' => 'Test AMP Container AY',
95+
'usageContext' => array( 'amp' ),
6596
),
6697
);
6798

@@ -84,6 +115,7 @@ function () {
84115
'methods' => 'GET',
85116
'callback' => function ( $request ) use ( $accounts, $containers ) {
86117
$account_id = $request['accountID'] ?: $accounts[0]['accountId'];
118+
$containers = filter_by_context( $containers, $request['usageContext'] );
87119

88120
return array(
89121
'accounts' => $accounts,
@@ -100,6 +132,8 @@ function () {
100132
array(
101133
'methods' => 'GET',
102134
'callback' => function ( $request ) use ( $containers ) {
135+
$containers = filter_by_context( $containers, $request['usageContext'] );
136+
103137
return filter_by_account_id( $containers, $request['accountID'] );
104138
},
105139
),

tests/e2e/specs/modules/tagmanager/setup.test.js

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,10 @@ describe( 'Tag Manager module setup', () => {
110110
await activatePlugin( 'e2e-tests-module-setup-tagmanager-api-mock' );
111111
await proceedToTagManagerSetup();
112112

113+
// Ensure only web container select is shown.
114+
await expect( page ).toMatchElement( '.googlesitekit-tagmanager__select-container--web' );
115+
await expect( page ).not.toMatchElement( '.googlesitekit-tagmanager__select-container--amp' );
116+
113117
// Ensure account and container are selected by default.
114118
await expect( page ).toMatchElement( '.googlesitekit-tagmanager__select-account .mdc-select__selected-text', { text: /test account a/i } );
115119
await expect( page ).toMatchElement( '.googlesitekit-tagmanager__select-container .mdc-select__selected-text', { text: /test container x/i } );
@@ -121,9 +125,17 @@ describe( 'Tag Manager module setup', () => {
121125
expect( page ).toClick( '.mdc-menu-surface--open .mdc-list-item', { text: /test account b/i } ),
122126
] );
123127

124-
// Ensure proper account and container are now selected.
128+
// Ensure account is selected.
125129
await expect( page ).toMatchElement( '.googlesitekit-tagmanager__select-account .mdc-select__selected-text', { text: /test account b/i } );
126-
await expect( page ).toMatchElement( '.googlesitekit-tagmanager__select-container .mdc-select__selected-text', { text: /test container y/i } );
130+
131+
// Select a container.
132+
await expect( page ).toClick( '.googlesitekit-tagmanager__select-container' );
133+
// Ensure no AMP containers are shown as options.
134+
// expect(...).not.toMatchElement with textContent matching does not work as expected.
135+
await expect(
136+
await page.$$eval( '.mdc-menu-surface--open .mdc-list-item', ( nodes ) => !! nodes.find( ( e ) => e.textContent.match( /test amp container/i ) ) )
137+
).toStrictEqual( false );
138+
await expect( page ).toClick( '.mdc-menu-surface--open .mdc-list-item', { text: /test container y/i } );
127139

128140
await page.waitFor( 1000 );
129141
await expect( page ).toClick( 'button', { text: /confirm \& continue/i } );

0 commit comments

Comments
 (0)