쇼핑 등록정보 그룹 만들기

쇼핑 등록정보 그룹을 사용하면 제품을 그룹으로 분류할 수 있습니다. 이를 제품 그룹의 UI에서 확인할 수 있습니다. 그룹화할 수 있습니다. 제품을 포함하거나 제외할 수 있습니다.

아래 트리를 살펴보겠습니다. 첫 번째 수준에서 제품이 상태를 새 제품, 중고품, 기타 제품 상태로 구분합니다. 두 번째 다른 제품 조건의 제품은 다음과 같이 브랜드별로 나뉩니다. "쿨브랜드" 제품, 'CheapBrand' 및 기타 브랜드입니다.

트리의 각 노드는 ListingGroupType 하위 그룹 트리에 새로운 레벨을 도입하는 반면, 단위는 트리의 잎입니다. 각 하위 부문은 항상 완전히 파티셔닝되어야 하므로 노드를 포함해야 함 Other를 나타냅니다. 이 예에서는 루트 및 제품 조건: (기타) 노드는 하위 그룹입니다. 이 트리 구조에는 하위 그룹 및 단위를 사용하면 단위 수준에서 입찰가를 설정하고 제품이 트리에서 단 하나의 단위 노드에 속하게 됩니다.

노드는 ListingGroupInfo의 객체입니다. 클래스가 포함되어 있으며 ListingGroupType 필드 노드는 단위 또는 하위 그룹입니다 ListingGroupInfo을(를) listing_group(으)로 설정 AdGroupCriterion의 URL을 사용하여 AdGroup

트리를 유효하게 만들려면 단위 노드가 하나 이상 필요합니다. 이 단위는 이 노드에는 ‘모든 제품’ 나눗셈. 광고가 게재되지 않습니다. 유효한 등록정보 그룹 트리 만들기

수동 CPC 입찰가 설정

다음 중 cpc_bid_micros를 설정할 수 있습니다. 단위 노드에서만 AdGroupCriterion 하위 그룹 노드에서 이를 시도하면 오류와 함께 실패합니다.

목록 크기

ListingGroupInfo에는 case_value도 있습니다. 이는 다음과 같은 ListingDimensionInfo입니다. 여러 측정기준 유형 중 하나를 포함합니다. ListingGroupInfo는 다음을 나타냅니다. 제품 ID, 브랜드, 제품 등 제품과 연결된 값 있습니다. 사용 가능한 ListingDimensionInfo 유형에 대한 자세한 설명은 다음과 같습니다. 참조 문서에서 확인하세요.

하위 부문의 각 하위 요소는 동일한 case_value을 가져야 합니다. ListingDimensionInfo 하위유형. 오직 루트 노드에만 case_value가 없습니다.

각 하위 그룹에는 'empty'가 포함되어야 합니다. case_value 있습니다. 이 하위 요소는 일반적으로 기타라고 불립니다. '기타 모든 값'을 나타냅니다. 해당 ListingDimensionInfo

등록정보 그룹 트리의 첫 번째 수준을 추가하는 아래의 코드 스니펫을 참고하세요. 를 참조하세요.

자바

private void runExample(
    GoogleAdsClient googleAdsClient,
    long customerId,
    long adGroupId,
    boolean replaceExistingTree) {
  // 1) Optional: Removes the existing listing group tree, if it already exists on the ad group.
  if (replaceExistingTree) {
    removeListingGroupTree(googleAdsClient, customerId, adGroupId);
  }
  // Creates a list of ad group criterion to add.q
  List<AdGroupCriterionOperation> operations = new ArrayList<>();

  // 2) Constructs the listing group tree "root" node.

  // Subdivision node: (Root node)
  AdGroupCriterion adGroupCriterionRoot =
      createListingGroupSubdivisionRoot(customerId, adGroupId, -1L);
  // Get the resource name that will be used for the root node.
  // This resource has not been created yet and will include the temporary ID as part of the
  // criterion ID.
  String adGroupCriterionResourceNameRoot = adGroupCriterionRoot.getResourceName();
  operations.add(AdGroupCriterionOperation.newBuilder().setCreate(adGroupCriterionRoot).build());

  // 3) Construct the listing group unit nodes for NEW, USED and other

  // Biddable Unit node: (Condition NEW node)
  // * Product Condition: NEW
  // * CPC bid: $0.20
  AdGroupCriterion adGroupCriterionConditionNew =
      createListingGroupUnitBiddable(
          customerId,
          adGroupId,
          adGroupCriterionResourceNameRoot,
          ListingDimensionInfo.newBuilder()
              .setProductCondition(
                  ProductConditionInfo.newBuilder().setCondition(ProductCondition.NEW).build())
              .build(),
          200_000L);
  operations.add(
      AdGroupCriterionOperation.newBuilder().setCreate(adGroupCriterionConditionNew).build());

  // Biddable Unit node: (Condition USED node)
  // * Product Condition: USED
  // * CPC bid: $0.10
  AdGroupCriterion adGroupCriterionConditionUsed =
      createListingGroupUnitBiddable(
          customerId,
          adGroupId,
          adGroupCriterionResourceNameRoot,
          ListingDimensionInfo.newBuilder()
              .setProductCondition(
                  ProductConditionInfo.newBuilder().setCondition(ProductCondition.USED).build())
              .build(),
          100_000L);
  operations.add(
      AdGroupCriterionOperation.newBuilder().setCreate(adGroupCriterionConditionUsed).build());

  // Sub-division node: (Condition "other" node)
  // * Product Condition: (not specified)
  AdGroupCriterion adGroupCriterionConditionOther =
      createListingGroupSubdivision(
          customerId,
          adGroupId,
          -2L,
          adGroupCriterionResourceNameRoot,
          ListingDimensionInfo.newBuilder()
              // All sibling nodes must have the same dimension type, even if they don't contain a
              // bid.
              // parent
              .setProductCondition(ProductConditionInfo.newBuilder().build())
              .build());
  // Gets the resource name that will be used for the condition other node.
  // This resource has not been created yet and will include the temporary ID as part of the
  // criterion ID.
  String adGroupCriterionResourceNameConditionOther =
      adGroupCriterionConditionOther.getResourceName();
  operations.add(
      AdGroupCriterionOperation.newBuilder().setCreate(adGroupCriterionConditionOther).build());

  // 4) Constructs the listing group unit nodes for CoolBrand, CheapBrand and other

  // Biddable Unit node: (Brand CoolBrand node)
  // * Brand: CoolBrand
  // * CPC bid: $0.90
  AdGroupCriterion adGroupCriterionBrandCoolBrand =
      createListingGroupUnitBiddable(
          customerId,
          adGroupId,
          adGroupCriterionResourceNameConditionOther,
          ListingDimensionInfo.newBuilder()
              .setProductBrand(ProductBrandInfo.newBuilder().setValue("CoolBrand").build())
              .build(),
          900_000L);
  operations.add(
      AdGroupCriterionOperation.newBuilder().setCreate(adGroupCriterionBrandCoolBrand).build());

  // Biddable Unit node: (Brand CheapBrand node)
  // * Brand: CheapBrand
  // * CPC bid: $0.01
  AdGroupCriterion adGroupCriterionBrandCheapBrand =
      createListingGroupUnitBiddable(
          customerId,
          adGroupId,
          adGroupCriterionResourceNameConditionOther,
          ListingDimensionInfo.newBuilder()
              .setProductBrand(ProductBrandInfo.newBuilder().setValue("CheapBrand").build())
              .build(),
          10_000L);
  operations.add(
      AdGroupCriterionOperation.newBuilder().setCreate(adGroupCriterionBrandCheapBrand).build());

  // Biddable Unit node: (Brand other node)
  // * Brand: CheapBrand
  // * CPC bid: $0.01
  AdGroupCriterion adGroupCriterionBrandOther =
      createListingGroupUnitBiddable(
          customerId,
          adGroupId,
          adGroupCriterionResourceNameConditionOther,
          ListingDimensionInfo.newBuilder()
              .setProductBrand(ProductBrandInfo.newBuilder().build())
              .build(),
          50_000L);
  operations.add(
      AdGroupCriterionOperation.newBuilder().setCreate(adGroupCriterionBrandOther).build());

  // Issues a mutate request to add the ad group criterion to the ad group.
  try (AdGroupCriterionServiceClient adGroupCriterionServiceClient =
      googleAdsClient.getLatestVersion().createAdGroupCriterionServiceClient()) {
    List<MutateAdGroupCriterionResult> mutateAdGroupCriteriaResults =
        adGroupCriterionServiceClient
            .mutateAdGroupCriteria(Long.toString(customerId), operations)
            .getResultsList();
    for (MutateAdGroupCriterionResult mutateAdGroupCriterionResult :
        mutateAdGroupCriteriaResults) {
      System.out.printf(
          "Added ad group criterion for listing group with resource name: '%s'%n",
          mutateAdGroupCriterionResult.getResourceName());
    }
  }
}

      

C#

public void Run(GoogleAdsClient client, long customerId, long adGroupId,
    bool replaceExistingTree)
{
    // Get the AdGroupCriterionService.
    AdGroupCriterionServiceClient adGroupCriterionService =
        client.GetService(Services.V17.AdGroupCriterionService);

    try
    {
        // 1) Optional: Remove the existing listing group tree, if it already exists on the
        // ad group.
        if (replaceExistingTree)
        {
            RemoveListingGroupTree(client, customerId, adGroupId);
        }
        // Create a list of ad group criterion to add
        List<AdGroupCriterionOperation> operations = new List<AdGroupCriterionOperation>();

        // 2) Construct the listing group tree "root" node.

        // Subdivision node: (Root node)
        AdGroupCriterion adGroupCriterionRoot = CreateListingGroupSubdivisionRoot(
            customerId, adGroupId, -1L);

        // Get the resource name that will be used for the root node.
        // This resource has not been created yet and will include the temporary ID as
        // part of the criterion ID.
        String adGroupCriterionResourceNameRoot = adGroupCriterionRoot.ResourceName;
        operations.Add(new AdGroupCriterionOperation()
        {
            Create = adGroupCriterionRoot
        });

        // 3) Construct the listing group unit nodes for NEW, USED and other

        // Biddable Unit node: (Condition NEW node)
        // * Product Condition: NEW
        // * CPC bid: $0.20
        AdGroupCriterion adGroupCriterionConditionNew =
            CreateListingGroupUnitBiddable(
                customerId,
                adGroupId,
                adGroupCriterionResourceNameRoot,
                new ListingDimensionInfo()
                {
                    ProductCondition = new ProductConditionInfo()
                    {
                        Condition = ProductCondition.New
                    }
                },
                200_000L);
        operations.Add(new AdGroupCriterionOperation()
        {
            Create = adGroupCriterionConditionNew
        });

        // Biddable Unit node: (Condition USED node)
        // * Product Condition: USED
        // * CPC bid: $0.10
        AdGroupCriterion adGroupCriterionConditionUsed =
            CreateListingGroupUnitBiddable(
                customerId,
                adGroupId,
                adGroupCriterionResourceNameRoot,
                new ListingDimensionInfo()
                {
                    ProductCondition = new ProductConditionInfo()
                    {
                        Condition = ProductCondition.Used
                    }
                },
                100_000L
            );
        operations.Add(new AdGroupCriterionOperation()
        {
            Create = adGroupCriterionConditionUsed
        });

        // Sub-division node: (Condition "other" node)
        // * Product Condition: (not specified)
        AdGroupCriterion adGroupCriterionConditionOther =
            CreateListingGroupSubdivision(
                customerId,
                adGroupId,
                -2L,
                adGroupCriterionResourceNameRoot,
                new ListingDimensionInfo()
                {
                    // All sibling nodes must have the same dimension type, even if they
                    // don't contain a bid.
                    ProductCondition = new ProductConditionInfo()
                }
            );
        // Get the resource name that will be used for the condition other node.
        // This resource has not been created yet and will include the temporary ID as
        // part of the criterion ID.
        String adGroupCriterionResourceNameConditionOther =
            adGroupCriterionConditionOther.ResourceName;
        operations.Add(new AdGroupCriterionOperation()
        {
            Create = adGroupCriterionConditionOther
        });

        // 4) Construct the listing group unit nodes for CoolBrand, CheapBrand and other

        // Biddable Unit node: (Brand CoolBrand node)
        // * Brand: CoolBrand
        // * CPC bid: $0.90
        AdGroupCriterion adGroupCriterionBrandCoolBrand =
            CreateListingGroupUnitBiddable(
                customerId,
                adGroupId,
                adGroupCriterionResourceNameConditionOther,
                new ListingDimensionInfo()
                {
                    ProductBrand = new ProductBrandInfo()
                    {
                        Value = "CoolBrand"
                    }
                },
                900_000L);
        operations.Add(new AdGroupCriterionOperation()
        {
            Create = adGroupCriterionBrandCoolBrand
        });

        // Biddable Unit node: (Brand CheapBrand node)
        // * Brand: CheapBrand
        // * CPC bid: $0.01
        AdGroupCriterion adGroupCriterionBrandCheapBrand =
            CreateListingGroupUnitBiddable(
                customerId,
                adGroupId,
                adGroupCriterionResourceNameConditionOther,
                new ListingDimensionInfo()
                {
                    ProductBrand = new ProductBrandInfo()
                    {
                        Value = "CheapBrand"
                    }
                },
                10_000L);

        operations.Add(new AdGroupCriterionOperation()
        {
            Create = adGroupCriterionBrandCheapBrand
        });

        // Biddable Unit node: (Brand other node)
        // * Brand: CheapBrand
        // * CPC bid: $0.01
        AdGroupCriterion adGroupCriterionBrandOther =
            CreateListingGroupUnitBiddable(
                customerId,
                adGroupId,
                adGroupCriterionResourceNameConditionOther,
                new ListingDimensionInfo()
                {
                    ProductBrand = new ProductBrandInfo()
                },
                50_000L);
        operations.Add(new AdGroupCriterionOperation()
        {
            Create = adGroupCriterionBrandOther
        });

        // Issues a mutate request to add the ad group criterion to the ad group.
        MutateAdGroupCriteriaResponse response =
            adGroupCriterionService.MutateAdGroupCriteria(
                customerId.ToString(), operations);

        // Display the results.
        foreach (MutateAdGroupCriterionResult mutateAdGroupCriterionResult
            in response.Results)
        {
            Console.WriteLine("Added ad group criterion for listing group with resource " +
                $"name: '{mutateAdGroupCriterionResult.ResourceName}.");
        }
    }
    catch (GoogleAdsException e)
    {
        Console.WriteLine("Failure:");
        Console.WriteLine($"Message: {e.Message}");
        Console.WriteLine($"Failure: {e.Failure}");
        Console.WriteLine($"Request ID: {e.RequestId}");
        throw;
    }
}
      

PHP

