Skip to content

Commit 7444fc8

Browse files
authored
Merge pull request #3230 from woocommerce/fix/GOOWOO-321
[GOOWOO-321] Fix error editing asset group when Brand Guidelines is enabled
2 parents b8a7da7 + 6fb546b commit 7444fc8

File tree

12 files changed

+643
-38
lines changed

12 files changed

+643
-38
lines changed

src/API/Google/AdsAssetGroup.php

Lines changed: 76 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,13 @@ class AdsAssetGroup implements OptionsAwareInterface, ContainerAwareInterface {
6868
*/
6969
protected $asset_group_asset;
7070

71+
/**
72+
* The AdsCampaign class.
73+
*
74+
* @var AdsCampaign
75+
*/
76+
protected $campaign;
77+
7178
/**
7279
* List of asset group resource names.
7380
*
@@ -80,10 +87,12 @@ class AdsAssetGroup implements OptionsAwareInterface, ContainerAwareInterface {
8087
*
8188
* @param GoogleAdsClient $client
8289
* @param AdsAssetGroupAsset $asset_group_asset
90+
* @param AdsCampaign $campaign
8391
*/
84-
public function __construct( GoogleAdsClient $client, AdsAssetGroupAsset $asset_group_asset ) {
92+
public function __construct( GoogleAdsClient $client, AdsAssetGroupAsset $asset_group_asset, AdsCampaign $campaign ) {
8593
$this->client = $client;
8694
$this->asset_group_asset = $asset_group_asset;
95+
$this->campaign = $campaign;
8796
}
8897

8998
/**
@@ -345,11 +354,56 @@ protected function get_assets( array $asset_groups ): array {
345354

346355
foreach ( $asset_group_ids as $asset_group_id ) {
347356
$asset_groups[ $asset_group_id ]['assets'] = $assets[ $asset_group_id ] ?? (object) [];
357+
358+
// When Brand Guidelines is enabled, business name and logo are at campaign level; merge them for display.
359+
$campaign_info = $this->get_campaign_info_by_asset_group_id( $asset_group_id );
360+
if ( ! empty( $campaign_info['brand_guidelines_enabled'] ) && ! empty( $campaign_info['id'] ) ) {
361+
$campaign_brand = $this->campaign->get_campaign_brand_assets_for_display( (int) $campaign_info['id'] );
362+
$existing = $asset_groups[ $asset_group_id ]['assets'];
363+
$existing = is_object( $existing ) ? (array) $existing : $existing;
364+
if ( $campaign_brand['business_name'] !== null ) {
365+
$existing['business_name'] = $campaign_brand['business_name'];
366+
}
367+
if ( ! empty( $campaign_brand['logo'] ) ) {
368+
$existing['logo'] = $campaign_brand['logo'];
369+
}
370+
$asset_groups[ $asset_group_id ]['assets'] = $existing;
371+
}
348372
}
349373

350374
return $asset_groups;
351375
}
352376

377+
/**
378+
* Get campaign information from asset group ID.
379+
*
380+
* @param int $asset_group_id The asset group ID.
381+
*
382+
* @return array Campaign information with 'id' and 'brand_guidelines_enabled' keys.
383+
*/
384+
protected function get_campaign_info_by_asset_group_id( int $asset_group_id ): array {
385+
try {
386+
$results = ( new AdsAssetGroupQuery() )
387+
->set_client( $this->client, $this->options->get_ads_id() )
388+
->add_columns( [ 'campaign.id', 'campaign.brand_guidelines_enabled' ] )
389+
->where( 'asset_group.id', $asset_group_id, '=' )
390+
->get_results();
391+
392+
foreach ( $results->iterateAllElements() as $row ) {
393+
$campaign = $row->getCampaign();
394+
return [
395+
'id' => $campaign->getId(),
396+
'brand_guidelines_enabled' => $campaign->getBrandGuidelinesEnabled(),
397+
];
398+
}
399+
400+
return [];
401+
} catch ( ApiException $e ) {
402+
do_action( 'woocommerce_gla_ads_client_exception', $e, __METHOD__ );
403+
return [];
404+
}
405+
}
406+
353407
/**
354408
* Edit an asset group.
355409
*
@@ -362,7 +416,17 @@ protected function get_assets( array $asset_groups ): array {
362416
*/
363417
public function edit_asset_group( int $asset_group_id, array $data, array $assets = [] ): int {
364418
try {
365-
$operations = $this->asset_group_asset->edit_operations( $asset_group_id, $assets );
419+
$is_brand_guidelines_enabled = false;
420+
// Check if Brand Guidelines is enabled for this asset group's campaign.
421+
$campaign_info = $this->get_campaign_info_by_asset_group_id( $asset_group_id );
422+
if ( ! empty( $campaign_info['brand_guidelines_enabled'] ) && ! empty( $campaign_info['id'] ) ) {
423+
$is_brand_guidelines_enabled = true;
424+
}
425+
426+
$edit_result = $this->asset_group_asset->edit_operations( $asset_group_id, $assets, $is_brand_guidelines_enabled );
427+
$operations = $edit_result['operations'];
428+
$assets_for_creation = $edit_result['assets_for_creation'] ?? [];
429+
$created_asset_resource_names = $edit_result['created_asset_resource_names'] ?? [];
366430

367431
// PMax only supports one final URL but it is required to be an array.
368432
if ( ! empty( $data['final_url'] ) ) {
@@ -375,6 +439,16 @@ public function edit_asset_group( int $asset_group_id, array $data, array $asset
375439
$operations = [ $this->edit_operation( $asset_group_id, $data ), ...$operations ];
376440
}
377441

442+
if ( ! empty( $campaign_info['brand_guidelines_enabled'] ) && ! empty( $campaign_info['id'] ) ) {
443+
$brand_operations = $this->campaign->get_brand_asset_link_operations(
444+
$campaign_info['id'],
445+
$assets,
446+
$assets_for_creation,
447+
$created_asset_resource_names
448+
);
449+
$operations = array_merge( $brand_operations, $operations );
450+
}
451+
378452
if ( ! empty( $operations ) ) {
379453
$this->mutate( $operations );
380454
}

src/API/Google/AdsAssetGroupAsset.php

Lines changed: 43 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -308,20 +308,30 @@ function ( $asset ) use ( $asset_group_id ) {
308308
/**
309309
* Edit assets group assets.
310310
*
311-
* @param int $asset_group_id The asset group id.
312-
* @param array $assets The assets to create.
311+
* When brand guidelines is enabled, business name and logo must NOT be linked at asset group level
312+
* (they must be CampaignAssets only, per Google Ads API requirements). This method skips creating
313+
* AssetGroupAsset operations for brand assets and returns the created asset data so the caller can
314+
* link them at campaign level instead.
313315
*
314-
* @return array The asset group asset operations.
316+
* @param int $asset_group_id The asset group id.
317+
* @param array $assets The assets to create.
318+
* @param bool $is_brand_guidelines_enabled Whether brand guidelines is enabled for the asset group's campaign.
319+
*
320+
* @return array{operations: MutateOperation[], assets_for_creation: array, created_asset_resource_names: array} Asset group operations and creation data for campaign-level linking.
315321
* @throws Exception If the asset type is not supported.
316322
*/
317-
public function edit_operations( int $asset_group_id, array $assets ): array {
323+
public function edit_operations( int $asset_group_id, array $assets, bool $is_brand_guidelines_enabled ): array {
318324
if ( empty( $assets ) ) {
319-
return [];
325+
return [
326+
'operations' => [],
327+
'assets_for_creation' => [],
328+
'created_asset_resource_names' => [],
329+
];
320330
}
321331

322332
$asset_group_assets_operations = [];
323333
$assets_for_creation = $this->get_assets_to_be_created( $assets );
324-
$asset_arns = $this->asset->create_assets( $assets_for_creation );
334+
$asset_resource_names = $this->asset->create_assets( $assets_for_creation );
325335
$total_assets = count( $assets_for_creation );
326336
$delete_asset_group_assets_operations = [];
327337

@@ -333,33 +343,54 @@ public function edit_operations( int $asset_group_id, array $assets ): array {
333343
// The asset mutation operation results (ARNs) are returned in the same order as the operations are specified.
334344
// See: https://youtu.be/9KaVjqW5tVM?t=103
335345
for ( $i = 0; $i < $total_assets; $i++ ) {
336-
$asset_group_assets_operations[] = $this->create_operation( $asset_group_id, $assets_for_creation[ $i ]['field_type'], $asset_arns[ $i ] );
346+
$field_type = $assets_for_creation[ $i ]['field_type'];
347+
348+
// When brand guidelines is enabled, do NOT add asset group asset create for business_name or logo.
349+
// Google Ads API requires them as CampaignAssets only, not AssetGroupAssets.
350+
if ( $is_brand_guidelines_enabled && ( 'business_name' === $field_type || 'logo' === $field_type ) ) {
351+
continue;
352+
}
353+
354+
$asset_group_assets_operations[] = $this->create_operation( $asset_group_id, $field_type, $asset_resource_names[ $i ] );
337355
}
338356

339357
foreach ( $this->get_assets_to_be_deleted( $assets ) as $asset ) {
358+
// When Brand Guidelines is enabled, skip deleting business_name/logo from asset group level.
359+
// They may not exist there (original implementation didn't link them at asset group level).
360+
// They're managed at campaign level via CampaignAsset links.
361+
if ( $is_brand_guidelines_enabled && isset( $asset['field_type'] ) && ( 'business_name' === $asset['field_type'] || 'logo' === $asset['field_type'] ) ) {
362+
continue;
363+
}
340364
$delete_asset_group_assets_operations[] = $this->delete_operation( $asset_group_id, $asset['field_type'], $asset['id'] );
341365
}
342366

343367
// The delete operations must be executed first otherwise will cause a conflict with existing assets with identical content.
344368
// See here: https://github.com/woocommerce/google-listings-and-ads/pull/1870
345-
return array_merge( $delete_asset_group_assets_operations, $asset_group_assets_operations );
346-
}
369+
$operations = array_merge( $delete_asset_group_assets_operations, $asset_group_assets_operations );
347370

371+
// Resource names (ARNs) from AdsAsset::create_assets() mutate response; same order as assets_for_creation.
372+
// Used when brand guidelines is enabled to link business name/logo at campaign level.
373+
return [
374+
'operations' => $operations,
375+
'assets_for_creation' => $assets_for_creation,
376+
'created_asset_resource_names' => $asset_resource_names,
377+
];
378+
}
348379

349380
/**
350381
* Creates an operation for an asset group asset.
351382
*
352383
* @param int $asset_group_id The ID of the asset group.
353384
* @param string $asset_field_type The field type of the asset.
354-
* @param string $asset_arn The the asset ARN.
385+
* @param string $asset_resource_name The asset resource name.
355386
*
356387
* @return MutateOperation The mutate create operation for the asset group asset.
357388
*/
358-
protected function create_operation( int $asset_group_id, string $asset_field_type, string $asset_arn ): MutateOperation {
389+
protected function create_operation( int $asset_group_id, string $asset_field_type, string $asset_resource_name ): MutateOperation {
359390
$operation = new AssetGroupAssetOperation();
360391
$new_asset_group_asset = new AssetGroupAsset(
361392
[
362-
'asset' => $asset_arn,
393+
'asset' => $asset_resource_name,
363394
'asset_group' => ResourceNames::forAssetGroup( $this->options->get_ads_id(), $asset_group_id ),
364395
'field_type' => AssetFieldType::number( $asset_field_type ),
365396
]

0 commit comments

Comments
 (0)