public static function runExample(
    GoogleAdsClient $googleAdsClient,
    int $customerId,
    int $adGroupId,
    bool $replaceExistingTree
) {
    // 1) Optional: Remove the existing listing group tree, if it already exists on the ad
    // group.
    if ($replaceExistingTree === 'true') {
        self::removeListingGroupTree($googleAdsClient, $customerId, $adGroupId);
    }
    // Create a list of ad group criteria to add.
    $operations = [];

    // 2) Construct the listing group tree "root" node.

    // Subdivision node: (Root node)
    $adGroupCriterionRoot = self::createListingGroupSubdivision($customerId, $adGroupId);
    // Get the resource name that will be used for the root node.
    // This resource has not been created yet and will include the temporary ID as part of the
    // criterion ID.
    $adGroupCriterionResourceNameRoot = $adGroupCriterionRoot->getResourceName();
    $operations[] = new AdGroupCriterionOperation(['create' => $adGroupCriterionRoot]);

    // 3) Construct the listing group unit nodes for NEW, USED and other.

    // Biddable Unit node: (Condition NEW node)
    // * Product Condition: NEW
    // * CPC bid: $0.20
    $adGroupCriterionConditionNew = self::createListingGroupUnitBiddable(
        $customerId,
        $adGroupId,
        $adGroupCriterionResourceNameRoot,
        new ListingDimensionInfo([
            'product_condition' => new ProductConditionInfo(
                ['condition' => ProductCondition::PBNEW]
            )
        ]),
        200000
    );
    $operations[] = new AdGroupCriterionOperation(['create' => $adGroupCriterionConditionNew]);

    // Biddable Unit node: (Condition USED node)
    // * Product Condition: USED
    // * CPC bid: $0.10
    $adGroupCriterionConditionUsed = self::createListingGroupUnitBiddable(
        $customerId,
        $adGroupId,
        $adGroupCriterionResourceNameRoot,
        new ListingDimensionInfo([
            'product_condition' => new ProductConditionInfo(
                ['condition' => ProductCondition::USED]
            )
        ]),
        100000
    );
    $operations[] = new AdGroupCriterionOperation(['create' => $adGroupCriterionConditionUsed]);

    // Sub-division node: (Condition "other" node)
    // * Product Condition: (not specified)
    $adGroupCriterionConditionOther = self::createListingGroupSubdivision(
        $customerId,
        $adGroupId,
        $adGroupCriterionResourceNameRoot,
        new ListingDimensionInfo([
            // All sibling nodes must have the same dimension type, even if they don't contain a
            // bid.
            'product_condition' => new ProductConditionInfo()
        ])
    );
    $operations[] =
        new AdGroupCriterionOperation(['create' => $adGroupCriterionConditionOther]);

    // Get the resource name that will be used for the condition other node.
    // This resource has not been created yet and will include the temporary ID as part of the
    // criterion ID.
    $adGroupCriterionResourceNameConditionOther =
        $adGroupCriterionConditionOther->getResourceName();

    // 4) Construct the listing group unit nodes for CoolBrand, CheapBrand and other.

    // Biddable Unit node: (Brand CoolBrand node)
    // * Brand: CoolBrand
    // * CPC bid: $0.90
    $adGroupCriterionBrandCoolBrand = self::createListingGroupUnitBiddable(
        $customerId,
        $adGroupId,
        $adGroupCriterionResourceNameConditionOther,
        new ListingDimensionInfo([
            'product_brand' => new ProductBrandInfo(['value' => 'CoolBrand'])
        ]),
        900000
    );
    $operations[] =
        new AdGroupCriterionOperation(['create' => $adGroupCriterionBrandCoolBrand]);

    // Biddable Unit node: (Brand CheapBrand node)
    // * Brand: CheapBrand
    // * CPC bid: $0.01
    $adGroupCriterionBrandCheapBrand = self::createListingGroupUnitBiddable(
        $customerId,
        $adGroupId,
        $adGroupCriterionResourceNameConditionOther,
        new ListingDimensionInfo([
            'product_brand' => new ProductBrandInfo(['value' => 'CheapBrand'])
        ]),
        10000
    );
    $operations[] =
        new AdGroupCriterionOperation(['create' => $adGroupCriterionBrandCheapBrand]);

    // Biddable Unit node: (Brand other node)
    // * CPC bid: $0.05
    $adGroupCriterionBrandOtherBrand = self::createListingGroupUnitBiddable(
        $customerId,
        $adGroupId,
        $adGroupCriterionResourceNameConditionOther,
        new ListingDimensionInfo([
            'product_brand' => new ProductBrandInfo()
        ]),
        50000
    );
    $operations[] =
        new AdGroupCriterionOperation(['create' => $adGroupCriterionBrandOtherBrand]);

    // Issues a mutate request.
    $adGroupCriterionServiceClient = $googleAdsClient->getAdGroupCriterionServiceClient();
    $response = $adGroupCriterionServiceClient->mutateAdGroupCriteria(
        MutateAdGroupCriteriaRequest::build($customerId, $operations)
    );
    printf(
        'Added %d ad group criteria for listing group tree with the following resource '
        . 'names:%s',
        $response->getResults()->count(),
        PHP_EOL
    );
    foreach ($response->getResults() as $addedAdGroupCriterion) {
        /** @var AdGroupCriterion $addedAdGroupCriterion */
        print $addedAdGroupCriterion->getResourceName() . PHP_EOL;
    }
}
      

Python

def main(client, customer_id, ad_group_id, replace_existing_tree):
    """Adds a shopping listing group tree to a shopping ad group.

    Args:
        client: An initialized Google Ads client.
        customer_id: The Google Ads customer ID.
        ad_group_id: The ad group ID to which the node will be added.
        replace_existing_tree: Boolean, whether to replace the existing listing
            group tree on the ad group. Defaults to false.
    """
    # Get the AdGroupCriterionService client.
    ad_group_criterion_service = client.get_service("AdGroupCriterionService")

    # Optional: Remove the existing listing group tree, if it already exists
    # on the ad group. The example will throw a LISTING_GROUP_ALREADY_EXISTS
    # error if a listing group tree already exists and this option is not
    # set to true.
    if replace_existing_tree:
        remove_listing_group_tree(client, customer_id, ad_group_id)

    # Create a list of ad group criteria operations.
    operations = []

    # Construct the listing group tree "root" node.
    # Subdivision node: (Root node)
    ad_group_criterion_root_operation = create_listing_group_subdivision(
        client, customer_id, ad_group_id
    )

    # Get the resource name that will be used for the root node.
    # This resource has not been created yet and will include the temporary
    # ID as part of the criterion ID.
    ad_group_criterion_root_resource_name = (
        ad_group_criterion_root_operation.create.resource_name
    )
    operations.append(ad_group_criterion_root_operation)

    # Construct the listing group unit nodes for NEW, USED, and other.
    product_condition_enum = client.enums.ProductConditionEnum
    condition_dimension_info = client.get_type("ListingDimensionInfo")

    # Biddable Unit node: (Condition NEW node)
    # * Product Condition: NEW
    # * CPC bid: $0.20
    condition_dimension_info.product_condition.condition = (
        product_condition_enum.NEW
    )
    operations.append(
        create_listing_group_unit_biddable(
            client,
            customer_id,
            ad_group_id,
            ad_group_criterion_root_resource_name,
            condition_dimension_info,
            200_000,
        )
    )

    # Biddable Unit node: (Condition USED node)
    # * Product Condition: USED
    # * CPC bid: $0.10
    condition_dimension_info.product_condition.condition = (
        product_condition_enum.USED
    )
    operations.append(
        create_listing_group_unit_biddable(
            client,
            customer_id,
            ad_group_id,
            ad_group_criterion_root_resource_name,
            condition_dimension_info,
            100_000,
        )
    )

    # Sub-division node: (Condition "other" node)
    # * Product Condition: (not specified)
    # Note that all sibling nodes must have the same dimension type, even if
    # they don't contain a bid.
    client.copy_from(
        condition_dimension_info.product_condition,
        client.get_type("ProductConditionInfo"),
    )
    ad_group_criterion_other_operation = create_listing_group_subdivision(
        client,
        customer_id,
        ad_group_id,
        ad_group_criterion_root_resource_name,
        condition_dimension_info,
    )
    # Get the resource name that will be used for the condition other node.
    # This resource has not been created yet and will include the temporary
    # ID as part of the criterion ID.
    ad_group_criterion_other_resource_name = (
        ad_group_criterion_other_operation.create.resource_name
    )
    operations.append(ad_group_criterion_other_operation)

    # Build the listing group nodes for CoolBrand, CheapBrand, and other.
    brand_dimension_info = client.get_type("ListingDimensionInfo")

    # Biddable Unit node: (Brand CoolBrand node)
    # * Brand: CoolBrand
    # * CPC bid: $0.90
    brand_dimension_info.product_brand.value = "CoolBrand"
    operations.append(
        create_listing_group_unit_biddable(
            client,
            customer_id,
            ad_group_id,
            ad_group_criterion_other_resource_name,
            brand_dimension_info,
            900_000,
        )
    )

    # Biddable Unit node: (Brand CheapBrand node)
    # * Brand: CheapBrand
    # * CPC bid: $0.01
    brand_dimension_info.product_brand.value = "CheapBrand"
    operations.append(
        create_listing_group_unit_biddable(
            client,
            customer_id,
            ad_group_id,
            ad_group_criterion_other_resource_name,
            brand_dimension_info,
            10_000,
        )
    )

    # Biddable Unit node: (Brand other node)
    # * CPC bid: $0.05
    client.copy_from(
        brand_dimension_info.product_brand,
        client.get_type("ProductBrandInfo"),
    )
    operations.append(
        create_listing_group_unit_biddable(
            client,
            customer_id,
            ad_group_id,
            ad_group_criterion_other_resource_name,
            brand_dimension_info,
            50_000,
        )
    )

    # Add the ad group criteria.
    mutate_ad_group_criteria_response = (
        ad_group_criterion_service.mutate_ad_group_criteria(
            customer_id=customer_id, operations=operations
        )
    )

    # Print the results of the successful mutates.
    print(
        "Added ad group criteria for the listing group tree with the "
        "following resource names:"
    )
    for result in mutate_ad_group_criteria_response.results:
        print(f"\t{result.resource_name}")

    print(f"{len(mutate_ad_group_criteria_response.results)} criteria added.")
      

Ruby

def add_shopping_product_listing_group_tree(
  customer_id,
  ad_group_id,
  should_replace_existing_tree
)
  # GoogleAdsClient will read a config file from
  # ENV['HOME']/google_ads_config.rb when called without parameters
  client = Google::Ads::GoogleAds::GoogleAdsClient.new

  # 1) Optional: Remove the existing listing group tree, if it already exists
  # on the ad group.
  if should_replace_existing_tree
    remove_listing_group_tree(client, customer_id, ad_group_id)
  end

  # 2) Construct the listing group tree "root" node.

  # Subdivision node: (Root node)
  ad_group_criterion_root = create_listing_group_subdivision(
    client,
    customer_id,
    ad_group_id,
  )
  # This resource has not been created yet and will include the temporary ID as
  # part of the criterion ID.
  ad_group_criterion_root_resource_name = ad_group_criterion_root.resource_name
  operations = [client.operation.create_resource.ad_group_criterion(ad_group_criterion_root)]

  # 3) Construct the listing group unit nodes for NEW, USED, and other.

  # Biddable Unit node: (Condition NEW node)
  # * Product Condition: NEW
  # * CPC bid: $0.20
  listing_dimension_info = client.resource.listing_dimension_info do |ldi|
    ldi.product_condition = client.resource.product_condition_info do |pci|
      pci.condition = :NEW
    end
  end

  ad_group_criterion_condition_new = create_listing_group_unit_biddable(
    client,
    customer_id,
    ad_group_id,
    ad_group_criterion_root_resource_name,
    listing_dimension_info,
    200_000,
  )
  operation = client.operation.create_resource.ad_group_criterion(
    ad_group_criterion_condition_new
  )
  operations << operation

  # Biddable Unit node: (Condition USED node)
  # * Product Condition: USED
  # * CPC bid: $0.10
  listing_dimension_info = client.resource.listing_dimension_info do |ldi|
    ldi.product_condition = client.resource.product_condition_info do |pci|
      pci.condition = :USED
    end
  end
  ad_group_criterion_condition_used = create_listing_group_unit_biddable(
    client,
    customer_id,
    ad_group_id,
    ad_group_criterion_root_resource_name,
    listing_dimension_info,
    100_000,
  )
  operation = client.operation.create_resource.ad_group_criterion(
    ad_group_criterion_condition_used
  )
  operations << operation

  # Sub-division node: (Condition "other" node)
  # * Product Condition: (not specified)
  listing_dimension_info = client.resource.listing_dimension_info do |ldi|
    ldi.product_condition = client.resource.product_condition_info
  end
  ad_group_criterion_condition_other = create_listing_group_subdivision(
    client,
    customer_id,
    ad_group_id,
    ad_group_criterion_root_resource_name,
    listing_dimension_info,
  )
  operation = client.operation.create_resource.ad_group_criterion(
    ad_group_criterion_condition_other
  )
  operations << operation

  ad_group_criterion_condition_other_resource_name =
    ad_group_criterion_condition_other.resource_name

  # 4) Construct the listing group unit nodes for CoolBrand, CheapBrand, and
  # other.

  # Biddable Unit node: (Brand CoolBrand node)
  # * Brand: CoolBrand
  # * CPC bid: $0.90
  listing_dimension_info = client.resource.listing_dimension_info do |ldi|
    ldi.product_brand = client.resource.product_brand_info do |pbi|
      pbi.value = "CoolBrand"
    end
  end

  ad_group_criterion_brand_cool_brand = create_listing_group_unit_biddable(
    client,
    customer_id,
    ad_group_id,
    ad_group_criterion_condition_other_resource_name,
    listing_dimension_info,
    900_000,
  )
  operation = client.operation.create_resource.ad_group_criterion(
    ad_group_criterion_brand_cool_brand
  )
  operations << operation

  # Biddable Unit node: (Brand CheapBrand node)
  # * Brand: CheapBrand
  # * CPC bid: $0.01
  listing_dimension_info = client.resource.listing_dimension_info do |ldi|
    ldi.product_brand = client.resource.product_brand_info do |pbi|
      pbi.value = "CheapBrand"
    end
  end
  ad_group_criterion_brand_cheap_brand = create_listing_group_unit_biddable(
    client,
    customer_id,
    ad_group_id,
    ad_group_criterion_condition_other_resource_name,
    listing_dimension_info,
    10_000,
  )
  operation = client.operation.create_resource.ad_group_criterion(
    ad_group_criterion_brand_cheap_brand
  )
  operations << operation

  # Biddable Unit node: (Brand other node)
  # * CPC bid: $0.05
  listing_dimension_info = client.resource.listing_dimension_info do |ldi|
    ldi.product_brand = client.resource.product_brand_info
  end
  ad_group_criterion_brand_other_brand = create_listing_group_unit_biddable(
    client,
    customer_id,
    ad_group_id,
    ad_group_criterion_condition_other_resource_name,
    listing_dimension_info,
    50_000,
  )
  operation = client.operation.create_resource.ad_group_criterion(
    ad_group_criterion_brand_other_brand
  )
  operations << operation

  # Issue the mutate request.
  response = client.service.ad_group_criterion.mutate_ad_group_criteria(
    customer_id: customer_id,
    operations: operations,
  )

  total_count = 0
  response.results.each do |added_criterion|
    puts "Added ad group criterion with name: #{added_criterion.resource_name}"
    total_count += 1
  end
  puts "#{total_count} criteria added in total."
end
      

Perl

sub add_shopping_product_listing_group_tree {
  my ($api_client, $customer_id, $ad_group_id, $replace_existing_tree) = @_;

  # 1) Optional: Remove the existing listing group tree, if it already exists
  # on the ad group.
  if ($replace_existing_tree) {
    remove_listing_group_tree($api_client, $customer_id, $ad_group_id);
  }

  # Create a list of ad group criteria operations to add.
  my $operations = [];

  # 2) Construct the listing group tree "root" node.

  # Subdivision node: (Root node)
  my $ad_group_criterion_root =
    create_listing_group_subdivision($customer_id, $ad_group_id);
  # Get the resource name that will be used for the root node.
  # This resource has not been created yet and will include the temporary ID as
  # part of the criterion ID.
  my $ad_group_criterion_root_resource_name =
    $ad_group_criterion_root->{resourceName};
  push @$operations,
    Google::Ads::GoogleAds::V17::Services::AdGroupCriterionService::AdGroupCriterionOperation
    ->new({
      create => $ad_group_criterion_root
    });

  # 3) Construct the listing group unit nodes for NEW, USED, and other.

  # Biddable Unit node: (Condition NEW node)
  # * Product Condition: NEW
  # * CPC bid: $0.20
  my $ad_group_criterion_condition_new = create_listing_group_unit_biddable(
    $customer_id,
    $ad_group_id,
    $ad_group_criterion_root_resource_name,
    Google::Ads::GoogleAds::V17::Common::ListingDimensionInfo->new({
        productCondition =>
          Google::Ads::GoogleAds::V17::Common::ProductConditionInfo->new({
            condition => NEW
          })}
    ),
    200000
  );
  push @$operations,
    Google::Ads::GoogleAds::V17::Services::AdGroupCriterionService::AdGroupCriterionOperation
    ->new({
      create => $ad_group_criterion_condition_new
    });

  # Biddable Unit node: (Condition USED node)
  # * Product Condition: USED
  # * CPC bid: $0.10
  my $ad_group_criterion_condition_used = create_listing_group_unit_biddable(
    $customer_id,
    $ad_group_id,
    $ad_group_criterion_root_resource_name,
    Google::Ads::GoogleAds::V17::Common::ListingDimensionInfo->new({
        productCondition =>
          Google::Ads::GoogleAds::V17::Common::ProductConditionInfo->new({
            condition => USED
          })}
    ),
    100000
  );
  push @$operations,
    Google::Ads::GoogleAds::V17::Services::AdGroupCriterionService::AdGroupCriterionOperation
    ->new({
      create => $ad_group_criterion_condition_used
    });

  # Sub-division node: (Condition "other" node)
  # * Product Condition: (not specified)
  my $ad_group_criterion_condition_other = create_listing_group_subdivision(
    $customer_id,
    $ad_group_id,
    $ad_group_criterion_root_resource_name,
    Google::Ads::GoogleAds::V17::Common::ListingDimensionInfo->new({
        # All sibling nodes must have the same dimension type, even if they
        # don't contain a bid.
        productCondition =>
          Google::Ads::GoogleAds::V17::Common::ProductConditionInfo->new()}));
  push @$operations,
    Google::Ads::GoogleAds::V17::Services::AdGroupCriterionService::AdGroupCriterionOperation
    ->new({
      create => $ad_group_criterion_condition_other
    });

  # Get the resource name that will be used for the condition other node.
  # This resource has not been created yet and will include the temporary ID as
  # part of the criterion ID.
  my $ad_group_criterion_condition_other_resource_name =
    $ad_group_criterion_condition_other->{resourceName};

  # 4) Construct the listing group unit nodes for CoolBrand, CheapBrand, and
  # other.

  # Biddable Unit node: (Brand CoolBrand node)
  # * Brand: CoolBrand
  # * CPC bid: $0.90
  my $ad_group_criterion_brand_cool_brand = create_listing_group_unit_biddable(
    $customer_id,
    $ad_group_id,
    $ad_group_criterion_condition_other_resource_name,
    Google::Ads::GoogleAds::V17::Common::ListingDimensionInfo->new({
        productBrand =>
          Google::Ads::GoogleAds::V17::Common::ProductBrandInfo->new(
          {value => "CoolBrand"})}
    ),
    900000
  );
  push @$operations,
    Google::Ads::GoogleAds::V17::Services::AdGroupCriterionService::AdGroupCriterionOperation
    ->new({
      create => $ad_group_criterion_brand_cool_brand
    });

  # Biddable Unit node: (Brand CheapBrand node)
  # * Brand: CheapBrand
  # * CPC bid: $0.01
  my $ad_group_criterion_brand_cheap_brand = create_listing_group_unit_biddable(
    $customer_id,
    $ad_group_id,
    $ad_group_criterion_condition_other_resource_name,
    Google::Ads::GoogleAds::V17::Common::ListingDimensionInfo->new({
        productBrand =>
          Google::Ads::GoogleAds::V17::Common::ProductBrandInfo->new(
          {value => "CheapBrand"})}
    ),
    10000
  );
  push @$operations,
    Google::Ads::GoogleAds::V17::Services::AdGroupCriterionService::AdGroupCriterionOperation
    ->new({
      create => $ad_group_criterion_brand_cheap_brand
    });

  # Biddable Unit node: (Brand other node)
  # * CPC bid: $0.05
  my $ad_group_criterion_brand_other_brand = create_listing_group_unit_biddable(
    $customer_id,
    $ad_group_id,
    $ad_group_criterion_condition_other_resource_name,
    Google::Ads::GoogleAds::V17::Common::ListingDimensionInfo->new({
        productBrand =>
          Google::Ads::GoogleAds::V17::Common::ProductBrandInfo->new()}
    ),
    50000
  );
  push @$operations,
    Google::Ads::GoogleAds::V17::Services::AdGroupCriterionService::AdGroupCriterionOperation
    ->new({
      create => $ad_group_criterion_brand_other_brand
    });

  # Add the ad group criterion.
  my $ad_group_criteria_response =
    $api_client->AdGroupCriterionService()->mutate({
      customerId => $customer_id,
      operations => $operations
    });

  printf "Added %d ad group criteria for listing group tree with the " .
    "following resource names:\n",
    scalar @{$ad_group_criteria_response->{results}};

  foreach my $result (@{$ad_group_criteria_response->{results}}) {
    print $result->{resourceName}, "\n";
  }

  return 1;
}
      

ListingDimensionInfo에 사용 가능한 측정기준

등록정보 그룹에 포함될 수 있는 여러 개의 등록정보 측정기준이 있습니다. 광고 그룹 수준) 또는 목록 범위 (캠페인 수준)가 있습니다.

쇼핑 캠페인에 사용할 수 있는 ListingDimensionInfo 유형은 다음과 같습니다.

각 리소스에는 ProductCategoryConstant.ProductCategoryLocalization 드림 필드를 확인합니다. 리소스에서 반환한 데이터를 이해하려면 다음을 시도해 보세요. 제품 카테고리 상수 가져오기 예시

임시 ID

광고 그룹 기준에 ID는 서버에서 처리합니다. 하지만 ListingGroupInfo는 완료된 것이므로 하위 그룹을 만들 때마다 동일한 요청에서 하위 노드 중 최소 한 개와 기타 노드 한 개를 가질 수 있습니다.

parent_criterion_id를 설정하려면 ListingGroupInfo: 임시 기준 ID를 사용할 수 있습니다. 이는 전역적으로 고유하지 않고 지역적으로 고유합니다. 단일 뮤테이션 요청의 컨텍스트 내에서만 적용되는 식별자입니다. 모든 문자 음의 정수를 임시 ID로 사용할 수 있습니다. 코드 예를 들어 루트 ListingGroupInfo의 ID가 -1로 설정됩니다.

요청이 처리되면 각 AdGroupCriterion에 양수가 할당됩니다. 전역 ID와 동일합니다.

코드 예

다음은 쇼핑 등록정보 그룹을 만들기 위한 전체 코드입니다.

자바

// Copyright 2018 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package com.google.ads.googleads.examples.shoppingads;

import com.beust.jcommander.Parameter;
import com.google.ads.googleads.examples.utils.ArgumentNames;
import com.google.ads.googleads.examples.utils.CodeSampleParams;
import com.google.ads.googleads.lib.GoogleAdsClient;
import com.google.ads.googleads.v17.common.ListingDimensionInfo;
import com.google.ads.googleads.v17.common.ListingGroupInfo;
import com.google.ads.googleads.v17.common.ProductBrandInfo;
import com.google.ads.googleads.v17.common.ProductConditionInfo;
import com.google.ads.googleads.v17.enums.AdGroupCriterionStatusEnum.AdGroupCriterionStatus;
import com.google.ads.googleads.v17.enums.ListingGroupTypeEnum.ListingGroupType;
import com.google.ads.googleads.v17.enums.ProductConditionEnum.ProductCondition;
import com.google.ads.googleads.v17.errors.GoogleAdsError;
import com.google.ads.googleads.v17.errors.GoogleAdsException;
import com.google.ads.googleads.v17.resources.AdGroupCriterion;
import com.google.ads.googleads.v17.services.AdGroupCriterionOperation;
import com.google.ads.googleads.v17.services.AdGroupCriterionServiceClient;
import com.google.ads.googleads.v17.services.GoogleAdsRow;
import com.google.ads.googleads.v17.services.GoogleAdsServiceClient;
import com.google.ads.googleads.v17.services.GoogleAdsServiceClient.SearchPagedResponse;
import com.google.ads.googleads.v17.services.MutateAdGroupCriteriaResponse;
import com.google.ads.googleads.v17.services.MutateAdGroupCriterionResult;
import com.google.ads.googleads.v17.services.SearchGoogleAdsRequest;
import com.google.ads.googleads.v17.utils.ResourceNames;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

/**
 * Adds a shopping listing group tree to a shopping ad group. The example will clear an existing
 * listing group tree and rebuild it include the following tree structure:
 *
 * <pre>
 * ProductCanonicalCondition NEW $0.20
 * ProductCanonicalCondition USED $0.10
 * ProductCanonicalCondition null (everything else)
 *  ProductBrand CoolBrand $0.90
 *  ProductBrand CheapBrand $0.01
 *  ProductBrand null (everything else) $0.50
 * </pre>
 */
public class AddShoppingProductListingGroupTree {

  private static class AddShoppingListingGroupParams extends CodeSampleParams {

    @Parameter(names = ArgumentNames.CUSTOMER_ID, required = true)
    private Long customerId;

    @Parameter(names = ArgumentNames.AD_GROUP_ID, required = true)
    private Long adGroupId;

    @Parameter(names = ArgumentNames.REPLACE_EXISTING_TREE, required = true, arity = 1)
    private Boolean replaceExistingTree;
  }

  public static void main(String[] args) {
    AddShoppingListingGroupParams params = new AddShoppingListingGroupParams();
    if (!params.parseArguments(args)) {
      // Either pass the required parameters for this example on the command line, or insert them
      // into the code here. See the parameter class definition above for descriptions.
      params.customerId = Long.parseLong("INSERT_CUSTOMER_ID_HERE");
      params.adGroupId = Long.parseLong("INSERT_AD_GROUP_ID_HERE");
      // Optional: To replace the existing listing group tree on an ad group set this parameter to
      // true.
      // This option will remove the existing listing group tree before creating a replacement.
      params.replaceExistingTree = Boolean.parseBoolean("INSERT_REPLACE_EXISTING_TREE_HERE");
    }

    GoogleAdsClient googleAdsClient = null;
    try {
      googleAdsClient = GoogleAdsClient.newBuilder().fromPropertiesFile().build();
    } catch (FileNotFoundException fnfe) {
      System.err.printf(
          "Failed to load GoogleAdsClient configuration from file. Exception: %s%n", fnfe);
      System.exit(1);
    } catch (IOException ioe) {
      System.err.printf("Failed to create GoogleAdsClient. Exception: %s%n", ioe);
      System.exit(1);
    }

    try {
      new AddShoppingProductListingGroupTree()
          .runExample(
              googleAdsClient, params.customerId, params.adGroupId, params.replaceExistingTree);
    } catch (GoogleAdsException gae) {
      // GoogleAdsException is the base class for most exceptions thrown by an API request.
      // Instances of this exception have a message and a GoogleAdsFailure that contains a
      // collection of GoogleAdsErrors that indicate the underlying causes of the
      // GoogleAdsException.
      System.err.printf(
          "Request ID %s failed due to GoogleAdsException. Underlying errors:%n",
          gae.getRequestId());
      int i = 0;
      for (GoogleAdsError googleAdsError : gae.getGoogleAdsFailure().getErrorsList()) {
        System.err.printf("  Error %d: %s%n", i++, googleAdsError);
      }
      System.exit(1);
    }
  }

  /**
   * Runs the example.
   *
   * @param googleAdsClient the Google Ads API client.
   * @param customerId the client customer ID.
   * @param adGroupId the ID of the ad group.
   * @param replaceExistingTree replace the existing listing group tree on the ad group, if it
   *     already exists. The example will throw a 'LISTING_GROUP_ALREADY_EXISTS' error if listing
   *     group tree already exists and this option is not set to true.
   * @throws GoogleAdsException if an API request failed with one or more service errors.
   */
  private void runExample(
      GoogleAdsClient googleAdsClient,
      long customerId,
      long adGroupId,
      boolean replaceExistingTree) {
    // 1) Optional: Removes the existing listing group tree, if it already exists on the ad group.
    if (replaceExistingTree) {
      removeListingGroupTree(googleAdsClient, customerId, adGroupId);
    }
    // Creates a list of ad group criterion to add.q
    List<AdGroupCriterionOperation> operations = new ArrayList<>();

    // 2) Constructs the listing group tree "root" node.

    // Subdivision node: (Root node)
    AdGroupCriterion adGroupCriterionRoot =
        createListingGroupSubdivisionRoot(customerId, adGroupId, -1L);
    // Get the resource name that will be used for the root node.
    // This resource has not been created yet and will include the temporary ID as part of the
    // criterion ID.
    String adGroupCriterionResourceNameRoot = adGroupCriterionRoot.getResourceName();
    operations.add(AdGroupCriterionOperation.newBuilder().setCreate(adGroupCriterionRoot).build());

    // 3) Construct the listing group unit nodes for NEW, USED and other

    // Biddable Unit node: (Condition NEW node)
    // * Product Condition: NEW
    // * CPC bid: $0.20
    AdGroupCriterion adGroupCriterionConditionNew =
        createListingGroupUnitBiddable(
            customerId,
            adGroupId,
            adGroupCriterionResourceNameRoot,
            ListingDimensionInfo.newBuilder()
                .setProductCondition(
                    ProductConditionInfo.newBuilder().setCondition(ProductCondition.NEW).build())
                .build(),
            200_000L);
    operations.add(
        AdGroupCriterionOperation.newBuilder().setCreate(adGroupCriterionConditionNew).build());

    // Biddable Unit node: (Condition USED node)
    // * Product Condition: USED
    // * CPC bid: $0.10
    AdGroupCriterion adGroupCriterionConditionUsed =
        createListingGroupUnitBiddable(
            customerId,
            adGroupId,
            adGroupCriterionResourceNameRoot,
            ListingDimensionInfo.newBuilder()
                .setProductCondition(
                    ProductConditionInfo.newBuilder().setCondition(ProductCondition.USED).build())
                .build(),
            100_000L);
    operations.add(
        AdGroupCriterionOperation.newBuilder().setCreate(adGroupCriterionConditionUsed).build());

    // Sub-division node: (Condition "other" node)
    // * Product Condition: (not specified)
    AdGroupCriterion adGroupCriterionConditionOther =
        createListingGroupSubdivision(
            customerId,
            adGroupId,
            -2L,
            adGroupCriterionResourceNameRoot,
            ListingDimensionInfo.newBuilder()
                // All sibling nodes must have the same dimension type, even if they don't contain a
                // bid.
                // parent
                .setProductCondition(ProductConditionInfo.newBuilder().build())
                .build());
    // Gets the resource name that will be used for the condition other node.
    // This resource has not been created yet and will include the temporary ID as part of the
    // criterion ID.
    String adGroupCriterionResourceNameConditionOther =
        adGroupCriterionConditionOther.getResourceName();
    operations.add(
        AdGroupCriterionOperation.newBuilder().setCreate(adGroupCriterionConditionOther).build());

    // 4) Constructs the listing group unit nodes for CoolBrand, CheapBrand and other

    // Biddable Unit node: (Brand CoolBrand node)
    // * Brand: CoolBrand
    // * CPC bid: $0.90
    AdGroupCriterion adGroupCriterionBrandCoolBrand =
        createListingGroupUnitBiddable(
            customerId,
            adGroupId,
            adGroupCriterionResourceNameConditionOther,
            ListingDimensionInfo.newBuilder()
                .setProductBrand(ProductBrandInfo.newBuilder().setValue("CoolBrand").build())
                .build(),
            900_000L);
    operations.add(
        AdGroupCriterionOperation.newBuilder().setCreate(adGroupCriterionBrandCoolBrand).build());

    // Biddable Unit node: (Brand CheapBrand node)
    // * Brand: CheapBrand
    // * CPC bid: $0.01
    AdGroupCriterion adGroupCriterionBrandCheapBrand =
        createListingGroupUnitBiddable(
            customerId,
            adGroupId,
            adGroupCriterionResourceNameConditionOther,
            ListingDimensionInfo.newBuilder()
                .setProductBrand(ProductBrandInfo.newBuilder().setValue("CheapBrand").build())
                .build(),
            10_000L);
    operations.add(
        AdGroupCriterionOperation.newBuilder().setCreate(adGroupCriterionBrandCheapBrand).build());

    // Biddable Unit node: (Brand other node)
    // * Brand: CheapBrand
    // * CPC bid: $0.01
    AdGroupCriterion adGroupCriterionBrandOther =
        createListingGroupUnitBiddable(
            customerId,
            adGroupId,
            adGroupCriterionResourceNameConditionOther,
            ListingDimensionInfo.newBuilder()
                .setProductBrand(ProductBrandInfo.newBuilder().build())
                .build(),
            50_000L);
    operations.add(
        AdGroupCriterionOperation.newBuilder().setCreate(adGroupCriterionBrandOther).build());

    // Issues a mutate request to add the ad group criterion to the ad group.
    try (AdGroupCriterionServiceClient adGroupCriterionServiceClient =
        googleAdsClient.getLatestVersion().createAdGroupCriterionServiceClient()) {
      List<MutateAdGroupCriterionResult> mutateAdGroupCriteriaResults =
          adGroupCriterionServiceClient
              .mutateAdGroupCriteria(Long.toString(customerId), operations)
              .getResultsList();
      for (MutateAdGroupCriterionResult mutateAdGroupCriterionResult :
          mutateAdGroupCriteriaResults) {
        System.out.printf(
            "Added ad group criterion for listing group with resource name: '%s'%n",
            mutateAdGroupCriterionResult.getResourceName());
      }
    }
  }


  /**
   * Removes all the ad group criteria that define the existing listing group tree for an ad group.
   * Returns without an error if all listing group criterion are successfully removed.
   *
   * @param googleAdsClient the Google Ads API client.
   * @param customerId the client customer ID.
   * @param adGroupId the ID of the ad group that the new listing group tree will be removed from.
   * @throws GoogleAdsException if an API request failed with one or more service errors.
   */
  private void removeListingGroupTree(
      GoogleAdsClient googleAdsClient, long customerId, long adGroupId) {
    try (GoogleAdsServiceClient googleAdsServiceClient =
        googleAdsClient.getLatestVersion().createGoogleAdsServiceClient()) {
      String searchQuery =
          "SELECT ad_group_criterion.resource_name "
              + "FROM ad_group_criterion "
              + "WHERE ad_group_criterion.type = LISTING_GROUP "
              + "AND ad_group_criterion.listing_group.parent_ad_group_criterion IS NULL "
              + String.format("AND ad_group.id = %d", adGroupId);

      // Creates a request that will retrieve all listing groups where the parent ad group criterion
      // is NULL (and hence the root node in the tree) for a given ad group id.
      SearchGoogleAdsRequest request =
          SearchGoogleAdsRequest.newBuilder()
              .setCustomerId(Long.toString(customerId))
              .setQuery(searchQuery)
              .build();

      // Issues the search request.
      SearchPagedResponse searchPagedResponse = googleAdsServiceClient.search(request);
      // Iterates over all rows in all pages to find the ad group criterion to remove.
      for (GoogleAdsRow googleAdsRow : searchPagedResponse.iterateAll()) {
        AdGroupCriterion adGroupCriterion = googleAdsRow.getAdGroupCriterion();
        System.out.printf(
            "Found ad group criterion with the resource name: '%s'.%n",
            adGroupCriterion.getResourceName());

        AdGroupCriterionOperation operation =
            AdGroupCriterionOperation.newBuilder()
                .setRemove(adGroupCriterion.getResourceName())
                .build();

        try (AdGroupCriterionServiceClient adGroupCriterionServiceClient =
            googleAdsClient.getLatestVersion().createAdGroupCriterionServiceClient()) {
          MutateAdGroupCriteriaResponse response =
              adGroupCriterionServiceClient.mutateAdGroupCriteria(
                  Long.toString(customerId), Collections.singletonList(operation));
          System.out.printf("Removed %d ad group criteria.%n", response.getResultsCount());
        }
      }
    }
  }

  /**
   * Creates a new criterion containing a biddable unit listing group node.
   *
   * @param customerId the client customer ID.
   * @param adGroupId the ID of the ad group.
   * @param parentAdGroupCriterionResourceName the resource name of the parent of this criterion.
   * @param listingDimensionInfo the ListingDimensionInfo to be set for this listing group.
   * @param cpcBidMicros the CPC bid for items in this listing group. This value should be specified
   *     in micros.
   * @return the ad group criterion object that contains the biddable unit listing group node.
   */
  private AdGroupCriterion createListingGroupUnitBiddable(
      long customerId,
      long adGroupId,
      String parentAdGroupCriterionResourceName,
      ListingDimensionInfo listingDimensionInfo,
      long cpcBidMicros) {

    String adGroupResourceName = ResourceNames.adGroup(customerId, adGroupId);
    // Note: There are two approaches for creating new unit nodes:
    // (1) Set the ad group resource name on the criterion (no temporary ID required).
    // (2) Use a temporary ID to construct the criterion resource name and set it using
    // setResourceName.
    // In both cases you must set the parentAdGroupCriterionResourceName on the listing
    // group for non-root nodes.
    // This example demonstrates method (1).
    AdGroupCriterion adGroupCriterion =
        AdGroupCriterion.newBuilder()
            // The ad group the listing group will be attached to.
            .setAdGroup(adGroupResourceName)
            .setStatus(AdGroupCriterionStatus.ENABLED)
            .setListingGroup(
                ListingGroupInfo.newBuilder()
                    // Sets the type as a UNIT, which will allow the group to be biddable.
                    .setType(ListingGroupType.UNIT)
                    // Sets the ad group criterion resource name for the parent listing group.
                    // This can include a temporary ID if the parent criterion is not yet created.
                    // Use StringValue to convert from a String to a compatible argument type.
                    .setParentAdGroupCriterion(parentAdGroupCriterionResourceName)
                    // Case values contain the listing dimension used for the node.
                    .setCaseValue(listingDimensionInfo)
                    .build())
            // Sets the bid for this listing group unit.
            // This will be used as the CPC bid for items that are included in this listing group
            .setCpcBidMicros(cpcBidMicros)
            .build();

    return adGroupCriterion;
  }

  /**
   * Creates a new criterion containing a subdivision listing group node.
   *
   * @param customerId the client customer ID.
   * @param adGroupId the ID of the ad group.
   * @param adGroupCriterionId the ID of the criterion. This value will used to construct the
   *     resource name. This can be a negative number if the criterion is yet to be created.
   * @param parentAdGroupCriterionResourceName the resource name of the parent of this criterion.
   * @param listingDimensionInfo the ListingDimensionInfo to be set for this listing group.
   * @return the ad group criterion object that contains the subdivision listing group node.
   */
  private AdGroupCriterion createListingGroupSubdivision(
      long customerId,
      long adGroupId,
      long adGroupCriterionId,
      String parentAdGroupCriterionResourceName,
      ListingDimensionInfo listingDimensionInfo) {

    String adGroupCriterionResourceName =
        ResourceNames.adGroupCriterion(customerId, adGroupId, adGroupCriterionId);
    AdGroupCriterion adGroupCriterion =
        AdGroupCriterion.newBuilder()
            // The resource name the criterion will be created with. This will define the ID for the
            // ad group criterion.
            .setResourceName(adGroupCriterionResourceName)
            .setStatus(AdGroupCriterionStatus.ENABLED)
            .setListingGroup(
                ListingGroupInfo.newBuilder()
                    // Sets the type as a SUBDIVISION, which will allow the node to be the parent of
                    // another sub-tree.
                    .setType(ListingGroupType.SUBDIVISION)
                    // Sets the ad group criterion resource name for the parent listing group.
                    // This can include a temporary ID if the parent criterion is not yet created.
                    // Uses StringValue to convert from a String to a compatible argument type.
                    .setParentAdGroupCriterion(parentAdGroupCriterionResourceName)
                    // Case values contain the listing dimension used for the node.
                    .setCaseValue(listingDimensionInfo)
                    .build())
            .build();

    return adGroupCriterion;
  }

  /**
   * Creates a new criterion containing a root subdivision listing group node.
   *
   * @param customerId the client customer ID.
   * @param adGroupId the ID of the ad group.
   * @param adGroupCriterionId the ID of the criterion. This value will used to construct the
   *     resource name. This can be a negative number if the criterion is yet to be created.
   * @return the ad group criterion object that contains the listing group root node.
   */
  private AdGroupCriterion createListingGroupSubdivisionRoot(
      long customerId, long adGroupId, long adGroupCriterionId) {

    String adGroupCriterionResourceName =
        ResourceNames.adGroupCriterion(customerId, adGroupId, adGroupCriterionId);
    AdGroupCriterion adGroupCriterion =
        AdGroupCriterion.newBuilder()
            // The resource name the criterion will be created with. This will define the ID for the
            // ad group criterion.
            .setResourceName(adGroupCriterionResourceName)
            .setStatus(AdGroupCriterionStatus.ENABLED)
            .setListingGroup(
                ListingGroupInfo.newBuilder()
                    // Sets the type as a SUBDIVISION, which will allow the node to be the parent of
                    // another sub-tree.
                    .setType(ListingGroupType.SUBDIVISION)
                    .build())
            .build();

    return adGroupCriterion;
  }
}

      

C#

// Copyright 2019 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

using CommandLine;
using Google.Ads.Gax.Examples;
using Google.Ads.GoogleAds.Lib;
using Google.Ads.GoogleAds.V17.Common;
using Google.Ads.GoogleAds.V17.Errors;
using Google.Ads.GoogleAds.V17.Resources;
using Google.Ads.GoogleAds.V17.Services;
using System;
using System.Collections.Generic;
using System.Linq;
using static Google.Ads.GoogleAds.V17.Enums.AdGroupCriterionStatusEnum.Types;
using static Google.Ads.GoogleAds.V17.Enums.ListingGroupTypeEnum.Types;
using static Google.Ads.GoogleAds.V17.Enums.ProductConditionEnum.Types;

namespace Google.Ads.GoogleAds.Examples.V17
{
    /// <summary>
    /// This code example shows how to add a shopping listing group tree to a shopping ad group.
    /// The example will clear an existing listing group tree and rebuild it include the following
    /// tree structure:
    ///
    /// <code>
    /// ProductCanonicalCondition NEW $0.20
    /// ProductCanonicalCondition USED $0.10
    /// ProductCanonicalCondition null (everything else)
    ///  ProductBrand CoolBrand $0.90
    ///  ProductBrand CheapBrand $0.01
    ///  ProductBrand null (everything else) $0.50
    /// </code>
    /// </summary>
    public class AddShoppingProductListingGroupTree : ExampleBase
    {
        /// <summary>
        /// Command line options for running the <see cref="AddShoppingProductListingGroupTree"/>
        /// example.
        /// </summary>
        public class Options : OptionsBase
        {
            /// <summary>
            /// The Google Ads customer ID for which the call is made.
            /// </summary>
            [Option("customerId", Required = true, HelpText =
                "The Google Ads customer ID for which the call is made.")]
            public long CustomerId { get; set; }

            /// <summary>
            /// The ID of the ad group.
            /// </summary>
            [Option("adGroupId", Required = true, HelpText =
                "The ID of the ad group.")]
            public long AdGroupId { get; set; }

            /// <summary>
            /// The boolean to indicate whether to replace the existing listing group tree on the
            /// ad group, if it already exists. The example will throw a
            /// LISTING_GROUP_ALREADY_EXISTS error if listing group tree already exists and this
            /// option is not set to true.
            /// </summary>
            [Option("replaceExistingTree", Required = true, HelpText =
                "The boolean to indicate whether to replace the existing listing group tree on " +
                "the ad group, if it already exists. The example will throw a " +
                "LISTING_GROUP_ALREADY_EXISTS error if listing group tree already exists and " +
                "this option is not set to true.")]
            public bool ReplaceExistingTree { get; set; }
        }

        /// <summary>
        /// Main method, to run this code example as a standalone application.
        /// </summary>
        /// <param name="args">The command line arguments.</param>
        public static void Main(string[] args)
        {
            Options options = ExampleUtilities.ParseCommandLine<Options>(args);

            AddShoppingProductListingGroupTree codeExample =
                new AddShoppingProductListingGroupTree();
            Console.WriteLine(codeExample.Description);
            codeExample.Run(new GoogleAdsClient(), options.CustomerId, options.AdGroupId,
                options.ReplaceExistingTree);
        }

        /// <summary>
        /// Returns a description about the code example.
        /// </summary>
        public override string Description =>
            "This code example shows how to add a shopping listing group tree to a shopping ad " +
            "group. The example will clear an existing listing group tree and rebuild it include " +
            "the following tree structure:\n" +
            "ProductCanonicalCondition NEW $0.20\n" +
            "ProductCanonicalCondition USED $0.10\n" +
            "ProductCanonicalCondition null (everything else)\n" +
            "  ProductBrand CoolBrand $0.90\n" +
            "  ProductBrand CheapBrand $0.01\n" +
            "  ProductBrand null (everything else) $0.50\n";

        /// <summary>
        /// Runs the code example.
        /// </summary>
        /// <param name="client">The Google Ads client.</param>
        /// <param name="customerId">The Google Ads customer ID for which the call is made.</param>
        /// <param name="adGroupId">The ID of the ad group.</param>
        /// <param name="replaceExistingTree">The boolean to indicate whether to replace the
        /// existing listing group tree on the ad group, if it already exists. The example will
        /// throw a <code>LISTING_GROUP_ALREADY_EXISTS</code> error if listing group tree already
        /// exists and this option is not set to true.</param>
        public void Run(GoogleAdsClient client, long customerId, long adGroupId,
            bool replaceExistingTree)
        {
            // Get the AdGroupCriterionService.
            AdGroupCriterionServiceClient adGroupCriterionService =
                client.GetService(Services.V17.AdGroupCriterionService);

            try
            {
                // 1) Optional: Remove the existing listing group tree, if it already exists on the
                // ad group.
                if (replaceExistingTree)
                {
                    RemoveListingGroupTree(client, customerId, adGroupId);
                }
                // Create a list of ad group criterion to add
                List<AdGroupCriterionOperation> operations = new List<AdGroupCriterionOperation>();

                // 2) Construct the listing group tree "root" node.

                // Subdivision node: (Root node)
                AdGroupCriterion adGroupCriterionRoot = CreateListingGroupSubdivisionRoot(
                    customerId, adGroupId, -1L);

                // Get the resource name that will be used for the root node.
                // This resource has not been created yet and will include the temporary ID as
                // part of the criterion ID.
                String adGroupCriterionResourceNameRoot = adGroupCriterionRoot.ResourceName;
                operations.Add(new AdGroupCriterionOperation()
                {
                    Create = adGroupCriterionRoot
                });

                // 3) Construct the listing group unit nodes for NEW, USED and other

                // Biddable Unit node: (Condition NEW node)
                // * Product Condition: NEW
                // * CPC bid: $0.20
                AdGroupCriterion adGroupCriterionConditionNew =
                    CreateListingGroupUnitBiddable(
                        customerId,
                        adGroupId,
                        adGroupCriterionResourceNameRoot,
                        new ListingDimensionInfo()
                        {
                            ProductCondition = new ProductConditionInfo()
                            {
                                Condition = ProductCondition.New
                            }
                        },
                        200_000L);
                operations.Add(new AdGroupCriterionOperation()
                {
                    Create = adGroupCriterionConditionNew
                });

                // Biddable Unit node: (Condition USED node)
                // * Product Condition: USED
                // * CPC bid: $0.10
                AdGroupCriterion adGroupCriterionConditionUsed =
                    CreateListingGroupUnitBiddable(
                        customerId,
                        adGroupId,
                        adGroupCriterionResourceNameRoot,
                        new ListingDimensionInfo()
                        {
                            ProductCondition = new ProductConditionInfo()
                            {
                                Condition = ProductCondition.Used
                            }
                        },
                        100_000L
                    );
                operations.Add(new AdGroupCriterionOperation()
                {
                    Create = adGroupCriterionConditionUsed
                });

                // Sub-division node: (Condition "other" node)
                // * Product Condition: (not specified)
                AdGroupCriterion adGroupCriterionConditionOther =
                    CreateListingGroupSubdivision(
                        customerId,
                        adGroupId,
                        -2L,
                        adGroupCriterionResourceNameRoot,
                        new ListingDimensionInfo()
                        {
                            // All sibling nodes must have the same dimension type, even if they
                            // don't contain a bid.
                            ProductCondition = new ProductConditionInfo()
                        }
                    );
                // Get the resource name that will be used for the condition other node.
                // This resource has not been created yet and will include the temporary ID as
                // part of the criterion ID.
                String adGroupCriterionResourceNameConditionOther =
                    adGroupCriterionConditionOther.ResourceName;
                operations.Add(new AdGroupCriterionOperation()
                {
                    Create = adGroupCriterionConditionOther
                });

                // 4) Construct the listing group unit nodes for CoolBrand, CheapBrand and other

                // Biddable Unit node: (Brand CoolBrand node)
                // * Brand: CoolBrand
                // * CPC bid: $0.90
                AdGroupCriterion adGroupCriterionBrandCoolBrand =
                    CreateListingGroupUnitBiddable(
                        customerId,
                        adGroupId,
                        adGroupCriterionResourceNameConditionOther,
                        new ListingDimensionInfo()
                        {
                            ProductBrand = new ProductBrandInfo()
                            {
                                Value = "CoolBrand"
                            }
                        },
                        900_000L);
                operations.Add(new AdGroupCriterionOperation()
                {
                    Create = adGroupCriterionBrandCoolBrand
                });

                // Biddable Unit node: (Brand CheapBrand node)
                // * Brand: CheapBrand
                // * CPC bid: $0.01
                AdGroupCriterion adGroupCriterionBrandCheapBrand =
                    CreateListingGroupUnitBiddable(
                        customerId,
                        adGroupId,
                        adGroupCriterionResourceNameConditionOther,
                        new ListingDimensionInfo()
                        {
                            ProductBrand = new ProductBrandInfo()
                            {
                                Value = "CheapBrand"
                            }
                        },
                        10_000L);

                operations.Add(new AdGroupCriterionOperation()
                {
                    Create = adGroupCriterionBrandCheapBrand
                });

                // Biddable Unit node: (Brand other node)
                // * Brand: CheapBrand
                // * CPC bid: $0.01
                AdGroupCriterion adGroupCriterionBrandOther =
                    CreateListingGroupUnitBiddable(
                        customerId,
                        adGroupId,
                        adGroupCriterionResourceNameConditionOther,
                        new ListingDimensionInfo()
                        {
                            ProductBrand = new ProductBrandInfo()
                        },
                        50_000L);
                operations.Add(new AdGroupCriterionOperation()
                {
                    Create = adGroupCriterionBrandOther
                });

                // Issues a mutate request to add the ad group criterion to the ad group.
                MutateAdGroupCriteriaResponse response =
                    adGroupCriterionService.MutateAdGroupCriteria(
                        customerId.ToString(), operations);

                // Display the results.
                foreach (MutateAdGroupCriterionResult mutateAdGroupCriterionResult
                    in response.Results)
                {
                    Console.WriteLine("Added ad group criterion for listing group with resource " +
                        $"name: '{mutateAdGroupCriterionResult.ResourceName}.");
                }
            }
            catch (GoogleAdsException e)
            {
                Console.WriteLine("Failure:");
                Console.WriteLine($"Message: {e.Message}");
                Console.WriteLine($"Failure: {e.Failure}");
                Console.WriteLine($"Request ID: {e.RequestId}");
                throw;
            }
        }

        /// <summary>
        /// Removes all the ad group criteria that define the existing listing group tree for an
        /// ad group. Returns without an error if all listing group criterion are successfully
        /// removed.
        /// </summary>
        /// <param name="client">The Google Ads API client..</param>
        /// <param name="customerId">The client customer ID.</param>
        /// <param name="adGroupId">The ID of the ad group that the new listing group tree will
        /// be removed from.</param>
        /// <exception cref="GoogleAdsException">Thrown if an API request failed with one or more
        /// service errors.</exception>
        private void RemoveListingGroupTree(GoogleAdsClient client, long customerId,
            long adGroupId)
        {
            // Get the GoogleAdsService.
            GoogleAdsServiceClient googleAdsService = client.GetService(
                Services.V17.GoogleAdsService);

            // Get the AdGroupCriterionService.
            AdGroupCriterionServiceClient adGroupCriterionService =
                client.GetService(Services.V17.AdGroupCriterionService);

            String searchQuery = "SELECT ad_group_criterion.resource_name FROM " +
                "ad_group_criterion WHERE ad_group_criterion.type = LISTING_GROUP AND " +
                "ad_group_criterion.listing_group.parent_ad_group_criterion IS NULL " +
                $"AND ad_group.id = {adGroupId}";

            // Creates a request that will retrieve all listing groups where the parent ad group
            // criterion is NULL (and hence the root node in the tree) for a given ad group ID.
            SearchGoogleAdsRequest request = new SearchGoogleAdsRequest()
            {
                CustomerId = customerId.ToString(),
                Query = searchQuery
            };

            // Issues the search request.
            GoogleAdsRow googleAdsRow = googleAdsService.Search(request).FirstOrDefault();

            if (googleAdsRow == null)
            {
                return;
            }

            AdGroupCriterion adGroupCriterion = googleAdsRow.AdGroupCriterion;
            Console.WriteLine("Found ad group criterion with the resource name: '{0}'.",
                adGroupCriterion.ResourceName);

            AdGroupCriterionOperation operation = new AdGroupCriterionOperation()
            {
                Remove = adGroupCriterion.ResourceName
            };

            MutateAdGroupCriteriaResponse response =
                adGroupCriterionService.MutateAdGroupCriteria(
                    customerId.ToString(), new AdGroupCriterionOperation[] { operation });
            Console.WriteLine($"Removed {response.Results.Count}.");
        }

        /// <summary>
        /// Creates a new criterion containing a biddable unit listing group node.
        /// </summary>
        /// <param name="customerId">The client customer ID.</param>
        /// <param name="adGroupId">The ID of the ad group.</param>
        /// <param name="parentAdGroupCriterionResourceName">The resource name of the parent of
        /// this criterion.</param>
        /// <param name="listingDimensionInfo">The ListingDimensionInfo to be set for this listing
        /// group.</param>
        /// <param name="cpcBidMicros">The CPC bid for items in this listing group. This value
        /// should be specified in micros.</param>
        /// <returns>The ad group criterion object that contains the biddable unit listing group
        /// node.</returns>
        private AdGroupCriterion CreateListingGroupUnitBiddable(long customerId, long adGroupId,
            String parentAdGroupCriterionResourceName, ListingDimensionInfo listingDimensionInfo,
            long cpcBidMicros)
        {
            String adGroupResourceName = ResourceNames.AdGroup(customerId, adGroupId);
            AdGroupCriterion adGroupCriterion = new AdGroupCriterion()
            {
                // The resource name the ad group the listing group node will be attached to unit.
                // Note: Listing group units do not require temporary IDs if ad group resource name
                // and parentAdGroupCriterionResourceName are specified. To use temporary IDs for
                // unit criteria, use ResourceName property.
                AdGroup = adGroupResourceName,
                Status = AdGroupCriterionStatus.Enabled,
                ListingGroup = new ListingGroupInfo()
                {
                    // Set the type as a UNIT, which will allow the group to be biddable
                    Type = ListingGroupType.Unit,

                    // Set the ad group criterion resource name for the parent listing group.
                    // This can include a criterion ID if the parent criterion is not yet created.
                    // Use StringValue to convert from a String to a compatible argument type.
                    ParentAdGroupCriterion = parentAdGroupCriterionResourceName,

                    // Case values contain the listing dimension used for the node.
                    CaseValue = listingDimensionInfo
                },

                // Set the bid for this listing group unit.
                // This will be used as the CPC bid for items that are included in this
                // listing group
                CpcBidMicros = cpcBidMicros
            };
            return adGroupCriterion;
        }

        /// <summary>
        /// Creates a new criterion containing a subdivision listing group node.
        /// </summary>
        /// <param name="customerId">The client customer ID.</param>
        /// <param name="adGroupId">The ID of the ad group.</param>
        /// <param name="adGroupCriterionId">The ID of the criterion. This value will used to
        /// construct the resource name. This can be a negative number if the criterion is yet to
        /// be created.</param>
        /// <param name="parentAdGroupCriterionResourceName">The resource name of the parent of
        /// this criterion.</param>
        /// <param name="listingDimensionInfo">The ListingDimensionInfo to be set for this listing
        /// group.</param>
        /// <returns>The ad group criterion object that contains the subdivision listing group
        /// node.</returns>
        private AdGroupCriterion CreateListingGroupSubdivision(long customerId, long adGroupId,
            long adGroupCriterionId, String parentAdGroupCriterionResourceName,
            ListingDimensionInfo listingDimensionInfo)
        {
            String adGroupCriterionResourceName = ResourceNames.AdGroupCriterion(
                customerId, adGroupId, adGroupCriterionId);

            AdGroupCriterion adGroupCriterion = new AdGroupCriterion()
            {
                // The resource name the criterion will be created with. This will define the
                // ID for the ad group criterion.
                ResourceName = adGroupCriterionResourceName,
                Status = AdGroupCriterionStatus.Enabled,
                ListingGroup = new ListingGroupInfo()
                {
                    Type = ListingGroupType.Subdivision,

                    // Set the ad group criterion resource name for the parent listing group.
                    // This can include a criterion ID if the parent criterion is not yet created.
                    // Use StringValue to convert from a String to a compatible argument type.
                    ParentAdGroupCriterion = parentAdGroupCriterionResourceName,

                    // Case values contain the listing dimension used for the node.
                    CaseValue = listingDimensionInfo
                }
            };

            return adGroupCriterion;
        }

        /// <summary>
        /// Creates a new criterion containing a root subdivision listing group node.
        /// </summary>
        /// <param name="customerId">The client customer ID.</param>
        /// <param name="adGroupId">The ID of the ad group.</param>
        /// <param name="adGroupCriterionId">The ID of the criterion. This value will used to
        /// construct the resource name. This can be a negative number if the criterion is yet
        /// to be created.</param>
        /// <returns>The ad group criterion object that contains the listing group root node.
        /// </returns>
        private AdGroupCriterion CreateListingGroupSubdivisionRoot(long customerId, long adGroupId,
            long adGroupCriterionId)
        {
            String adGroupCriterionResourceName = ResourceNames.AdGroupCriterion(customerId,
                adGroupId, adGroupCriterionId);

            AdGroupCriterion adGroupCriterion = new AdGroupCriterion()
            {
                // The resource name the criterion will be created with. This will define the ID
                // for the ad group criterion.
                ResourceName = adGroupCriterionResourceName,
                Status = AdGroupCriterionStatus.Enabled,
                ListingGroup = new ListingGroupInfo()
                {
                    // Set the type as a SUBDIVISION, which will allow the node to be the parent of
                    // another sub-tree.
                    Type = ListingGroupType.Subdivision
                }
            };
            return adGroupCriterion;
        }
    }
}

      

PHP

<?php

/**
 * Copyright 2018 Google LLC
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

namespace Google\Ads\GoogleAds\Examples\ShoppingAds;

require __DIR__ . '/../../vendor/autoload.php';

use GetOpt\GetOpt;
use Google\Ads\GoogleAds\Examples\Utils\ArgumentNames;
use Google\Ads\GoogleAds\Examples\Utils\ArgumentParser;
use Google\Ads\GoogleAds\Lib\V17\GoogleAdsClient;
use Google\Ads\GoogleAds\Lib\V17\GoogleAdsClientBuilder;
use Google\Ads\GoogleAds\Lib\V17\GoogleAdsException;
use Google\Ads\GoogleAds\Lib\OAuth2TokenBuilder;
use Google\Ads\GoogleAds\Util\V17\ResourceNames;
use Google\Ads\GoogleAds\V17\Common\ProductBrandInfo;
use Google\Ads\GoogleAds\V17\Common\ListingDimensionInfo;
use Google\Ads\GoogleAds\V17\Common\ListingGroupInfo;
use Google\Ads\GoogleAds\V17\Common\ProductConditionInfo;
use Google\Ads\GoogleAds\V17\Enums\AdGroupCriterionStatusEnum\AdGroupCriterionStatus;
use Google\Ads\GoogleAds\V17\Enums\ListingGroupTypeEnum\ListingGroupType;
use Google\Ads\GoogleAds\V17\Enums\ProductConditionEnum\ProductCondition;
use Google\Ads\GoogleAds\V17\Errors\GoogleAdsError;
use Google\Ads\GoogleAds\V17\Resources\AdGroupCriterion;
use Google\Ads\GoogleAds\V17\Services\AdGroupCriterionOperation;
use Google\Ads\GoogleAds\V17\Services\GoogleAdsRow;
use Google\Ads\GoogleAds\V17\Services\MutateAdGroupCriteriaRequest;
use Google\Ads\GoogleAds\V17\Services\SearchGoogleAdsRequest;
use Google\ApiCore\ApiException;

/**
 * This example shows how to add a shopping listing group tree to a shopping ad group. The example
 * will optionally clear an existing listing group tree and rebuild it to include the following tree
 * structure:
 *
 * <pre>
 * ProductCanonicalCondition NEW $0.20
 * ProductCanonicalCondition USED $0.10
 * ProductCanonicalCondition null (everything else)
 *  ProductBrand CoolBrand $0.90
 *  ProductBrand CheapBrand $0.01
 *  ProductBrand null (everything else) $0.50
 * </pre>
 */
class AddShoppingProductListingGroupTree
{
    private const CUSTOMER_ID = 'INSERT_CUSTOMER_ID_HERE';
    private const AD_GROUP_ID = 'INSERT_AD_GROUP_ID_HERE';
    private const REPLACE_EXISTING_TREE = 'INSERT_BOOLEAN_TRUE_OR_FALSE_HERE';

    public static function main()
    {
        // Either pass the required parameters for this example on the command line, or insert them
        // into the constants above.
        $options = (new ArgumentParser())->parseCommandArguments([
            ArgumentNames::CUSTOMER_ID => GetOpt::REQUIRED_ARGUMENT,
            ArgumentNames::AD_GROUP_ID => GetOpt::REQUIRED_ARGUMENT,
            ArgumentNames::REPLACE_EXISTING_TREE => GetOpt::REQUIRED_ARGUMENT
        ]);

        // Generate a refreshable OAuth2 credential for authentication.
        $oAuth2Credential = (new OAuth2TokenBuilder())->fromFile()->build();

        // Construct a Google Ads client configured from a properties file and the
        // OAuth2 credentials above.
        $googleAdsClient = (new GoogleAdsClientBuilder())->fromFile()
            ->withOAuth2Credential($oAuth2Credential)
            // We set this value to true to show how to use GAPIC v2 source code. You can remove the
            // below line if you wish to use the old-style source code. Note that in that case, you
            // probably need to modify some parts of the code below to make it work.
            // For more information, see
            // https://developers.devsite.corp.google.com/google-ads/api/docs/client-libs/php/gapic.
            ->usingGapicV2Source(true)
            ->build();

        try {
            self::runExample(
                $googleAdsClient,
                $options[ArgumentNames::CUSTOMER_ID] ?: self::CUSTOMER_ID,
                $options[ArgumentNames::AD_GROUP_ID]
                    ?: self::AD_GROUP_ID,
                $options[ArgumentNames::REPLACE_EXISTING_TREE]
                    ?: self::REPLACE_EXISTING_TREE
            );
        } catch (GoogleAdsException $googleAdsException) {
            printf(
                "Request with ID '%s' has failed.%sGoogle Ads failure details:%s",
                $googleAdsException->getRequestId(),
                PHP_EOL,
                PHP_EOL
            );
            foreach ($googleAdsException->getGoogleAdsFailure()->getErrors() as $error) {
                /** @var GoogleAdsError $error */
                printf(
                    "\t%s: %s%s",
                    $error->getErrorCode()->getErrorCode(),
                    $error->getMessage(),
                    PHP_EOL
                );
            }
            exit(1);
        } catch (ApiException $apiException) {
            printf(
                "ApiException was thrown with message '%s'.%s",
                $apiException->getMessage(),
                PHP_EOL
            );
            exit(1);
        }
    }

    /**
     * Runs the example.
     *
     * @param GoogleAdsClient $googleAdsClient the Google Ads API client
     * @param int $customerId the customer ID
     * @param int $adGroupId the ad group ID
     * @param bool $replaceExistingTree true if it should replace the existing listing group
     *     tree on the ad group, if it already exists. The example will throw a
     *     'LISTING_GROUP_ALREADY_EXISTS' error if listing group tree already exists and this option
     *     is not set to true
     */
    public static function runExample(
        GoogleAdsClient $googleAdsClient,
        int $customerId,
        int $adGroupId,
        bool $replaceExistingTree
    ) {
        // 1) Optional: Remove the existing listing group tree, if it already exists on the ad
        // group.
        if ($replaceExistingTree === 'true') {
            self::removeListingGroupTree($googleAdsClient, $customerId, $adGroupId);
        }
        // Create a list of ad group criteria to add.
        $operations = [];

        // 2) Construct the listing group tree "root" node.

        // Subdivision node: (Root node)
        $adGroupCriterionRoot = self::createListingGroupSubdivision($customerId, $adGroupId);
        // Get the resource name that will be used for the root node.
        // This resource has not been created yet and will include the temporary ID as part of the
        // criterion ID.
        $adGroupCriterionResourceNameRoot = $adGroupCriterionRoot->getResourceName();
        $operations[] = new AdGroupCriterionOperation(['create' => $adGroupCriterionRoot]);

        // 3) Construct the listing group unit nodes for NEW, USED and other.

        // Biddable Unit node: (Condition NEW node)
        // * Product Condition: NEW
        // * CPC bid: $0.20
        $adGroupCriterionConditionNew = self::createListingGroupUnitBiddable(
            $customerId,
            $adGroupId,
            $adGroupCriterionResourceNameRoot,
            new ListingDimensionInfo([
                'product_condition' => new ProductConditionInfo(
                    ['condition' => ProductCondition::PBNEW]
                )
            ]),
            200000
        );
        $operations[] = new AdGroupCriterionOperation(['create' => $adGroupCriterionConditionNew]);

        // Biddable Unit node: (Condition USED node)
        // * Product Condition: USED
        // * CPC bid: $0.10
        $adGroupCriterionConditionUsed = self::createListingGroupUnitBiddable(
            $customerId,
            $adGroupId,
            $adGroupCriterionResourceNameRoot,
            new ListingDimensionInfo([
                'product_condition' => new ProductConditionInfo(
                    ['condition' => ProductCondition::USED]
                )
            ]),
            100000
        );
        $operations[] = new AdGroupCriterionOperation(['create' => $adGroupCriterionConditionUsed]);

        // Sub-division node: (Condition "other" node)
        // * Product Condition: (not specified)
        $adGroupCriterionConditionOther = self::createListingGroupSubdivision(
            $customerId,
            $adGroupId,
            $adGroupCriterionResourceNameRoot,
            new ListingDimensionInfo([
                // All sibling nodes must have the same dimension type, even if they don't contain a
                // bid.
                'product_condition' => new ProductConditionInfo()
            ])
        );
        $operations[] =
            new AdGroupCriterionOperation(['create' => $adGroupCriterionConditionOther]);

        // Get the resource name that will be used for the condition other node.
        // This resource has not been created yet and will include the temporary ID as part of the
        // criterion ID.
        $adGroupCriterionResourceNameConditionOther =
            $adGroupCriterionConditionOther->getResourceName();

        // 4) Construct the listing group unit nodes for CoolBrand, CheapBrand and other.

        // Biddable Unit node: (Brand CoolBrand node)
        // * Brand: CoolBrand
        // * CPC bid: $0.90
        $adGroupCriterionBrandCoolBrand = self::createListingGroupUnitBiddable(
            $customerId,
            $adGroupId,
            $adGroupCriterionResourceNameConditionOther,
            new ListingDimensionInfo([
                'product_brand' => new ProductBrandInfo(['value' => 'CoolBrand'])
            ]),
            900000
        );
        $operations[] =
            new AdGroupCriterionOperation(['create' => $adGroupCriterionBrandCoolBrand]);

        // Biddable Unit node: (Brand CheapBrand node)
        // * Brand: CheapBrand
        // * CPC bid: $0.01
        $adGroupCriterionBrandCheapBrand = self::createListingGroupUnitBiddable(
            $customerId,
            $adGroupId,
            $adGroupCriterionResourceNameConditionOther,
            new ListingDimensionInfo([
                'product_brand' => new ProductBrandInfo(['value' => 'CheapBrand'])
            ]),
            10000
        );
        $operations[] =
            new AdGroupCriterionOperation(['create' => $adGroupCriterionBrandCheapBrand]);

        // Biddable Unit node: (Brand other node)
        // * CPC bid: $0.05
        $adGroupCriterionBrandOtherBrand = self::createListingGroupUnitBiddable(
            $customerId,
            $adGroupId,
            $adGroupCriterionResourceNameConditionOther,
            new ListingDimensionInfo([
                'product_brand' => new ProductBrandInfo()
            ]),
            50000
        );
        $operations[] =
            new AdGroupCriterionOperation(['create' => $adGroupCriterionBrandOtherBrand]);

        // Issues a mutate request.
        $adGroupCriterionServiceClient = $googleAdsClient->getAdGroupCriterionServiceClient();
        $response = $adGroupCriterionServiceClient->mutateAdGroupCriteria(
            MutateAdGroupCriteriaRequest::build($customerId, $operations)
        );
        printf(
            'Added %d ad group criteria for listing group tree with the following resource '
            . 'names:%s',
            $response->getResults()->count(),
            PHP_EOL
        );
        foreach ($response->getResults() as $addedAdGroupCriterion) {
            /** @var AdGroupCriterion $addedAdGroupCriterion */
            print $addedAdGroupCriterion->getResourceName() . PHP_EOL;
        }
    }

    /**
     * Removes all the ad group criteria that define the existing listing group tree for an ad
     * group.
     *
     * @param GoogleAdsClient $googleAdsClient the Google Ads API client
     * @param int $customerId the customer ID
     * @param int $adGroupId the ID of ad group that the existing listing group tree will be
     *     removed from
     */
    private static function removeListingGroupTree(
        GoogleAdsClient $googleAdsClient,
        int $customerId,
        int $adGroupId
    ) {
        $googleAdsServiceClient = $googleAdsClient->getGoogleAdsServiceClient();
        // Creates a query that retrieves a listing group tree.
        $query = 'SELECT ad_group_criterion.resource_name '
            . 'FROM ad_group_criterion '
            . 'WHERE ad_group_criterion.type = LISTING_GROUP '
            . 'AND ad_group_criterion.listing_group.parent_ad_group_criterion IS NULL '
            . 'AND ad_group.id = ' . $adGroupId;

        // Issues a search request.
        $response =
            $googleAdsServiceClient->search(SearchGoogleAdsRequest::build($customerId, $query));

        $operations = [];
        // Iterates over all rows in all pages and prints the requested field values for
        // the listing group tree in each row.
        foreach ($response->iterateAllElements() as $googleAdsRow) {
            /** @var GoogleAdsRow $googleAdsRow */
            $adGroupCriterion = $googleAdsRow->getAdGroupCriterion();
            printf(
                "Found an ad group criterion with the resource name: '%s'.%s",
                $adGroupCriterion->getResourceName(),
                PHP_EOL
            );

            // Creates an ad group criterion operation.
            $adGroupCriterionOperation = new AdGroupCriterionOperation();
            $adGroupCriterionOperation->setRemove($adGroupCriterion->getResourceName());
            $operations[] = $adGroupCriterionOperation;
        }
        if (count($operations) > 0) {
            // Issues a mutate request.
            $adGroupCriterionServiceClient = $googleAdsClient->getAdGroupCriterionServiceClient();
            $response = $adGroupCriterionServiceClient->mutateAdGroupCriteria(
                MutateAdGroupCriteriaRequest::build($customerId, $operations)
            );
            printf("Removed %d ad group criteria.%s", $response->getResults()->count(), PHP_EOL);
        }
    }

    /**
     * Creates a new criterion containing a subdivision listing group node. If the parent ad group
     * criterion resource name is not specified, this method creates a root node.
     *
     * @param int $customerId the customer ID
     * @param int $adGroupId the ad group ID
     * @param string|null $parentAdGroupCriterionResourceName the resource name of the parent of
     *     this criterion. If null, this method will create a root of the tree
     * @param ListingDimensionInfo|null $listingDimensionInfo the listing dimension info to be set
     *     for this listing group. This is required for non-root subdivisions
     * @return AdGroupCriterion the ad group criterion that contains the listing group root node
     */
    private static function createListingGroupSubdivision(
        int $customerId,
        int $adGroupId,
        string $parentAdGroupCriterionResourceName = null,
        ListingDimensionInfo $listingDimensionInfo = null
    ) {
        static $tempId = 0;
        $listingGroupInfo = new ListingGroupInfo([
            // Set the type as a SUBDIVISION, which will allow the node to be the parent of
            // another sub-tree.
            'type' => ListingGroupType::SUBDIVISION
        ]);
        // If $parentAdGroupCriterionResourceName and $listingDimensionInfo are not null, create
        // a non-root division by setting its parent and case value.
        if (!is_null($parentAdGroupCriterionResourceName) && !is_null($listingDimensionInfo)) {
            // Set the ad group criterion resource name for the parent listing group.
            // This can include a temporary ID if the parent criterion is not yet created.
            $listingGroupInfo->setParentAdGroupCriterion($parentAdGroupCriterionResourceName);
            // Case values contain the listing dimension used for the node.
            $listingGroupInfo->setCaseValue($listingDimensionInfo);
        }

        $adGroupCriterion = new AdGroupCriterion([
            // The resource name the criterion will be created with. This will define the ID for the
            // ad group criterion.
            'resource_name' => ResourceNames::forAdGroupCriterion(
                $customerId,
                $adGroupId,
                // Specify a decreasing negative number as a temporary ad group criterion ID. The
                // ad group criterion will get the real ID when created on the server.
                --$tempId
            ),
            'status' => AdGroupCriterionStatus::ENABLED,
            'listing_group' => $listingGroupInfo
        ]);

        return $adGroupCriterion;
    }

    /**
     * Creates a new criterion containing a biddable unit listing group node.
     *
     * @param int $customerId the customer ID
     * @param int $adGroupId the ad group ID
     * @param string $parentAdGroupCriterionResourceName the resource name of the parent of this
     *     criterion
     * @param ListingDimensionInfo $listingDimensionInfo the listing dimension info to be set for
     *     this listing group
     * @param int $cpcBidMicros the CPC bid for items in this listing group. This value should be
     *     specified
     * @return AdGroupCriterion the ad group criterion that contains the biddable unit listing
     *     group node
     */
    private static function createListingGroupUnitBiddable(
        int $customerId,
        int $adGroupId,
        string $parentAdGroupCriterionResourceName,
        ListingDimensionInfo $listingDimensionInfo,
        int $cpcBidMicros
    ) {
        // Note: There are two approaches for creating new unit nodes:
        // (1) Set the ad group resource name on the criterion (no temporary ID required).
        // (2) Use a temporary ID to construct the criterion resource name and set it using
        // setResourceName.
        // In both cases you must set the parentAdGroupCriterionResourceName on the listing
        // group for non-root nodes.
        // This example demonstrates method (1).
        $adGroupCriterion = new AdGroupCriterion([
            // The ad group the listing group will be attached to.
            'ad_group' => ResourceNames::forAdGroup($customerId, $adGroupId),
            'status' => AdGroupCriterionStatus::ENABLED,
            'listing_group' => new ListingGroupInfo([
                // Set the type as a UNIT, which will allow the group to be biddable.
                'type' => ListingGroupType::UNIT,
                // Set the ad group criterion resource name for the parent listing group.
                // This can include a temporary ID if the parent criterion is not yet created.
                'parent_ad_group_criterion' => $parentAdGroupCriterionResourceName,
                // Case values contain the listing dimension used for the node.
                'case_value' => $listingDimensionInfo
            ]),
            // Set the bid for this listing group unit.
            // This will be used as the CPC bid for items that are included in this listing group.
            'cpc_bid_micros' => $cpcBidMicros
        ]);

        return $adGroupCriterion;
    }
}

AddShoppingProductListingGroupTree::main();

      

Python

#!/usr/bin/env python
# Copyright 2020 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""Adds a shopping listing group tree to a shopping ad group.

The example will clear an existing listing group tree and rebuild it include the
following tree structure:

ProductCanonicalCondition NEW $0.20
ProductCanonicalCondition USED $0.10
ProductCanonicalCondition null (everything else)
    ProductBrand CoolBrand $0.90
    ProductBrand CheapBrand $0.01
    ProductBrand null (everything else) $0.50
"""

import argparse
import sys

from google.ads.googleads.client import GoogleAdsClient
from google.ads.googleads.errors import GoogleAdsException

last_criterion_id = 0


def next_id():
    """Returns a decreasing negative number for temporary ad group criteria IDs.

    The ad group criteria will get real IDs when created on the server.
    Returns -1, -2, -3, etc. on subsequent calls.

    Returns:
        The string representation of a negative integer.
    """
    global last_criterion_id
    last_criterion_id -= 1
    return str(last_criterion_id)


def main(client, customer_id, ad_group_id, replace_existing_tree):
    """Adds a shopping listing group tree to a shopping ad group.

    Args:
        client: An initialized Google Ads client.
        customer_id: The Google Ads customer ID.
        ad_group_id: The ad group ID to which the node will be added.
        replace_existing_tree: Boolean, whether to replace the existing listing
            group tree on the ad group. Defaults to false.
    """
    # Get the AdGroupCriterionService client.
    ad_group_criterion_service = client.get_service("AdGroupCriterionService")

    # Optional: Remove the existing listing group tree, if it already exists
    # on the ad group. The example will throw a LISTING_GROUP_ALREADY_EXISTS
    # error if a listing group tree already exists and this option is not
    # set to true.
    if replace_existing_tree:
        remove_listing_group_tree(client, customer_id, ad_group_id)

    # Create a list of ad group criteria operations.
    operations = []

    # Construct the listing group tree "root" node.
    # Subdivision node: (Root node)
    ad_group_criterion_root_operation = create_listing_group_subdivision(
        client, customer_id, ad_group_id
    )

    # Get the resource name that will be used for the root node.
    # This resource has not been created yet and will include the temporary
    # ID as part of the criterion ID.
    ad_group_criterion_root_resource_name = (
        ad_group_criterion_root_operation.create.resource_name
    )
    operations.append(ad_group_criterion_root_operation)

    # Construct the listing group unit nodes for NEW, USED, and other.
    product_condition_enum = client.enums.ProductConditionEnum
    condition_dimension_info = client.get_type("ListingDimensionInfo")

    # Biddable Unit node: (Condition NEW node)
    # * Product Condition: NEW
    # * CPC bid: $0.20
    condition_dimension_info.product_condition.condition = (
        product_condition_enum.NEW
    )
    operations.append(
        create_listing_group_unit_biddable(
            client,
            customer_id,
            ad_group_id,
            ad_group_criterion_root_resource_name,
            condition_dimension_info,
            200_000,
        )
    )

    # Biddable Unit node: (Condition USED node)
    # * Product Condition: USED
    # * CPC bid: $0.10
    condition_dimension_info.product_condition.condition = (
        product_condition_enum.USED
    )
    operations.append(
        create_listing_group_unit_biddable(
            client,
            customer_id,
            ad_group_id,
            ad_group_criterion_root_resource_name,
            condition_dimension_info,
            100_000,
        )
    )

    # Sub-division node: (Condition "other" node)
    # * Product Condition: (not specified)
    # Note that all sibling nodes must have the same dimension type, even if
    # they don't contain a bid.
    client.copy_from(
        condition_dimension_info.product_condition,
        client.get_type("ProductConditionInfo"),
    )
    ad_group_criterion_other_operation = create_listing_group_subdivision(
        client,
        customer_id,
        ad_group_id,
        ad_group_criterion_root_resource_name,
        condition_dimension_info,
    )
    # Get the resource name that will be used for the condition other node.
    # This resource has not been created yet and will include the temporary
    # ID as part of the criterion ID.
    ad_group_criterion_other_resource_name = (
        ad_group_criterion_other_operation.create.resource_name
    )
    operations.append(ad_group_criterion_other_operation)

    # Build the listing group nodes for CoolBrand, CheapBrand, and other.
    brand_dimension_info = client.get_type("ListingDimensionInfo")

    # Biddable Unit node: (Brand CoolBrand node)
    # * Brand: CoolBrand
    # * CPC bid: $0.90
    brand_dimension_info.product_brand.value = "CoolBrand"
    operations.append(
        create_listing_group_unit_biddable(
            client,
            customer_id,
            ad_group_id,
            ad_group_criterion_other_resource_name,
            brand_dimension_info,
            900_000,
        )
    )

    # Biddable Unit node: (Brand CheapBrand node)
    # * Brand: CheapBrand
    # * CPC bid: $0.01
    brand_dimension_info.product_brand.value = "CheapBrand"
    operations.append(
        create_listing_group_unit_biddable(
            client,
            customer_id,
            ad_group_id,
            ad_group_criterion_other_resource_name,
            brand_dimension_info,
            10_000,
        )
    )

    # Biddable Unit node: (Brand other node)
    # * CPC bid: $0.05
    client.copy_from(
        brand_dimension_info.product_brand,
        client.get_type("ProductBrandInfo"),
    )
    operations.append(
        create_listing_group_unit_biddable(
            client,
            customer_id,
            ad_group_id,
            ad_group_criterion_other_resource_name,
            brand_dimension_info,
            50_000,
        )
    )

    # Add the ad group criteria.
    mutate_ad_group_criteria_response = (
        ad_group_criterion_service.mutate_ad_group_criteria(
            customer_id=customer_id, operations=operations
        )
    )

    # Print the results of the successful mutates.
    print(
        "Added ad group criteria for the listing group tree with the "
        "following resource names:"
    )
    for result in mutate_ad_group_criteria_response.results:
        print(f"\t{result.resource_name}")

    print(f"{len(mutate_ad_group_criteria_response.results)} criteria added.")


def remove_listing_group_tree(client, customer_id, ad_group_id):
    """Removes ad group criteria for an ad group's existing listing group tree.

    Args:
        client: An initialized Google Ads client.
        customer_id: The Google Ads customer ID.
        ad_group_id: The ad group ID from which to remove the listing group
            tree.
    """
    # Get the GoogleAdsService client.
    googleads_service = client.get_service("GoogleAdsService")

    print("Removing existing listing group tree...")
    # Create a search Google Ads request that will retrieve all listing groups
    # where the parent ad group criterion is NULL (and hence the root node in
    # the tree) for a given ad group id.
    query = f"""
        SELECT ad_group_criterion.resource_name
        FROM ad_group_criterion
        WHERE
          ad_group_criterion.type = LISTING_GROUP
          AND ad_group_criterion.listing_group.parent_ad_group_criterion IS NULL
          AND ad_group.id = {ad_group_id}"""

    results = googleads_service.search(customer_id=customer_id, query=query)
    ad_group_criterion_operations = []

    # Iterate over all rows to find the ad group criteria to remove.
    for row in results:
        criterion = row.ad_group_criterion
        print(
            "Found an ad group criterion with resource name: "
            f"'{criterion.resource_name}'."
        )
        ad_group_criterion_operation = client.get_type(
            "AdGroupCriterionOperation"
        )
        ad_group_criterion_operation.remove = criterion.resource_name
        ad_group_criterion_operations.append(ad_group_criterion_operation)

    if ad_group_criterion_operations:
        # Remove the ad group criteria that define the listing group tree.
        ad_group_criterion_service = client.get_service(
            "AdGroupCriterionService"
        )
        response = ad_group_criterion_service.mutate_ad_group_criteria(
            customer_id=customer_id, operations=ad_group_criterion_operations
        )
        print(f"Removed {len(response.results)} ad group criteria.")


def create_listing_group_subdivision(
    client,
    customer_id,
    ad_group_id,
    parent_ad_group_criterion_resource_name=None,
    listing_dimension_info=None,
):
    """Creates a new criterion containing a subdivision listing group node.

    If the parent ad group criterion resource name or listing dimension info are
    not specified, this method creates a root node.

    Args:
        client: An initialized Google Ads client.
        customer_id: The Google Ads customer ID.
        ad_group_id: The ad group ID to which the node will be added.
        parent_ad_group_criterion_resource_name: The string resource name of the
            parent node to which this listing will be attached.
        listing_dimension_info: A ListingDimensionInfo object containing details
            for this listing.

    Returns:
        An AdGroupCriterionOperation containing a populated ad group criterion.
    """
    # Create an ad group criterion operation and populate the criterion.
    operation = client.get_type("AdGroupCriterionOperation")
    ad_group_criterion = operation.create
    # The resource name the criterion will be created with. This will define
    # the ID for the ad group criterion.
    ad_group_criterion.resource_name = client.get_service(
        "AdGroupCriterionService"
    ).ad_group_criterion_path(customer_id, ad_group_id, next_id())
    ad_group_criterion.status = client.enums.AdGroupCriterionStatusEnum.ENABLED

    listing_group_info = ad_group_criterion.listing_group
    # Set the type as a SUBDIVISION, which will allow the node to be the
    # parent of another sub-tree.
    listing_group_info.type_ = client.enums.ListingGroupTypeEnum.SUBDIVISION
    # If parent_ad_group_criterion_resource_name and listing_dimension_info
    # are not null, create a non-root division by setting its parent and case
    # value.
    if (
        parent_ad_group_criterion_resource_name
        and listing_dimension_info != None
    ):
        # Set the ad group criterion resource name for the parent listing group.
        # This can include a temporary ID if the parent criterion is not yet
        # created.
        listing_group_info.parent_ad_group_criterion = (
            parent_ad_group_criterion_resource_name
        )

        # Case values contain the listing dimension used for the node.
        client.copy_from(listing_group_info.case_value, listing_dimension_info)

    return operation


def create_listing_group_unit_biddable(
    client,
    customer_id,
    ad_group_id,
    parent_ad_group_criterion_resource_name,
    listing_dimension_info,
    cpc_bid_micros=None,
):
    """Creates a new criterion containing a biddable unit listing group node.

    Args:
        client: An initialized Google Ads client.
        customer_id: The Google Ads customer ID.
        ad_group_id: The ad group ID to which the node will be added.
        parent_ad_group_criterion_resource_name: The string resource name of the
            parent node to which this listing will be attached.
        listing_dimension_info: A ListingDimensionInfo object containing details
            for this listing.
        cpc_bid_micros: The cost-per-click bid for this listing in micros.

    Returns:
        An AdGroupCriterionOperation with a populated create field.
    """
    # Note: There are two approaches for creating new unit nodes:
    # (1) Set the ad group resource name on the criterion (no temporary ID
    # required).
    # (2) Use a temporary ID to construct the criterion resource name and set
    # it to the 'resourceName' attribute.
    # In both cases you must set the parent ad group criterion's resource name
    # on the listing group for non-root nodes.
    # This example demonstrates method (1).
    operation = client.get_type("AdGroupCriterionOperation")

    criterion = operation.create
    criterion.ad_group = client.get_service("AdGroupService").ad_group_path(
        customer_id, ad_group_id
    )
    criterion.status = client.enums.AdGroupCriterionStatusEnum.ENABLED
    # Set the bid for this listing group unit.
    # This will be used as the CPC bid for items that are included in this
    # listing group.
    if cpc_bid_micros:
        criterion.cpc_bid_micros = cpc_bid_micros

    listing_group = criterion.listing_group
    # Set the type as a UNIT, which will allow the group to be biddable.
    listing_group.type_ = client.enums.ListingGroupTypeEnum.UNIT
    # Set the ad group criterion resource name for the parent listing group.
    # This can have a temporary ID if the parent criterion is not yet created.
    listing_group.parent_ad_group_criterion = (
        parent_ad_group_criterion_resource_name
    )
    # Case values contain the listing dimension used for the node.
    if listing_dimension_info != None:
        client.copy_from(listing_group.case_value, listing_dimension_info)

    return operation


if __name__ == "__main__":
    parser = argparse.ArgumentParser(
        description="Add shopping product listing group tree to a shopping ad "
        "group."
    )
    # The following argument(s) should be provided to run the example.
    parser.add_argument(
        "-c",
        "--customer_id",
        type=str,
        required=True,
        help="The Google Ads customer ID.",
    )
    parser.add_argument(
        "-a",
        "--ad_group_id",
        type=str,
        required=True,
        help="The ID of the ad group that will receive the listing group tree.",
    )
    parser.add_argument(
        "-r",
        "--replace_existing_tree",
        action="store_true",
        required=False,
        default=False,
        help="Optional, whether to replace the existing listing group tree on "
        "the ad group if one already exists. Defaults to false.",
    )

    args = parser.parse_args()

    # GoogleAdsClient will read the google-ads.yaml configuration file in the
    # home directory if none is specified.
    googleads_client = GoogleAdsClient.load_from_storage(version="v17")

    try:
        main(
            googleads_client,
            args.customer_id,
            args.ad_group_id,
            args.replace_existing_tree,
        )
    except GoogleAdsException as ex:
        print(
            f"Request with ID '{ex.request_id}' failed with status "
            f"'{ex.error.code().name}' and includes the following errors:"
        )
        for error in ex.failure.errors:
            print(f"\tError with message '{error.message}'.")
            if error.location:
                for field_path_element in error.location.field_path_elements:
                    print(f"\t\tOn field: {field_path_element.field_name}")
        sys.exit(1)

      

Ruby

#!/usr/bin/env ruby
# Encoding: utf-8
#
# Copyright 2019 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
# This example shows how to add a shopping listing group tree to a shopping ad
# group. The example will optionally clear an existing listing group tree and
# rebuild it to include the following tree structure:
#
# ProductCanonicalCondition NEW $0.20
# ProductCanonicalCondition USED $0.10
# ProductCanonicalCondition null (everything else)
#   ProductBrand CoolBrand $0.90
#   ProductBrand CheapBrand $0.01
#   ProductBrand null (everything else) $0.50

require 'optparse'
require 'google/ads/google_ads'
require 'date'

def add_shopping_product_listing_group_tree(
  customer_id,
  ad_group_id,
  should_replace_existing_tree
)
  # GoogleAdsClient will read a config file from
  # ENV['HOME']/google_ads_config.rb when called without parameters
  client = Google::Ads::GoogleAds::GoogleAdsClient.new

  # 1) Optional: Remove the existing listing group tree, if it already exists
  # on the ad group.
  if should_replace_existing_tree
    remove_listing_group_tree(client, customer_id, ad_group_id)
  end

  # 2) Construct the listing group tree "root" node.

  # Subdivision node: (Root node)
  ad_group_criterion_root = create_listing_group_subdivision(
    client,
    customer_id,
    ad_group_id,
  )
  # This resource has not been created yet and will include the temporary ID as
  # part of the criterion ID.
  ad_group_criterion_root_resource_name = ad_group_criterion_root.resource_name
  operations = [client.operation.create_resource.ad_group_criterion(ad_group_criterion_root)]

  # 3) Construct the listing group unit nodes for NEW, USED, and other.

  # Biddable Unit node: (Condition NEW node)
  # * Product Condition: NEW
  # * CPC bid: $0.20
  listing_dimension_info = client.resource.listing_dimension_info do |ldi|
    ldi.product_condition = client.resource.product_condition_info do |pci|
      pci.condition = :NEW
    end
  end

  ad_group_criterion_condition_new = create_listing_group_unit_biddable(
    client,
    customer_id,
    ad_group_id,
    ad_group_criterion_root_resource_name,
    listing_dimension_info,
    200_000,
  )
  operation = client.operation.create_resource.ad_group_criterion(
    ad_group_criterion_condition_new
  )
  operations << operation

  # Biddable Unit node: (Condition USED node)
  # * Product Condition: USED
  # * CPC bid: $0.10
  listing_dimension_info = client.resource.listing_dimension_info do |ldi|
    ldi.product_condition = client.resource.product_condition_info do |pci|
      pci.condition = :USED
    end
  end
  ad_group_criterion_condition_used = create_listing_group_unit_biddable(
    client,
    customer_id,
    ad_group_id,
    ad_group_criterion_root_resource_name,
    listing_dimension_info,
    100_000,
  )
  operation = client.operation.create_resource.ad_group_criterion(
    ad_group_criterion_condition_used
  )
  operations << operation

  # Sub-division node: (Condition "other" node)
  # * Product Condition: (not specified)
  listing_dimension_info = client.resource.listing_dimension_info do |ldi|
    ldi.product_condition = client.resource.product_condition_info
  end
  ad_group_criterion_condition_other = create_listing_group_subdivision(
    client,
    customer_id,
    ad_group_id,
    ad_group_criterion_root_resource_name,
    listing_dimension_info,
  )
  operation = client.operation.create_resource.ad_group_criterion(
    ad_group_criterion_condition_other
  )
  operations << operation

  ad_group_criterion_condition_other_resource_name =
    ad_group_criterion_condition_other.resource_name

  # 4) Construct the listing group unit nodes for CoolBrand, CheapBrand, and
  # other.

  # Biddable Unit node: (Brand CoolBrand node)
  # * Brand: CoolBrand
  # * CPC bid: $0.90
  listing_dimension_info = client.resource.listing_dimension_info do |ldi|
    ldi.product_brand = client.resource.product_brand_info do |pbi|
      pbi.value = "CoolBrand"
    end
  end

  ad_group_criterion_brand_cool_brand = create_listing_group_unit_biddable(
    client,
    customer_id,
    ad_group_id,
    ad_group_criterion_condition_other_resource_name,
    listing_dimension_info,
    900_000,
  )
  operation = client.operation.create_resource.ad_group_criterion(
    ad_group_criterion_brand_cool_brand
  )
  operations << operation

  # Biddable Unit node: (Brand CheapBrand node)
  # * Brand: CheapBrand
  # * CPC bid: $0.01
  listing_dimension_info = client.resource.listing_dimension_info do |ldi|
    ldi.product_brand = client.resource.product_brand_info do |pbi|
      pbi.value = "CheapBrand"
    end
  end
  ad_group_criterion_brand_cheap_brand = create_listing_group_unit_biddable(
    client,
    customer_id,
    ad_group_id,
    ad_group_criterion_condition_other_resource_name,
    listing_dimension_info,
    10_000,
  )
  operation = client.operation.create_resource.ad_group_criterion(
    ad_group_criterion_brand_cheap_brand
  )
  operations << operation

  # Biddable Unit node: (Brand other node)
  # * CPC bid: $0.05
  listing_dimension_info = client.resource.listing_dimension_info do |ldi|
    ldi.product_brand = client.resource.product_brand_info
  end
  ad_group_criterion_brand_other_brand = create_listing_group_unit_biddable(
    client,
    customer_id,
    ad_group_id,
    ad_group_criterion_condition_other_resource_name,
    listing_dimension_info,
    50_000,
  )
  operation = client.operation.create_resource.ad_group_criterion(
    ad_group_criterion_brand_other_brand
  )
  operations << operation

  # Issue the mutate request.
  response = client.service.ad_group_criterion.mutate_ad_group_criteria(
    customer_id: customer_id,
    operations: operations,
  )

  total_count = 0
  response.results.each do |added_criterion|
    puts "Added ad group criterion with name: #{added_criterion.resource_name}"
    total_count += 1
  end
  puts "#{total_count} criteria added in total."
end

def remove_listing_group_tree(client, customer_id, ad_group_id)
  ga_service = client.service.google_ads

  query = <<~QUERY
    SELECT
      ad_group_criterion.resource_name
    FROM
      ad_group_criterion
    WHERE
      ad_group_criterion.type = LISTING_GROUP
    AND
      ad_group_criterion.listing_group.parent_ad_group_criterion IS NULL
    AND
      ad_group.id = #{ad_group_id}
  QUERY

  response = ga_service.search(customer_id: customer_id, query: query, page_size: PAGE_SIZE)

  operations = response.map do |row|
    criterion = row.ad_group_criterion
    puts "Found an ad group criterion with resource name: #{criterion.resource_name}"

    client.operation.remove_resource.ad_group_criterion(criterion.resource_name)
  end

  if operations.any?
    response = client.service.ad_group_criterion.mutate_ad_group_criteria(
      customer_id: customer_id,
      operations: operations,
    )
    puts "Removed #{response.results.count} ad group criteria."
  end
end

# Specify a decreasing negative number for temporary ad group criteria IDs. The
# ad group criteria will get real IDs when created on the server.
# Returns -1, -2, -3, etc. on subsequent calls.
def next_id
  @id ||= 0
  @id -= 1
end

def create_listing_group_subdivision(
  client,
  customer_id,
  ad_group_id,
  parent_ad_group_criterion_name = nil,
  listing_dimension_info = nil
)
  client.resource.ad_group_criterion do |criterion|
    criterion.resource_name = client.path.ad_group_criterion(
      customer_id,
      ad_group_id,
      next_id,
    )

    criterion.status = :ENABLED
    criterion.listing_group = client.resource.listing_group_info do |listing_group_info|
      listing_group_info.type = :SUBDIVISION

      if parent_ad_group_criterion_name && listing_dimension_info
        listing_group_info.parent_ad_group_criterion = parent_ad_group_criterion_name
        listing_group_info.case_value = listing_dimension_info
      end
    end
  end
end

def create_listing_group_unit_biddable(client, customer_id, ad_group_id,
                                       parent_ad_group_criterion_name, listing_dimension_info, cpc_bid_micros)
  # Note: There are two approaches for creating new unit nodes:
  # (1) Set the ad group resource name on the criterion (no temporary ID
  # required).
  # (2) Use a temporary ID to construct the criterion resource name and set it
  # using the client.path utility.
  # In both cases you must set the parent ad group criterion's resource name on
  # the listing group for non-root nodes.
  # This example demonstrates method (1).
  client.resource.ad_group_criterion do |criterion|
    criterion.ad_group = client.path.ad_group(customer_id, ad_group_id)
    criterion.status = :ENABLED
    criterion.cpc_bid_micros = cpc_bid_micros

    criterion.listing_group = client.resource.listing_group_info do |listing_group|
      # The type UNIT allows the group to be biddable.
      listing_group.type = :UNIT
      listing_group.parent_ad_group_criterion = parent_ad_group_criterion_name
      listing_group.case_value = listing_dimension_info
    end
  end
end

if __FILE__ == $0
  PAGE_SIZE = 1000

  options = {}
  # The following parameter(s) should be provided to run the example. You can
  # either specify these by changing the INSERT_XXX_ID_HERE values below, or on
  # the command line.
  #
  # Parameters passed on the command line will override any parameters set in
  # code.
  #
  # Running the example with -h will print the command line usage.
  options[:customer_id] = 'INSERT_CUSTOMER_ID_HERE'
  options[:ad_group_id] = 'INSERT_AD_GROUP_ID_HERE'
  # Specifying any value for this field on the command line will override this
  # to true.
  options[:should_replace_existing_tree] = false

  OptionParser.new do |opts|
    opts.banner = sprintf("Usage: #{File.basename(__FILE__)} [options]")

    opts.separator ''
    opts.separator 'Options:'

    opts.on('-C', '--customer-id CUSTOMER-ID', String, 'Customer ID') do |v|
      options[:customer_id] = v
    end

    opts.on('-A', '--ad-group-id AD-GROUP-ID', String, 'Ad Group ID') do |v|
      options[:ad_group_id] = v
    end

    opts.on('-r', '--replace-existing-tree REPLACE-EXISTING-TREE',
        TrueClass, 'Create Default Listing Group') do |v|
      options[:should_replace_existing_tree] = v
    end

    opts.separator ''
    opts.separator 'Help:'

    opts.on_tail('-h', '--help', 'Show this message') do
      puts opts
      exit
    end
  end.parse!

  begin
    add_shopping_product_listing_group_tree(
      options.fetch(:customer_id).tr("-", ""),
      options.fetch(:ad_group_id),
      options.fetch(:should_replace_existing_tree),
    )
  rescue Google::Ads::GoogleAds::Errors::GoogleAdsError => e
    e.failure.errors.each do |error|
      STDERR.printf("Error with message: %s\n", error.message)
      if error.location
        error.location.field_path_elements.each do |field_path_element|
          STDERR.printf("\tOn field: %s\n", field_path_element.field_name)
        end
      end
      error.error_code.to_h.each do |k, v|
        next if v == :UNSPECIFIED
        STDERR.printf("\tType: %s\n\tCode: %s\n", k, v)
      end
    end
    raise
  end
end

      

Perl

#!/usr/bin/perl -w
#
# Copyright 2019, Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
# This example shows how to add a shopping listing group tree to a shopping ad
# group. The example will optionally clear an existing listing group tree and
# rebuild it to include the following tree structure:
#
# ProductCanonicalCondition NEW $0.20
# ProductCanonicalCondition USED $0.10
# ProductCanonicalCondition null (everything else)
#   ProductBrand CoolBrand $0.90
#   ProductBrand CheapBrand $0.01
#   ProductBrand null (everything else) $0.50

use strict;
use warnings;
use utf8;

use FindBin qw($Bin);
use lib "$Bin/../../lib";
use Google::Ads::GoogleAds::Client;
use Google::Ads::GoogleAds::Utils::GoogleAdsHelper;
use Google::Ads::GoogleAds::Utils::SearchGoogleAdsIterator;
use Google::Ads::GoogleAds::V17::Resources::AdGroupCriterion;
use Google::Ads::GoogleAds::V17::Common::ListingGroupInfo;
use Google::Ads::GoogleAds::V17::Common::ListingDimensionInfo;
use Google::Ads::GoogleAds::V17::Common::ProductConditionInfo;
use Google::Ads::GoogleAds::V17::Common::ProductBrandInfo;
use Google::Ads::GoogleAds::V17::Enums::ListingGroupTypeEnum
  qw(SUBDIVISION UNIT);
use Google::Ads::GoogleAds::V17::Enums::AdGroupCriterionStatusEnum qw(ENABLED);
use Google::Ads::GoogleAds::V17::Enums::ProductConditionEnum       qw(NEW USED);
use
  Google::Ads::GoogleAds::V17::Services::AdGroupCriterionService::AdGroupCriterionOperation;
use
  Google::Ads::GoogleAds::V17::Services::GoogleAdsService::SearchGoogleAdsRequest;
use Google::Ads::GoogleAds::V17::Utils::ResourceNames;

use Getopt::Long qw(:config auto_help);
use Pod::Usage;
use Cwd          qw(abs_path);
use Data::Uniqid qw(uniqid);

# The following parameter(s) should be provided to run the example. You can
# either specify these by changing the INSERT_XXX_ID_HERE values below, or on
# the command line.
#
# Parameters passed on the command line will override any parameters set in
# code.
#
# Running the example with -h will print the command line usage.
my $customer_id           = "INSERT_CUSTOMER_ID_HERE";
my $ad_group_id           = "INSERT_AD_GROUP_ID_HERE";
my $replace_existing_tree = undef;

sub add_shopping_product_listing_group_tree {
  my ($api_client, $customer_id, $ad_group_id, $replace_existing_tree) = @_;

  # 1) Optional: Remove the existing listing group tree, if it already exists
  # on the ad group.
  if ($replace_existing_tree) {
    remove_listing_group_tree($api_client, $customer_id, $ad_group_id);
  }

  # Create a list of ad group criteria operations to add.
  my $operations = [];

  # 2) Construct the listing group tree "root" node.

  # Subdivision node: (Root node)
  my $ad_group_criterion_root =
    create_listing_group_subdivision($customer_id, $ad_group_id);
  # Get the resource name that will be used for the root node.
  # This resource has not been created yet and will include the temporary ID as
  # part of the criterion ID.
  my $ad_group_criterion_root_resource_name =
    $ad_group_criterion_root->{resourceName};
  push @$operations,
    Google::Ads::GoogleAds::V17::Services::AdGroupCriterionService::AdGroupCriterionOperation
    ->new({
      create => $ad_group_criterion_root
    });

  # 3) Construct the listing group unit nodes for NEW, USED, and other.

  # Biddable Unit node: (Condition NEW node)
  # * Product Condition: NEW
  # * CPC bid: $0.20
  my $ad_group_criterion_condition_new = create_listing_group_unit_biddable(
    $customer_id,
    $ad_group_id,
    $ad_group_criterion_root_resource_name,
    Google::Ads::GoogleAds::V17::Common::ListingDimensionInfo->new({
        productCondition =>
          Google::Ads::GoogleAds::V17::Common::ProductConditionInfo->new({
            condition => NEW
          })}
    ),
    200000
  );
  push @$operations,
    Google::Ads::GoogleAds::V17::Services::AdGroupCriterionService::AdGroupCriterionOperation
    ->new({
      create => $ad_group_criterion_condition_new
    });

  # Biddable Unit node: (Condition USED node)
  # * Product Condition: USED
  # * CPC bid: $0.10
  my $ad_group_criterion_condition_used = create_listing_group_unit_biddable(
    $customer_id,
    $ad_group_id,
    $ad_group_criterion_root_resource_name,
    Google::Ads::GoogleAds::V17::Common::ListingDimensionInfo->new({
        productCondition =>
          Google::Ads::GoogleAds::V17::Common::ProductConditionInfo->new({
            condition => USED
          })}
    ),
    100000
  );
  push @$operations,
    Google::Ads::GoogleAds::V17::Services::AdGroupCriterionService::AdGroupCriterionOperation
    ->new({
      create => $ad_group_criterion_condition_used
    });

  # Sub-division node: (Condition "other" node)
  # * Product Condition: (not specified)
  my $ad_group_criterion_condition_other = create_listing_group_subdivision(
    $customer_id,
    $ad_group_id,
    $ad_group_criterion_root_resource_name,
    Google::Ads::GoogleAds::V17::Common::ListingDimensionInfo->new({
        # All sibling nodes must have the same dimension type, even if they
        # don't contain a bid.
        productCondition =>
          Google::Ads::GoogleAds::V17::Common::ProductConditionInfo->new()}));
  push @$operations,
    Google::Ads::GoogleAds::V17::Services::AdGroupCriterionService::AdGroupCriterionOperation
    ->new({
      create => $ad_group_criterion_condition_other
    });

  # Get the resource name that will be used for the condition other node.
  # This resource has not been created yet and will include the temporary ID as
  # part of the criterion ID.
  my $ad_group_criterion_condition_other_resource_name =
    $ad_group_criterion_condition_other->{resourceName};

  # 4) Construct the listing group unit nodes for CoolBrand, CheapBrand, and
  # other.

  # Biddable Unit node: (Brand CoolBrand node)
  # * Brand: CoolBrand
  # * CPC bid: $0.90
  my $ad_group_criterion_brand_cool_brand = create_listing_group_unit_biddable(
    $customer_id,
    $ad_group_id,
    $ad_group_criterion_condition_other_resource_name,
    Google::Ads::GoogleAds::V17::Common::ListingDimensionInfo->new({
        productBrand =>
          Google::Ads::GoogleAds::V17::Common::ProductBrandInfo->new(
          {value => "CoolBrand"})}
    ),
    900000
  );
  push @$operations,
    Google::Ads::GoogleAds::V17::Services::AdGroupCriterionService::AdGroupCriterionOperation
    ->new({
      create => $ad_group_criterion_brand_cool_brand
    });

  # Biddable Unit node: (Brand CheapBrand node)
  # * Brand: CheapBrand
  # * CPC bid: $0.01
  my $ad_group_criterion_brand_cheap_brand = create_listing_group_unit_biddable(
    $customer_id,
    $ad_group_id,
    $ad_group_criterion_condition_other_resource_name,
    Google::Ads::GoogleAds::V17::Common::ListingDimensionInfo->new({
        productBrand =>
          Google::Ads::GoogleAds::V17::Common::ProductBrandInfo->new(
          {value => "CheapBrand"})}
    ),
    10000
  );
  push @$operations,
    Google::Ads::GoogleAds::V17::Services::AdGroupCriterionService::AdGroupCriterionOperation
    ->new({
      create => $ad_group_criterion_brand_cheap_brand
    });

  # Biddable Unit node: (Brand other node)
  # * CPC bid: $0.05
  my $ad_group_criterion_brand_other_brand = create_listing_group_unit_biddable(
    $customer_id,
    $ad_group_id,
    $ad_group_criterion_condition_other_resource_name,
    Google::Ads::GoogleAds::V17::Common::ListingDimensionInfo->new({
        productBrand =>
          Google::Ads::GoogleAds::V17::Common::ProductBrandInfo->new()}
    ),
    50000
  );
  push @$operations,
    Google::Ads::GoogleAds::V17::Services::AdGroupCriterionService::AdGroupCriterionOperation
    ->new({
      create => $ad_group_criterion_brand_other_brand
    });

  # Add the ad group criterion.
  my $ad_group_criteria_response =
    $api_client->AdGroupCriterionService()->mutate({
      customerId => $customer_id,
      operations => $operations
    });

  printf "Added %d ad group criteria for listing group tree with the " .
    "following resource names:\n",
    scalar @{$ad_group_criteria_response->{results}};

  foreach my $result (@{$ad_group_criteria_response->{results}}) {
    print $result->{resourceName}, "\n";
  }

  return 1;
}

# Removes all the ad group criteria that define the existing listing group
# tree for an ad group.
sub remove_listing_group_tree {
  my ($api_client, $customer_id, $ad_group_id) = @_;

  my $search_query =
    "SELECT ad_group_criterion.resource_name " .
    "FROM ad_group_criterion WHERE ad_group_criterion.type = LISTING_GROUP " .
    "AND ad_group_criterion.listing_group.parent_ad_group_criterion IS NULL " .
    "AND ad_group.id = $ad_group_id";

  # Create a search Google Ads request that will retrieve all listing groups
  # where the parent ad group criterion is NULL (and hence the root node in
  # the tree) for a given ad group id.
  my $search_request =
    Google::Ads::GoogleAds::V17::Services::GoogleAdsService::SearchGoogleAdsRequest
    ->new({
      customerId => $customer_id,
      query      => $search_query
    });

  # Get the GoogleAdsService.
  my $google_ads_service = $api_client->GoogleAdsService();

  my $iterator = Google::Ads::GoogleAds::Utils::SearchGoogleAdsIterator->new({
    service => $google_ads_service,
    request => $search_request
  });

  my $operations = [];
  # Iterate over all rows in all pages to find the ad group criterion to remove.
  while ($iterator->has_next) {
    my $google_ads_row     = $iterator->next;
    my $ad_group_criterion = $google_ads_row->{adGroupCriterion};
    printf "Found an ad group criterion with the resource name: '%s'.\n",
      $ad_group_criterion->{resourceName};

    # Create an ad group criterion operation.
    my $ad_group_criterion_operation =
      Google::Ads::GoogleAds::V17::Services::AdGroupCriterionService::AdGroupCriterionOperation
      ->new({
        remove => $ad_group_criterion->{resourceName}});

    push @$operations, $ad_group_criterion_operation;
  }

  if (scalar @$operations) {
    # Remove the ad group criterion that define the listing group tree.
    my $ad_group_criteria_response =
      $api_client->AdGroupCriterionService()->mutate({
        customerId => $customer_id,
        operations => $operations
      });

    printf "Removed %d ad group criteria.\n",
      scalar @{$ad_group_criteria_response->{results}};
  }
}

# Creates a new criterion containing a subdivision listing group node. If
# the parent ad group criterion resource name is not specified, this method
# creates a root node.
sub create_listing_group_subdivision {
  my ($customer_id, $ad_group_id, $parent_ad_group_criterion_resource_name,
    $listing_dimension_info)
    = @_;

  my $listing_group_info =
    Google::Ads::GoogleAds::V17::Common::ListingGroupInfo->new({
      # Set the type as a SUBDIVISION, which will allow the node to be the
      # parent of another sub-tree.
      'type' => SUBDIVISION
    });

  # If $parent_ad_group_criterion_resource_name and $listing_dimension_info
  # are not null, create a non-root division by setting its parent and case value.
  if ($parent_ad_group_criterion_resource_name and $listing_dimension_info) {
    # Set the ad group criterion resource name for the parent listing group.
    # This can include a temporary ID if the parent criterion is not yet created.
    $listing_group_info->{parentAdGroupCriterion} =
      $parent_ad_group_criterion_resource_name;

    # Case values contain the listing dimension used for the node.
    $listing_group_info->{caseValue} = $listing_dimension_info;
  }

  my $ad_group_criterion =
    Google::Ads::GoogleAds::V17::Resources::AdGroupCriterion->new({
      # The resource name the criterion will be created with. This will define
      # the ID for the ad group criterion.
      resourceName =>
        Google::Ads::GoogleAds::V17::Utils::ResourceNames::ad_group_criterion(
        $customer_id, $ad_group_id, next_id()
        ),
      status       => ENABLED,
      listingGroup => $listing_group_info
    });

  return $ad_group_criterion;
}

# Creates a new criterion containing a biddable unit listing group node.
sub create_listing_group_unit_biddable {
  my ($customer_id, $ad_group_id, $parent_ad_group_criterion_resource_name,
    $listing_dimension_info, $cpc_bid_micros)
    = @_;

  # Note: There are two approaches for creating new unit nodes:
  # (1) Set the ad group resource name on the criterion (no temporary ID
  # required).
  # (2) Use a temporary ID to construct the criterion resource name and set it
  # to the 'resourceName' attribute.
  # In both cases you must set the parent ad group criterion's resource name on
  # the listing group for non-root nodes.
  # This example demonstrates method (1).
  my $ad_group_criterion =
    Google::Ads::GoogleAds::V17::Resources::AdGroupCriterion->new({
      adGroup => Google::Ads::GoogleAds::V17::Utils::ResourceNames::ad_group(
        $customer_id, $ad_group_id
      ),
      status       => ENABLED,
      listingGroup =>
        Google::Ads::GoogleAds::V17::Common::ListingGroupInfo->new({
          # Set the type as a UNIT, which will allow the group to be biddable.
          type => UNIT,
          # Set the ad group criterion resource name for the parent listing group.
          # This can include a temporary ID if the parent criterion is not yet created.
          parentAdGroupCriterion => $parent_ad_group_criterion_resource_name,
          # Case values contain the listing dimension used for the node.
          caseValue => $listing_dimension_info
        }
        ),
      # Set the bid for this listing group unit.
      # This will be used as the CPC bid for items that are included in this
      # listing group.
      cpcBidMicros => $cpc_bid_micros
    });

  return $ad_group_criterion;
}

# Specifies a decreasing negative number for temporary ad group criteria IDs.
# The ad group criteria will get real IDs when created on the server.
# Returns -1, -2, -3, etc. on subsequent calls.
sub next_id {
  our $id ||= 0;
  $id -= 1;
}

# Don't run the example if the file is being included.
if (abs_path($0) ne abs_path(__FILE__)) {
  return 1;
}

# Get Google Ads Client, credentials will be read from ~/googleads.properties.
my $api_client = Google::Ads::GoogleAds::Client->new();

# By default examples are set to die on any server returned fault.
$api_client->set_die_on_faults(1);

# Parameters passed on the command line will override any parameters set in code.
GetOptions(
  "customer_id=s"           => \$customer_id,
  "ad_group_id=i"           => \$ad_group_id,
  "replace_existing_tree=s" => \$replace_existing_tree
);

# Print the help message if the parameters are not initialized in the code nor
# in the command line.
pod2usage(2) if not check_params($customer_id, $ad_group_id);

# Call the example.
add_shopping_product_listing_group_tree($api_client, $customer_id =~ s/-//gr,
  $ad_group_id, $replace_existing_tree);

=pod

=head1 NAME

add_shopping_product_listing_group_tree

=head1 DESCRIPTION

This example shows how to add a shopping listing group tree to a shopping ad group.
The example will optionally clear an existing listing group tree and rebuild it to
include the following tree structure:

ProductCanonicalCondition NEW $0.20
ProductCanonicalCondition USED $0.10
ProductCanonicalCondition null (everything else)
  ProductBrand CoolBrand $0.90
  ProductBrand CheapBrand $0.01
  ProductBrand null (everything else) $0.50

=head1 SYNOPSIS

add_shopping_product_listing_group_tree.pl [options]

    -help                           Show the help message.
    -customer_id                    The Google Ads customer ID.
    -ad_group_id                    The ad group ID.
    -replace_existing_tree          [optional] Replace the existing listing group tree
                                    on the ad group, if it already exists.

=cut