জাভা
// 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
//
// 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.
package com.google.ads.googleads.examples.extensions;
import static com.google.ads.googleads.examples.utils.CodeSampleHelper.getPrintableDateTime;
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.v13.common.MatchingFunction;
import com.google.ads.googleads.v13.enums.AffiliateLocationFeedRelationshipTypeEnum.AffiliateLocationFeedRelationshipType;
import com.google.ads.googleads.v13.enums.AffiliateLocationPlaceholderFieldEnum.AffiliateLocationPlaceholderField;
import com.google.ads.googleads.v13.enums.FeedOriginEnum.FeedOrigin;
import com.google.ads.googleads.v13.enums.PlaceholderTypeEnum.PlaceholderType;
import com.google.ads.googleads.v13.errors.GoogleAdsError;
import com.google.ads.googleads.v13.errors.GoogleAdsException;
import com.google.ads.googleads.v13.resources.AttributeFieldMapping;
import com.google.ads.googleads.v13.resources.CampaignFeed;
import com.google.ads.googleads.v13.resources.CustomerFeed;
import com.google.ads.googleads.v13.resources.Feed;
import com.google.ads.googleads.v13.resources.Feed.AffiliateLocationFeedData;
import com.google.ads.googleads.v13.resources.FeedMapping;
import com.google.ads.googleads.v13.services.CampaignFeedOperation;
import com.google.ads.googleads.v13.services.CampaignFeedServiceClient;
import com.google.ads.googleads.v13.resources.FeedName;
import com.google.ads.googleads.v13.services.FeedOperation;
import com.google.ads.googleads.v13.services.FeedServiceClient;
import com.google.ads.googleads.v13.services.GoogleAdsRow;
import com.google.ads.googleads.v13.services.GoogleAdsServiceClient;
import com.google.ads.googleads.v13.services.GoogleAdsServiceClient.SearchPagedResponse;
import com.google.ads.googleads.v13.services.MutateCampaignFeedsResponse;
import com.google.ads.googleads.v13.services.MutateFeedsResponse;
import com.google.ads.googleads.v13.utils.ResourceNames;
import com.google.api.gax.grpc.GrpcStatusCode;
import com.google.api.gax.rpc.ApiException;
import com.google.common.collect.ImmutableList;
import io.grpc.Status.Code;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
/**
* Adds a feed that syncs retail addresses for a given retail chain ID and associates the feed with
* a campaign for serving affiliate location extensions.
*/
public class AddAffiliateLocationExtensions {
private static final int MAX_FEEDMAPPING_RETRIEVAL_ATTEMPTS = 10;
private static class AddAffiliateLocationExtensionsParams extends CodeSampleParams {
@Parameter(names = ArgumentNames.CUSTOMER_ID, required = true)
private long customerId;
@Parameter(names = ArgumentNames.CAMPAIGN_ID, required = true)
private long campaignId;
@Parameter(
names = ArgumentNames.CHAIN_ID,
description =
"The retail chain ID. See"
+ " https://developers.google.com/google-ads/api/reference/data/codes-formats#chain-ids"
+ " a complete list of valid retail chain IDs",
required = true)
private long chainId;
}
public static void main(String[] args) throws IOException {
AddAffiliateLocationExtensionsParams params = new AddAffiliateLocationExtensionsParams();
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.campaignId = Long.parseLong("INSERT_CAMPAIGN_ID_HERE");
params.chainId = Long.parseLong("INSERT_CHAIN_ID_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 AddAffiliateLocationExtensions()
.runExample(googleAdsClient, params.customerId, params.campaignId, params.chainId);
} 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.
gae.printStackTrace();
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);
}
}
}
/** Runs the example. */
private void runExample(
GoogleAdsClient googleAdsClient, long customerId, long campaignId, long chainId) {
String feedResourceName =
createAffiliateLocationExtensionFeed(googleAdsClient, customerId, chainId);
// The feed created above will not be available for use in a campaign feed until the associated
// feed mappings have been created by Google.
FeedMapping feedMapping = waitForFeedToBeReady(googleAdsClient, customerId, feedResourceName);
// Creates the campaign feed now that the feed mappings are ready.
createCampaignFeed(
googleAdsClient, customerId, campaignId, feedMapping, feedResourceName, chainId);
}
/** Creates an affiliate location extension feed. */
private String createAffiliateLocationExtensionFeed(
GoogleAdsClient googleAdsClient, long customerId, long chainId) {
// Removes all existing location extension feeds. This is an optional step, but is required for
// this code example to run correctly more than once. This is because:
// 1. Google Ads only allows one location extension feed per email address.
// 2. A Google Ads account cannot have a location extension feed and an affiliate
// location extension feed at the same time.
removeLocationExtensionFeeds(googleAdsClient, customerId);
// Creates a feed that will sync to retail addresses for a given retail chain ID.
// Do not add FeedAttributes to this object as Google Ads will add
// them automatically because this will be a system generated feed.
Feed feed =
Feed.newBuilder()
.setName("Affiliate Location Extension feed #" + getPrintableDateTime())
.setAffiliateLocationFeedData(
AffiliateLocationFeedData.newBuilder()
.addChainIds(chainId)
.setRelationshipType(AffiliateLocationFeedRelationshipType.GENERAL_RETAILER))
// Since this feed's contents will be managed by Google,
// you must set its origin to GOOGLE.
.setOrigin(FeedOrigin.GOOGLE)
.build();
// Constructs an operation to create the feed.
FeedOperation op = FeedOperation.newBuilder().setCreate(feed).build();
// Creates the FeedServiceClient.
try (FeedServiceClient feedService =
googleAdsClient.getLatestVersion().createFeedServiceClient()) {
// Issues a mutate request to add the feed.
MutateFeedsResponse response =
feedService.mutateFeeds(String.valueOf(customerId), ImmutableList.of(op));
// Displays the results.
String resourceName = response.getResults(0).getResourceName();
System.out.printf(
"Affliate location extension feed created with resource name: %s.%n", resourceName);
return resourceName;
}
}
/** Removes all location extension feeds. */
private void removeLocationExtensionFeeds(GoogleAdsClient googleAdsClient, long customerId) {
// Removes a location extension feed. Does this with the following steps:
// 1. Retrieves the existing CustomerFeed links.
// 2. Removes the CustomerFeed so that the location extensions from the feed stop serving.
// 3. Removes the feed so that Google Ads will no longer sync from the Business Profile
// account.
List<CustomerFeed> oldCustomerFeeds =
getLocationExtensionCustomerFeeds(googleAdsClient, customerId);
if (oldCustomerFeeds.isEmpty()) {
// Optional: You may also want to remove the CampaignFeeds and AdGroupFeeds.
removeCustomerFeeds(googleAdsClient, customerId, oldCustomerFeeds);
}
List<Feed> feeds = getLocationExtensionFeeds(googleAdsClient, customerId);
if (!feeds.isEmpty()) {
removeFeeds(googleAdsClient, customerId, feeds);
}
}
/** Creates a CampaignFeed. This links a preexisting {@link Feed} to a campaign. */
private void createCampaignFeed(
GoogleAdsClient googleAdsClient,
long customerId,
long campaignId,
FeedMapping feedMapping,
String feedResourceName,
long chainId) {
// Gets the attribute ID that is used for the chain ID. This will be used to filter the feed to
// extract affiliate locations.
long attributeIdForChainId = getAttributeIdForChainId(feedMapping);
// Extracts the feed ID.
long feedId = Long.valueOf(FeedName.parse(feedResourceName).getFeedId());
// Constructs a matching function string which filters the Feed to extract affiliate locations.
String matchingFunction =
String.format("IN(FeedAttribute[%d, %d], %d)", feedId, attributeIdForChainId, chainId);
// Creates a CampaignFeed object.
CampaignFeed campaignFeed =
CampaignFeed.newBuilder()
.setFeed(feedResourceName)
.addPlaceholderTypes(PlaceholderType.AFFILIATE_LOCATION)
.setMatchingFunction(
MatchingFunction.newBuilder().setFunctionString(matchingFunction).build())
.setCampaign(ResourceNames.campaign(customerId, campaignId))
.build();
// Creates an operation to create the CampaignFeed.
CampaignFeedOperation operation =
CampaignFeedOperation.newBuilder().setCreate(campaignFeed).build();
// Adds a CampaignFeed that associates the feed with this campaign for
// the AFFILIATE_LOCATION placeholder type.
try (CampaignFeedServiceClient feedServiceClient =
googleAdsClient.getLatestVersion().createCampaignFeedServiceClient()) {
MutateCampaignFeedsResponse response =
feedServiceClient.mutateCampaignFeeds(
String.valueOf(customerId), ImmutableList.of(operation));
System.out.printf(
"Campaign feed created with resource name: %s.%n",
response.getResultsList().get(0).getResourceName());
}
}
/** Gets the feed item attribute ID that specifies the chain ID. */
private long getAttributeIdForChainId(FeedMapping feedMapping) {
Optional<AttributeFieldMapping> fieldMapping =
feedMapping.getAttributeFieldMappingsList().stream()
.filter(
m -> m.getAffiliateLocationField() == AffiliateLocationPlaceholderField.CHAIN_ID)
.findFirst();
if (!fieldMapping.isPresent()) {
throw new RuntimeException("Affiliate location field mapping isn't setup correctly");
}
return fieldMapping.get().getFeedAttributeId();
}
/** Removes a list of feeds from the customerID. */
private void removeFeeds(GoogleAdsClient googleAdsClient, long customerId, List<Feed> feeds) {
List<FeedOperation> removeOperations =
feeds.stream()
.map(f -> FeedOperation.newBuilder().setRemove(f.getResourceName()).build())
.collect(Collectors.toList());
try (FeedServiceClient feedServiceClient =
googleAdsClient.getLatestVersion().createFeedServiceClient()) {
feedServiceClient.mutateFeeds(String.valueOf(customerId), removeOperations);
}
}
/** Retrieves all location extension feeds from a specified customer ID. */
private List<Feed> getLocationExtensionFeeds(GoogleAdsClient googleAdsClient, long customerId) {
String query =
"SELECT"
+ " customer_feed.resource_name, "
+ " customer_feed.feed, "
+ " customer_feed.status, "
+ " customer_feed.matching_function.function_string "
+ "FROM"
+ " customer_feed "
+ "WHERE"
+ " customer_feed.placeholder_types CONTAINS ANY(LOCATION, AFFILIATE_LOCATION)"
+ " AND customer_feed.status = ENABLED";
try (GoogleAdsServiceClient client =
googleAdsClient.getLatestVersion().createGoogleAdsServiceClient()) {
SearchPagedResponse response = client.search(String.valueOf(customerId), query);
List<Feed> results = new ArrayList();
response.iterateAll().forEach(row -> results.add(row.getFeed()));
return results;
}
}
/** Removes all feeds linked at the customer (global) level. */
private void removeCustomerFeeds(
GoogleAdsClient googleAdsClient, long customerId, List<CustomerFeed> oldCustomerFeeds) {
List<FeedOperation> operations =
oldCustomerFeeds.stream()
.map(f -> FeedOperation.newBuilder().setRemove(f.getResourceName()).build())
.collect(Collectors.toList());
if (!operations.isEmpty()) {
try (FeedServiceClient feedServiceClient =
googleAdsClient.getLatestVersion().createFeedServiceClient()) {
feedServiceClient.mutateFeeds(String.valueOf(customerId), operations);
}
}
}
/** Retrieves the location extension feeds linked to a customer ID. */
private List<CustomerFeed> getLocationExtensionCustomerFeeds(
GoogleAdsClient googleAdsClient, long customerId) {
String query =
"SELECT"
+ " customer_feed.resource_name, "
+ " customer_feed.feed, "
+ " customer_feed.status, "
+ " customer_feed.matching_function.function_string "
+ "FROM"
+ " customer_feed "
+ "WHERE"
+ " customer_feed.placeholder_types CONTAINS ANY(LOCATION, AFFILIATE_LOCATION) "
+ " AND customer_feed.status = ENABLED";
try (GoogleAdsServiceClient googleAdsServiceClient =
googleAdsClient.getLatestVersion().createGoogleAdsServiceClient()) {
SearchPagedResponse response =
googleAdsServiceClient.search(String.valueOf(customerId), query);
List<CustomerFeed> results = new ArrayList();
response.iterateAll().forEach(row -> results.add(row.getCustomerFeed()));
return results;
}
}
/** Waits for a feed (identified by it's feedResourceName) to become ready. */
private FeedMapping waitForFeedToBeReady(
GoogleAdsClient googleAdsServiceClient, long customerId, String feedResourceName) {
int numAttempts = 0;
int sleepSeconds = 0;
// Waits for Google's servers to setup the feed with feed attributes and attribute mapping.
// This process is asynchronous, so we wait until the feed mapping is created, with exponential
// backoff.
while (numAttempts < MAX_FEEDMAPPING_RETRIEVAL_ATTEMPTS) {
Optional<FeedMapping> feedMapping =
getFeedMapping(googleAdsServiceClient, customerId, feedResourceName);
if (feedMapping.isPresent()) {
System.out.printf("Feed with resource name '%s' is now ready.%n", feedResourceName);
return feedMapping.get();
} else {
numAttempts++;
sleepSeconds = (int) (5 * Math.pow(2, numAttempts));
System.out.printf(
"Checked: %d time(s). Feed is not ready "
+ "yet. Waiting %d seconds before trying again.%n",
numAttempts, sleepSeconds);
try {
Thread.sleep(sleepSeconds * 1000);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
throw new RuntimeException(e);
}
}
}
throw new ApiException(
String.format("Feed is not ready after %d retries.", numAttempts),
null,
GrpcStatusCode.of(Code.DEADLINE_EXCEEDED),
true);
}
/** Retrieves the {@link FeedMapping} for a given feed. */
private Optional<FeedMapping> getFeedMapping(
GoogleAdsClient googleAdsServiceClient, long customerId, String feedResourceName) {
String query =
String.format(
"SELECT"
+ " feed_mapping.resource_name, "
+ " feed_mapping.attribute_field_mappings, "
+ " feed_mapping.status "
+ "FROM"
+ " feed_mapping "
+ "WHERE feed_mapping.feed = '%s'"
+ " AND feed_mapping.status = ENABLED "
+ " AND feed_mapping.placeholder_type = AFFILIATE_LOCATION "
+ "LIMIT 1",
feedResourceName);
try (GoogleAdsServiceClient client =
googleAdsServiceClient.getLatestVersion().createGoogleAdsServiceClient()) {
SearchPagedResponse response = client.search(String.valueOf(customerId), query);
Iterator<GoogleAdsRow> iterator = response.iterateAll().iterator();
if (iterator.hasNext()) {
return Optional.of(iterator.next().getFeedMapping());
}
return Optional.empty();
}
}
}
সি#
// 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
//
// 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.V13.Common;
using Google.Ads.GoogleAds.V13.Errors;
using Google.Ads.GoogleAds.V13.Resources;
using Google.Ads.GoogleAds.V13.Services;
using Google.Api.Gax;
using Grpc.Core;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using static Google.Ads.GoogleAds.V13.Enums.AffiliateLocationFeedRelationshipTypeEnum.Types;
using static Google.Ads.GoogleAds.V13.Enums.AffiliateLocationPlaceholderFieldEnum.Types;
using static Google.Ads.GoogleAds.V13.Enums.FeedOriginEnum.Types;
using static Google.Ads.GoogleAds.V13.Enums.PlaceholderTypeEnum.Types;
using static Google.Ads.GoogleAds.V13.Resources.Feed.Types;
namespace Google.Ads.GoogleAds.Examples.V13
{
/// <summary>
/// This code example adds a feed that syncs retail addresses for a given retail chain ID and
/// associates the feed with a campaign for serving affiliate location extensions.
/// </summary>
public class AddAffiliateLocationExtensions : ExampleBase
{
/// <summary>
/// Command line options for running the <see cref="AddAffiliateLocationExtensions"/>
/// example.
/// </summary>
public class Options : OptionsBase
{
/// <summary>
/// The customer ID for which the call is made.
/// </summary>
[Option("customerId", Required = true, HelpText =
"The customer ID for which the call is made.")]
public long CustomerId { get; set; }
/// <summary>
/// The retail chain ID.
/// </summary>
[Option("chainId", Required = true, HelpText =
"The retail chain ID.")]
public long ChainId { get; set; }
/// <summary>
/// The campaign ID for which the affiliate location extensions are added.
/// </summary>
[Option("campaignId", Required = true, HelpText =
"The campaign ID for which the affiliate location extensions are added.")]
public long CampaignId { 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);
AddAffiliateLocationExtensions codeExample = new AddAffiliateLocationExtensions();
Console.WriteLine(codeExample.Description);
codeExample.Run(new GoogleAdsClient(), options.CustomerId, options.ChainId, options.CampaignId);
}
// The maximum number of attempts to make to retrieve the FeedMappings before throwing an
// exception.
private const int MAX_FEEDMAPPING_RETRIEVAL_ATTEMPTS = 10;
/// <summary>
/// Returns a description about the code example.
/// </summary>
public override string Description =>
"This code example adds a feed that syncs retail addresses for a given retail chain " +
"ID and associates the feed with a campaign for serving affiliate location extensions.";
/// <summary>
/// Runs the code example.
/// </summary>
/// <param name="client">The Google Ads client.</param>
/// <param name="customerId">The customer ID for which the call is made.</param>
/// <param name="chainId">The retail chain ID.</param>
/// <param name="campaignId">
/// The campaign ID for which the affiliate location extensions are added.
/// </param>
public void Run(GoogleAdsClient client, long customerId, long chainId, long campaignId)
{
try
{
string feedResourceName = CreateAffiliateLocationExtensionFeed(
client, customerId, chainId);
// After the completion of the feed creation operation above the added feed will not
// be available for usage in a campaign feed until the feed mappings are created. We
// will wait with an exponential back-off policy until the feed mappings have been
// created.
FeedMapping feedMapping = WaitForFeedToBeReady(client, customerId,
feedResourceName);
CreateCampaignFeed(client, customerId, campaignId, feedMapping,
feedResourceName, chainId);
}
catch (GoogleAdsException e)
{
Console.WriteLine("Failure:");
Console.WriteLine($"Message: {e.Message}");
Console.WriteLine($"Failure: {e.Failure}");
Console.WriteLine($"Request ID: {e.RequestId}");
throw;
}
}
/// <summary>
/// Creates the Affiliate Location Extension feed.
/// </summary>
/// <param name="client">The Google Ads client.</param>
/// <param name="customerId">The customer ID for which the call is made.</param>
/// <param name="chainId">The retail chain ID.</param>
/// <returns>Resource name of the newly created Affiliate Location Extension feed.</returns>
private static string CreateAffiliateLocationExtensionFeed(GoogleAdsClient client,
long customerId, long chainId)
{
// Optional: Delete all existing location extension feeds. This is an optional step, and
// is required for this code example to run correctly more than once.
// 1. Google Ads only allows one location extension feed per email address.
// 2. A Google Ads account cannot have a location extension feed and an affiliate
// location extension feed at the same time.
DeleteLocationExtensionFeeds(client, customerId);
// Get the FeedServiceClient.
FeedServiceClient feedService = client.GetService(Services.V13.FeedService);
// Creates a feed that will sync to retail addresses for a given retail chain ID. Do not
// add FeedAttributes to this object as Google Ads will add them automatically because
// this will be a system generated feed.
Feed feed = new Feed()
{
Name = "Affiliate Location Extension feed #" + ExampleUtilities.GetRandomString(),
AffiliateLocationFeedData = new AffiliateLocationFeedData()
{
ChainIds = { chainId },
RelationshipType = AffiliateLocationFeedRelationshipType.GeneralRetailer
},
// Since this feed's contents will be managed by Google, you must set its origin to
// GOOGLE.
Origin = FeedOrigin.Google
};
FeedOperation operation = new FeedOperation()
{
Create = feed
};
// Adds the feed.
MutateFeedsResponse response =
feedService.MutateFeeds(customerId.ToString(), new[] { operation });
// Displays the results.
string feedResourceName = response.Results[0].ResourceName;
Console.WriteLine($"Affliate location extension feed created with resource name: " +
$"{feedResourceName}.");
return feedResourceName;
}
/// <summary>
/// Deletes the old location extension feeds.
/// </summary>
/// <param name="client">The Google Ads client.</param>
/// <param name="customerId">The customer ID for which the call is made.</param>
private static void DeleteLocationExtensionFeeds(GoogleAdsClient client, long customerId)
{
// To delete a location extension feed, you need to
// 1. Delete the CustomerFeed so that the location extensions from the feed stop
// serving.
// 2. Delete the feed so that Google Ads will no longer sync from the Business Profile
// account.
CustomerFeed[] oldCustomerFeeds =
GetLocationExtensionCustomerFeeds(client, customerId);
if (oldCustomerFeeds.Length != 0)
{
// Optional: You may also want to delete the CampaignFeeds and AdGroupFeeds.
DeleteCustomerFeeds(client, customerId, oldCustomerFeeds);
}
Feed[] feeds = GetLocationExtensionFeeds(client, customerId);
if (feeds.Length != 0)
{
RemoveFeeds(client, customerId, feeds);
}
}
/// <summary>
/// Gets the location extension feeds.
/// </summary>
/// <param name="client">The Google Ads client.</param>
/// <param name="customerId">The customer ID for which the call is made.</param>
/// <returns>The list of location extension feeds.</returns>
private static Feed[] GetLocationExtensionFeeds(GoogleAdsClient client, long customerId)
{
List<Feed> feeds = new List<Feed>();
GoogleAdsServiceClient googleAdsService = client.GetService(
Services.V13.GoogleAdsService);
// Create the query.
string query = $"SELECT feed.resource_name, feed.status, " +
$"feed.places_location_feed_data.email_address, " +
$"feed.affiliate_location_feed_data.chain_ids " +
$" from feed where feed.status = ENABLED";
PagedEnumerable<SearchGoogleAdsResponse, GoogleAdsRow> result =
googleAdsService.Search(customerId.ToString(), query);
foreach (GoogleAdsRow row in result)
{
// A location extension feed can be identified by checking whether the
// PlacesLocationFeedData field is set (Location extensions feeds) or
// AffiliateLocationFeedData field is set (Affiliate location extension feeds)
Feed feed = row.Feed;
if (feed.PlacesLocationFeedData != null || feed.AffiliateLocationFeedData != null)
{
feeds.Add(feed);
}
}
return feeds.ToArray();
}
/// <summary>
/// Removes the feeds.
/// </summary>
/// <param name="client">The Google Ads client.</param>
/// <param name="customerId">The customer ID for which the call is made.</param>
/// <param name="feeds">The list of feeds to remove.</param>
private static void RemoveFeeds(GoogleAdsClient client, long customerId, Feed[] feeds)
{
List<FeedOperation> operations = new List<FeedOperation>();
foreach (Feed feed in feeds)
{
FeedOperation operation = new FeedOperation()
{
Remove = feed.ResourceName,
};
operations.Add(operation);
}
FeedServiceClient feedService = client.GetService(
Services.V13.FeedService);
feedService.MutateFeeds(customerId.ToString(), operations.ToArray());
}
/// <summary>
/// Gets the location extension customer feeds.
/// </summary>
/// <param name="client">The Google Ads client.</param>
/// <param name="customerId">The customer ID for which the call is made.</param>
/// <returns>The list of location extension customer feeds.</returns>
private static CustomerFeed[] GetLocationExtensionCustomerFeeds(GoogleAdsClient client,
long customerId)
{
List<CustomerFeed> customerFeeds = new List<CustomerFeed>();
GoogleAdsServiceClient googleAdsService = client.GetService(
Services.V13.GoogleAdsService);
// Create the query. A location extension customer feed can be identified by filtering
// for placeholder_types=LOCATION (location extension feeds) or placeholder_types
// =AFFILIATE_LOCATION (affiliate location extension feeds)
string query = $"SELECT customer_feed.resource_name, customer_feed.feed, " +
$"customer_feed.status, customer_feed.matching_function.function_string from " +
$"customer_feed " +
$"WHERE customer_feed.placeholder_types CONTAINS " +
$"ANY(LOCATION, AFFILIATE_LOCATION) and customer_feed.status=ENABLED";
PagedEnumerable<SearchGoogleAdsResponse, GoogleAdsRow> result =
googleAdsService.Search(customerId.ToString(), query);
foreach (GoogleAdsRow row in result)
{
customerFeeds.Add(row.CustomerFeed);
}
return customerFeeds.ToArray();
}
/// <summary>
/// Deletes the customer feeds.
/// </summary>
/// <param name="client">The Google Ads client.</param>
/// <param name="customerId">The customer ID for which the call is made.</param>
/// <param name="customerFeeds">The customer feeds to delete.</param>
private static void DeleteCustomerFeeds(GoogleAdsClient client, long customerId,
CustomerFeed[] customerFeeds)
{
List<CustomerFeedOperation> operations = new List<CustomerFeedOperation>();
foreach (CustomerFeed customerFeed in customerFeeds)
{
CustomerFeedOperation operation = new CustomerFeedOperation()
{
Remove = customerFeed.ResourceName,
};
operations.Add(operation);
}
CustomerFeedServiceClient feedService = client.GetService(
Services.V13.CustomerFeedService);
feedService.MutateCustomerFeeds(customerId.ToString(), operations.ToArray());
}
/// <summary>
/// Gets the Affiliate Location Extension feed mapping.
/// </summary>
/// <param name="client">The Google Ads client.</param>
/// <param name="customerId">The customer ID for which the call is made.</param>
/// <param name="feedResourceName">The feed resource name.</param>
/// <returns>The newly created feed mapping.</returns>
private static FeedMapping GetAffiliateLocationExtensionFeedMapping(GoogleAdsClient client,
long customerId, string feedResourceName)
{
// Get the GoogleAdsService.
GoogleAdsServiceClient googleAdsService = client.GetService(
Services.V13.GoogleAdsService);
// Create the query.
string query = $"SELECT feed_mapping.resource_name, " +
$"feed_mapping.attribute_field_mappings, feed_mapping.status FROM " +
$"feed_mapping WHERE feed_mapping.feed = '{feedResourceName}' and " +
$"feed_mapping.status = ENABLED and feed_mapping.placeholder_type = " +
"AFFILIATE_LOCATION LIMIT 1";
// Issue a search request.
PagedEnumerable<SearchGoogleAdsResponse, GoogleAdsRow> result =
googleAdsService.Search(customerId.ToString(), query);
// Display the results.
GoogleAdsRow googleAdsRow = result.FirstOrDefault();
return (googleAdsRow == null) ? null : googleAdsRow.FeedMapping;
}
/// <summary>
/// Waits for the Affliate location extension feed to be ready.
/// </summary>
/// <param name="client">The Google Ads client.</param>
/// <param name="customerId">The customer ID for which the call is made.</param>
/// <param name="feedResourceName">Resource name of the feed.</param>
private static FeedMapping WaitForFeedToBeReady(GoogleAdsClient client, long customerId,
string feedResourceName)
{
int numAttempts = 0;
int sleepSeconds = 0;
while (numAttempts < MAX_FEEDMAPPING_RETRIEVAL_ATTEMPTS)
{
// Once you create a feed, Google's servers will setup the feed by creating feed
// attributes and feed mapping. Once the feed mapping is created, it is ready to be
// used for creating customer feed. This process is asynchronous, so we wait until
// the feed mapping is created, peforming exponential backoff.
FeedMapping feedMapping = GetAffiliateLocationExtensionFeedMapping(
client, customerId, feedResourceName);
if (feedMapping == null)
{
numAttempts++;
sleepSeconds = (int) (5 * Math.Pow(2, numAttempts));
Console.WriteLine($"Checked: #{numAttempts} time(s). Feed is not ready " +
$"yet. Waiting {sleepSeconds} seconds before trying again.");
Thread.Sleep(sleepSeconds * 1000);
}
else
{
Console.WriteLine($"Feed {feedResourceName} is now ready.");
return feedMapping;
}
}
throw new RpcException(new Status(StatusCode.DeadlineExceeded,
$"Feed is not ready after {MAX_FEEDMAPPING_RETRIEVAL_ATTEMPTS}" +
$" retries."));
}
/// <summary>
/// Creates the campaign feed.
/// </summary>
/// <param name="client">The Google Ads client.</param>
/// <param name="customerId">The customer ID for which the call is made.</param>
/// <param name="campaignId">
/// The campaign ID for which the affiliate location extensions are added.
/// </param>
/// <param name="feedMapping">
/// The affliate location extension feedmapping for <paramref name="feedResourceName"/>
/// </param>
/// <param name="feedResourceName">The feed resource name.</param>
/// <param name="chainId">The retail chain ID.</param>
private static void CreateCampaignFeed(GoogleAdsClient client, long customerId,
long campaignId, FeedMapping feedMapping, string feedResourceName, long chainId)
{
// Get the CampaignFeedService.
CampaignFeedServiceClient campaignFeedService = client.GetService(
Services.V13.CampaignFeedService);
long attributeIdForChainId = GetAttributeIdForChainId(feedMapping);
string feedId = FeedName.Parse(feedResourceName).FeedId;
string matchingFunction =
$"IN(FeedAttribute[{feedId}, {attributeIdForChainId}], {chainId})";
// Adds a CampaignFeed that associates the feed with this campaign for the
// AFFILIATE_LOCATION placeholder type.
CampaignFeed campaignFeed = new CampaignFeed()
{
Feed = feedResourceName,
PlaceholderTypes = { PlaceholderType.AffiliateLocation },
MatchingFunction = new MatchingFunction()
{
FunctionString = matchingFunction
},
Campaign = ResourceNames.Campaign(customerId, campaignId),
};
CampaignFeedOperation operation = new CampaignFeedOperation()
{
Create = campaignFeed
};
MutateCampaignFeedsResponse campaignFeedsResponse =
campaignFeedService.MutateCampaignFeeds(
customerId.ToString(), new[] { operation });
// Displays the result.
string addedCampaignFeed = campaignFeedsResponse.Results[0].ResourceName;
Console.WriteLine($"Campaign feed created with resource name: {addedCampaignFeed}.");
return;
}
/// <summary>
/// Gets the feed attribute ID for the retail chain Id.
/// </summary>
/// <param name="feedMapping">The feed mapping.</param>
/// <returns>The feeed attribute ID.</returns>
/// <exception cref="ArgumentException">
/// Affiliate location feed mapping isn't setup correctly.
/// </exception>
public static long GetAttributeIdForChainId(FeedMapping feedMapping)
{
foreach (AttributeFieldMapping fieldMapping in feedMapping.AttributeFieldMappings)
{
if (fieldMapping.AffiliateLocationField ==
AffiliateLocationPlaceholderField.ChainId)
{
return fieldMapping.FeedAttributeId;
}
}
throw new ArgumentException("Affiliate location feed mapping isn't setup correctly.");
}
}
}
পিএইচপি
<?php
/**
* 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.
*/
namespace Google\Ads\GoogleAds\Examples\Extensions;
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\Examples\Utils\Helper;
use Google\Ads\GoogleAds\Lib\OAuth2TokenBuilder;
use Google\Ads\GoogleAds\Lib\V13\GoogleAdsClient;
use Google\Ads\GoogleAds\Lib\V13\GoogleAdsClientBuilder;
use Google\Ads\GoogleAds\Lib\V13\GoogleAdsException;
use Google\Ads\GoogleAds\Lib\V13\GoogleAdsServerStreamDecorator;
use Google\Ads\GoogleAds\Util\V13\ResourceNames;
use Google\Ads\GoogleAds\V13\Common\MatchingFunction;
use Google\Ads\GoogleAds\V13\Enums\AffiliateLocationFeedRelationshipTypeEnum\AffiliateLocationFeedRelationshipType;
use Google\Ads\GoogleAds\V13\Enums\AffiliateLocationPlaceholderFieldEnum\AffiliateLocationPlaceholderField;
use Google\Ads\GoogleAds\V13\Enums\FeedOriginEnum\FeedOrigin;
use Google\Ads\GoogleAds\V13\Enums\PlaceholderTypeEnum\PlaceholderType;
use Google\Ads\GoogleAds\V13\Errors\GoogleAdsError;
use Google\Ads\GoogleAds\V13\Resources\AttributeFieldMapping;
use Google\Ads\GoogleAds\V13\Resources\CampaignFeed;
use Google\Ads\GoogleAds\V13\Resources\CustomerFeed;
use Google\Ads\GoogleAds\V13\Resources\Feed;
use Google\Ads\GoogleAds\V13\Resources\Feed\AffiliateLocationFeedData;
use Google\Ads\GoogleAds\V13\Resources\FeedMapping;
use Google\Ads\GoogleAds\V13\Services\CampaignFeedOperation;
use Google\Ads\GoogleAds\V13\Services\CustomerFeedOperation;
use Google\Ads\GoogleAds\V13\Services\FeedOperation;
use Google\Ads\GoogleAds\V13\Services\FeedServiceClient;
use Google\Ads\GoogleAds\V13\Services\GoogleAdsRow;
use Google\ApiCore\ApiException;
use RuntimeException;
/**
* This code example adds a feed that syncs retail addresses for a given retail chain ID and
* associates the feed with a campaign for serving affiliate location extensions.
*/
class AddAffiliateLocationExtensions
{
private const CUSTOMER_ID = 'INSERT_CUSTOMER_ID_HERE';
// The retail chain ID. For a complete list of valid retail chain IDs, see
// https://developers.google.com/adwords/api/docs/appendix/codes-formats#chain-ids.
private const CHAIN_ID = 'INSERT_CHAIN_ID_HERE';
// The campaign ID for which the affiliate location extensions are added.
private const CAMPAIGN_ID = 'INSERT_CAMPAIGN_ID_HERE';
// Optional: Delete all existing location extension feeds. This is required for this code
// example to run correctly more than once.
// 1. Google Ads only allows one location extension feed per email address.
// 2. A Google Ads account cannot have a location extension feed and an affiliate location
// extension feed at the same time.
private const DELETE_EXISTING_FEEDS = false;
// The maximum number of attempts to make to retrieve the feed mapping before throwing an
// exception.
private const MAX_FEED_MAPPING_RETRIEVAL_ATTEMPTS = 10;
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::CHAIN_ID => GetOpt::REQUIRED_ARGUMENT,
ArgumentNames::CAMPAIGN_ID => GetOpt::REQUIRED_ARGUMENT,
ArgumentNames::DELETE_EXISTING_FEEDS => GetOpt::OPTIONAL_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)
->build();
try {
self::runExample(
$googleAdsClient,
$options[ArgumentNames::CUSTOMER_ID] ?: self::CUSTOMER_ID,
$options[ArgumentNames::CHAIN_ID] ?: self::CHAIN_ID,
$options[ArgumentNames::CAMPAIGN_ID] ?: self::CAMPAIGN_ID,
filter_var(
$options[ArgumentNames::DELETE_EXISTING_FEEDS]
?: self::DELETE_EXISTING_FEEDS,
FILTER_VALIDATE_BOOLEAN
)
);
} 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 $chainId the retail chain ID
* @param int $campaignId the campaign ID for which the affiliate location extensions are added
* @param bool $shouldDeleteExistingFeeds true if it should delete the existing feeds. The
* example will throw an error if feeds already exist and this option is not set to true
*/
public static function runExample(
GoogleAdsClient $googleAdsClient,
int $customerId,
int $chainId,
int $campaignId,
bool $shouldDeleteExistingFeeds
) {
if ($shouldDeleteExistingFeeds) {
self::deleteLocationExtensionFeeds($googleAdsClient, $customerId);
}
$feedResourceName = self::createAffiliateLocationExtensionFeed(
$googleAdsClient,
$customerId,
$chainId
);
// After the completion of the feed creation operation above the added feed will not
// be available for usage in a campaign feed until the feed mapping is created.
// We then need to wait for the feed mapping to be created.
$feedMapping = self::waitForFeedToBeReady(
$googleAdsClient,
$customerId,
$feedResourceName
);
self::createCampaignFeed(
$googleAdsClient,
$customerId,
$campaignId,
$feedMapping,
$feedResourceName,
$chainId
);
}
/**
* Deletes the existing location extension feeds.
*
* @param GoogleAdsClient $googleAdsClient the Google Ads API client
* @param int $customerId the customer ID
*/
private static function deleteLocationExtensionFeeds(
GoogleAdsClient $googleAdsClient,
int $customerId
) {
// To delete a location extension feed, you need to
// 1. Delete the customer feed so that the location extensions from the feed stop serving.
// 2. Delete the feed so that Google Ads will no longer sync from the Business Profile
// account.
$customerFeeds = self::getLocationExtensionCustomerFeeds($googleAdsClient, $customerId);
if (!empty($customerFeeds)) {
// Optional: You may also want to delete the campaign and ad group feeds.
self::removeCustomerFeeds($googleAdsClient, $customerId, $customerFeeds);
}
$feeds = self::getLocationExtensionFeeds($googleAdsClient, $customerId);
if (!empty($feeds)) {
self::removeFeeds($googleAdsClient, $customerId, $feeds);
}
}
/**
* Gets the existing location extension customer feeds.
*
* @param GoogleAdsClient $googleAdsClient the Google Ads API client
* @param int $customerId the customer ID
* @return CustomerFeed[] the list of location extension customer feeds
*/
private static function getLocationExtensionCustomerFeeds(
GoogleAdsClient $googleAdsClient,
int $customerId
): array {
$customerFeeds = [];
$googleAdsServiceClient = $googleAdsClient->getGoogleAdsServiceClient();
// Creates the query. A location extension customer feed can be identified by filtering
// for placeholder_types as LOCATION (location extension feeds) or
// placeholder_types as AFFILIATE_LOCATION (affiliate location extension feeds).
$query = 'SELECT customer_feed.resource_name ' .
'FROM customer_feed ' .
'WHERE customer_feed.placeholder_types CONTAINS ANY(LOCATION, AFFILIATE_LOCATION) ' .
'AND customer_feed.status = ENABLED';
// Issues a search stream request.
/** @var GoogleAdsServerStreamDecorator $stream */
$stream = $googleAdsServiceClient->searchStream($customerId, $query);
// Iterates over all rows in all messages to collect the results.
foreach ($stream->iterateAllElements() as $googleAdsRow) {
/** @var GoogleAdsRow $googleAdsRow */
$customerFeeds[] = $googleAdsRow->getCustomerFeed();
}
return $customerFeeds;
}
/**
* Removes the customer feeds.
*
* @param GoogleAdsClient $googleAdsClient the Google Ads API client
* @param int $customerId the customer ID
* @param CustomerFeed[] $customerFeeds the list of customer feeds to remove
*/
private static function removeCustomerFeeds(
GoogleAdsClient $googleAdsClient,
int $customerId,
array $customerFeeds
) {
$operations = [];
foreach ($customerFeeds as $customerFeed) {
/** @var CustomerFeed $customerFeed */
$operations[] = new CustomerFeedOperation([
'remove' => $customerFeed->getResourceName()
]);
}
// Issues a mutate request to remove the customer feeds.
$googleAdsClient->getCustomerFeedServiceClient()->mutateCustomerFeeds(
$customerId,
$operations
);
}
/**
* Gets the existing location extension feeds.
*
* @param GoogleAdsClient $googleAdsClient the Google Ads API client
* @param int $customerId the customer ID
* @return Feed[] the list of location extension feeds
*/
private static function getLocationExtensionFeeds(
GoogleAdsClient $googleAdsClient,
int $customerId
): array {
$feeds = [];
$googleAdsServiceClient = $googleAdsClient->getGoogleAdsServiceClient();
// Creates the query.
$query = 'SELECT feed.resource_name ' .
'FROM feed ' .
'WHERE feed.status = ENABLED ' .
'AND feed.origin = USER';
// Issues a search stream request.
/** @var GoogleAdsServerStreamDecorator $stream */
$stream = $googleAdsServiceClient->searchStream($customerId, $query);
// Iterates over all rows in all messages to collect the results.
foreach ($stream->iterateAllElements() as $googleAdsRow) {
/** @var GoogleAdsRow $googleAdsRow */
$feeds[] = $googleAdsRow->getFeed();
}
return $feeds;
}
/**
* Removes the feeds.
*
* @param GoogleAdsClient $googleAdsClient the Google Ads API client
* @param int $customerId the customer ID
* @param Feed[] $feeds the list of feeds to remove
*/
private static function removeFeeds(
GoogleAdsClient $googleAdsClient,
int $customerId,
array $feeds
) {
$operations = [];
foreach ($feeds as $feed) {
/** @var Feed $feed */
$operations[] = new FeedOperation([
'remove' => $feed->getResourceName()
]);
}
// Issues a mutate request to remove the feeds.
$googleAdsClient->getFeedServiceClient()->mutateFeeds(
$customerId,
$operations
);
}
/**
* Creates the affiliate location extension feed.
*
* @param GoogleAdsClient $googleAdsClient the Google Ads API client
* @param int $customerId the customer ID
* @param int $chainId the retail chain ID
* @return string the resource name of the newly created affiliate location extension feed
*/
private static function createAffiliateLocationExtensionFeed(
GoogleAdsClient $googleAdsClient,
int $customerId,
int $chainId
): string {
// Creates a feed that will sync to retail addresses for a given retail chain ID.
// Do not add feed attributes, Google Ads will add them automatically because this will
// be a system generated feed.
$feed = new Feed([
'name' => 'Affiliate Location Extension feed #' . Helper::getPrintableDatetime(),
'affiliate_location_feed_data' => new AffiliateLocationFeedData([
'chain_ids' => [$chainId],
'relationship_type' => AffiliateLocationFeedRelationshipType::GENERAL_RETAILER
]),
// Since this feed's contents will be managed by Google, you must set its origin to
// GOOGLE.
'origin' => FeedOrigin::GOOGLE
]);
// Creates the feed operation.
$operation = new FeedOperation();
$operation->setCreate($feed);
// Issues a mutate request to add the feed and prints some information.
$feedServiceClient = $googleAdsClient->getFeedServiceClient();
$response = $feedServiceClient->mutateFeeds($customerId, [$operation]);
$feedResourceName = $response->getResults()[0]->getResourceName();
printf(
"Affiliate location extension feed created with resource name: '%s'.%s",
$feedResourceName,
PHP_EOL
);
return $feedResourceName;
}
/**
* Waits for the affiliate location extension feed to be ready. An exponential back-off
* policy with a maximum number of attempts is used to poll the server.
*
* @param GoogleAdsClient $googleAdsClient the Google Ads API client
* @param int $customerId the customer ID
* @param string $feedResourceName the feed resource name
* @throws RuntimeException if the feed mapping is still not ready and the maximum number of
* attempts has been reached
* @return FeedMapping the newly created feed mapping
*/
private static function waitForFeedToBeReady(
GoogleAdsClient $googleAdsClient,
int $customerId,
string $feedResourceName
): FeedMapping {
$numAttempts = 0;
while ($numAttempts < self::MAX_FEED_MAPPING_RETRIEVAL_ATTEMPTS) {
// Once you create a feed, Google's servers will setup the feed by creating feed
// attributes and feed mapping. Once the feed mapping is created, it is ready to be
// used for creating customer feed.
// This process is asynchronous, so we wait until the feed mapping is created,
// performing exponential backoff.
$feedMapping = self::getAffiliateLocationExtensionFeedMapping(
$googleAdsClient,
$customerId,
$feedResourceName
);
if (is_null($feedMapping)) {
$numAttempts++;
$sleepSeconds = intval(5 * pow(2, $numAttempts));
printf(
'Checked: %d time(s). Feed is not ready yet. ' .
'Waiting %d seconds before trying again.%s',
$numAttempts,
$sleepSeconds,
PHP_EOL
);
sleep($sleepSeconds);
} else {
printf("Feed '%s' is now ready.%s", $feedResourceName, PHP_EOL);
return $feedMapping;
}
}
throw new RuntimeException(sprintf(
"The affiliate location feed mapping is still not ready after %d attempt(s).%s",
self::MAX_FEED_MAPPING_RETRIEVAL_ATTEMPTS,
PHP_EOL
));
}
/**
* Gets the affiliate location extension feed mapping.
*
* @param GoogleAdsClient $googleAdsClient the Google Ads API client
* @param int $customerId the customer ID
* @param string $feedResourceName the feed resource name
* @return FeedMapping|null the feed mapping if it exists otherwise null
*/
private static function getAffiliateLocationExtensionFeedMapping(
GoogleAdsClient $googleAdsClient,
int $customerId,
string $feedResourceName
): ?FeedMapping {
$googleAdsServiceClient = $googleAdsClient->getGoogleAdsServiceClient();
// Creates a query that retrieves the feed mapping.
$query = sprintf(
"SELECT feed_mapping.resource_name, " .
"feed_mapping.attribute_field_mappings, " .
"feed_mapping.status " .
"FROM feed_mapping " .
"WHERE feed_mapping.feed = '%s' " .
"AND feed_mapping.status = ENABLED " .
"AND feed_mapping.placeholder_type = AFFILIATE_LOCATION " .
"LIMIT 1",
$feedResourceName
);
// Issues a search request.
$response = $googleAdsServiceClient->search(
$customerId,
$query,
['returnTotalResultsCount' => true]
);
return $response->getPage()->getPageElementCount() === 1
? $response->getIterator()->current()->getFeedMapping()
: null;
}
/**
* Creates the campaign feed.
*
* @param GoogleAdsClient $googleAdsClient the Google Ads API client
* @param int $customerId the customer ID
* @param int $campaignId the campaign ID for which the affiliate location extensions are added
* @param FeedMapping $feedMapping the affiliate location extension feed mapping
* @param string $feedResourceName the feed resource name
* @param int $chainId the retail chain ID
*/
private static function createCampaignFeed(
GoogleAdsClient $googleAdsClient,
int $customerId,
int $campaignId,
FeedMapping $feedMapping,
string $feedResourceName,
int $chainId
) {
$matchingFunction = sprintf(
'IN(FeedAttribute[%d, %d], %d)',
FeedServiceClient::parseName($feedResourceName)['feed'],
self::getAttributeIdForChainId($feedMapping),
$chainId
);
// Adds a campaign feed that associates the feed with this campaign for the
// AFFILIATE_LOCATION placeholder type.
$campaignFeed = new CampaignFeed([
'feed' => $feedResourceName,
'placeholder_types' => [PlaceholderType::AFFILIATE_LOCATION],
'matching_function' => new MatchingFunction(['function_string' => $matchingFunction]),
'campaign' => ResourceNames::forCampaign($customerId, $campaignId)
]);
// Creates the campaign feed operation.
$operation = new CampaignFeedOperation();
$operation->setCreate($campaignFeed);
// Issues a mutate request to add the campaign feed and prints some information.
$campaignFeedServiceClient = $googleAdsClient->getCampaignFeedServiceClient();
$response = $campaignFeedServiceClient->MutateCampaignFeeds($customerId, [$operation]);
printf(
"Campaign feed created with resource name: '%s'.%s",
$response->getResults()[0]->getResourceName(),
PHP_EOL
);
}
/**
* Gets the feed attribute ID for the retail chain ID.
*
* @param FeedMapping $feedMapping the feed mapping
* @@return int the feed attribute ID
*/
private static function getAttributeIdForChainId(FeedMapping $feedMapping): int
{
foreach ($feedMapping->getAttributeFieldMappings() as $fieldMapping) {
/** @var AttributeFieldMapping $fieldMapping */
if (
$fieldMapping->getAffiliateLocationField()
=== AffiliateLocationPlaceholderField::CHAIN_ID
) {
return $fieldMapping->getFeedAttributeId();
}
}
throw new RuntimeException(
"Affiliate location feed mapping isn't setup correctly." . PHP_EOL
);
}
}
AddAffiliateLocationExtensions::main();
পাইথন
#!/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.
"""Demonstrates how to add Affiliate Location extensions.
This example adds a feed that syncs retail addresses for a given retail chain ID
and associates the feed with a campaign for serving affiliate location
extensions.
"""
import argparse
import sys
from time import sleep
from uuid import uuid4
from google.ads.googleads.client import GoogleAdsClient
from google.ads.googleads.errors import GoogleAdsException
# The maximum number of attempts to retrieve the FeedMappings before throwing an
# exception.
MAX_FEEDMAPPING_RETRIEVAL_ATTEMPTS = 10
def main(client, customer_id, chain_id, campaign_id):
"""Demonstrates how to add Affiliate Location extensions.
Args:
client: An initialized instance.
customer_id: The client customer ID.
chain_id: The retail chain ID. See:
https://developers.google.com/google-ads/api/reference/data/codes-formats#chain-ids
for a complete list of valid retail chain IDs.
campaign_id: The campaign ID for which the affiliate location extensions
will be added.
"""
feed_resource_name = create_affiliate_location_extension_feed(
client, customer_id, chain_id
)
# After the completion of the feed creation operation above, the added
# feed will not be available for usage in a campaign feed until the feed
# mappings are created. We will wait with an exponential back-off policy
# until the feed mappings have been created.
feed_mapping = wait_for_feed_to_be_ready(
client, customer_id, feed_resource_name
)
create_campaign_feed(
client,
customer_id,
campaign_id,
feed_mapping,
feed_resource_name,
chain_id,
)
def create_affiliate_location_extension_feed(client, customer_id, chain_id):
"""Creates the Affiliate Location Extension feed.
Args:
client: The Google Ads API client.
customer_id: The Google Ads customer ID.
chain_id: The retail chain ID.
Returns:
The string resource name of the newly created Affiliate Location
Extension feed.
"""
# Optional: Remove all existing location extension feeds. This is an
# optional step, and is required for this code example to run correctly more
# than once.
# This is because Google Ads only allows one location extension feed per
# email address, and a Google Ads account cannot have a location extension
# feed and an affiliate location extension feed at the same time.
remove_location_extension_feeds(client, customer_id)
# Get the FeedServiceClient.
feed_service = client.get_service("FeedService")
# Create a feed that will sync to retail addresses for a given retail chain
# ID. Do not add FeedAttributes to this object as Google Ads will add
# them automatically as this will be a system generated feed.
feed_operation = client.get_type("FeedOperation")
feed = feed_operation.create
feed.name = f"Affiliate Location Extension feed #{uuid4()}"
feed.affiliate_location_feed_data.chain_ids.append(chain_id)
feed.affiliate_location_feed_data.relationship_type = (
client.enums.AffiliateLocationFeedRelationshipTypeEnum.GENERAL_RETAILER
)
# Since this feed's contents will be managed by Google, you must set its
# origin to GOOGLE.
feed.origin = client.enums.FeedOriginEnum.GOOGLE
# Add the feed.
mutate_feeds_response = feed_service.mutate_feeds(
customer_id=customer_id, operations=[feed_operation]
)
# Display the results.
feed_resource_name = mutate_feeds_response.results[0].resource_name
print(
"Affiliate location extension feed created with resource name: "
f"{feed_resource_name}."
)
return feed_resource_name
def remove_location_extension_feeds(client, customer_id):
"""Removes the old location extension feeds.
Args:
client: The Google Ads API client.
customer_id: The Google Ads customer ID.
"""
# To remove a location extension feed, you need to:
# 1. Remove the CustomerFeed so that the location extensions from the feed
# stop serving.
# 2. Remove the feed so that Google Ads will no longer sync from the
# Business Profile account.
# Optional: You may also want to remove the CampaignFeeds and AdGroupFeeds.
old_customer_feeds = get_location_extension_customer_feeds(
client, customer_id
)
if old_customer_feeds:
remove_customer_feeds(client, customer_id, old_customer_feeds)
feeds = get_location_extension_feeds(client, customer_id)
if feeds:
remove_feeds(client, customer_id, feeds)
def get_location_extension_feeds(client, customer_id):
"""Gets the location extension feeds.
Args:
client: The Google Ads API client.
customer_id: The Google Ads customer ID.
Returns:
The list of location extension feeds.
"""
googleads_service = client.get_service("GoogleAdsService")
# Create the query.
query = """
SELECT
feed.resource_name,
feed.status,
feed.places_location_feed_data.email_address,
feed.affiliate_location_feed_data.chain_ids
FROM feed
WHERE feed.status = ENABLED"""
search_results = googleads_service.search(
customer_id=customer_id, query=query
)
# A location extension feed can be identified by checking whether the
# PlacesLocationFeedData field is set (Location extensions feeds) or
# AffiliateLocationFeedData field is set (Affiliate location extension
# feeds)
return [
row.feed
for row in search_results
if row.feed.places_location_feed_data
or row.feed.affiliate_location_feed_data
]
def remove_feeds(client, customer_id, feeds):
"""Removes the feeds.
Args:
client: The Google Ads API client.
customer_id: The Google Ads customer ID.
feeds: The list of feeds to remove.
"""
operations = []
for feed in feeds:
operation = client.get_type("FeedOperation")
operation.remove = feed.resource_name
operations.append(operation)
feed_service = client.get_service("FeedService")
feed_service.mutate_feeds(customer_id=customer_id, operations=operations)
def get_location_extension_customer_feeds(client, customer_id):
"""Gets the location extension customer feeds.
Args:
client: The Google Ads API client.
customer_id: The customer ID from which to fetch feeds.
Returns:
A list of location extension customer feeds.
"""
googleads_service = client.get_service("GoogleAdsService")
# Create the query. A location extension customer feed can be identified by
# filtering for placeholder_types=LOCATION (location extension feeds) or
# placeholder_types =AFFILIATE_LOCATION (affiliate location extension feeds)
query = """
SELECT
customer_feed.resource_name,
customer_feed.feed,
customer_feed.status,
customer_feed.matching_function.function_string
FROM customer_feed
WHERE
customer_feed.placeholder_types CONTAINS ANY(LOCATION, AFFILIATE_LOCATION)
AND customer_feed.status=ENABLED"""
search_results = googleads_service.search(
customer_id=customer_id, query=query
)
return [row.customer_feed for row in search_results]
def remove_customer_feeds(client, customer_id, customer_feeds):
"""Removes the customer feeds.
Args:
client: The Google Ads API client.
customer_id: The Google Ads customer ID.
customer_feeds: The customer feeds to remove.
"""
operations = []
for customer_feed in customer_feeds:
operation = client.get_type("CustomerFeedOperation")
operation.remove = customer_feed.resource_name
operations.append(operation)
customer_feed_service = client.get_service("CustomerFeedService")
customer_feed_service.mutate_customer_feeds(
customer_id=customer_id, operations=operations
)
def get_affiliate_location_extension_feed_mapping(
client, customer_id, feed_resource_name
):
"""Gets the Affiliate Location Extension feed mapping.
Args:
client: The Google Ads API client.
customer_id: The Google Ads customer ID.
feed_resource_name: The feed resource name.
Returns:
The newly created feed mapping.
"""
# Get the GoogleAdsService.
googleads_service = client.get_service("GoogleAdsService")
# Create the query.
query = f"""
SELECT
feed_mapping.resource_name,
feed_mapping.attribute_field_mappings,
feed_mapping.status
FROM feed_mapping
WHERE
feed_mapping.feed = '{feed_resource_name}'
AND feed_mapping.status = ENABLED
AND feed_mapping.placeholder_type = AFFILIATE_LOCATION
LIMIT 1"""
# Issue a search request.
search_results = googleads_service.search(
customer_id=customer_id, query=query
)
# Return the feed mapping that results from the search.
# It is possible that the feed is not yet ready, so we catch the exception
# if the feed mapping is not yet available.
try:
row = next(iter(search_results))
except StopIteration:
return None
else:
return row.feed_mapping
def wait_for_feed_to_be_ready(client, customer_id, feed_resource_name):
"""Waits for the Affiliate location extension feed to be ready.
Args:
client: The Google Ads API client.
customer_id: The Google Ads customer ID.
feed_resource_name: The resource name of the feed.
Returns:
The newly created FeedMapping.
Raises:
Exception: if the feed is not ready after the specified number of
retries.
"""
num_attempts = 0
sleep_seconds = 0
while num_attempts < MAX_FEEDMAPPING_RETRIEVAL_ATTEMPTS:
# Once you create a feed, Google's servers will setup the feed by
# creating feed attributes and feed mapping. Once the feed mapping is
# created, it is ready to be used for creating customer feed.
# This process is asynchronous, so we wait until the feed mapping is
# created, performing exponential backoff.
feed_mapping = get_affiliate_location_extension_feed_mapping(
client, customer_id, feed_resource_name
)
if feed_mapping is None:
num_attempts += 1
sleep_seconds = 5 * 2 ** num_attempts
print(
f"Checked {num_attempts} time(s). Feed is not ready "
f"yet. Waiting {sleep_seconds} seconds before trying again."
)
sleep(sleep_seconds)
else:
print(f"Feed {feed_resource_name} is now ready.")
return feed_mapping
raise Exception(
f"Feed is not ready after "
f"{MAX_FEEDMAPPING_RETRIEVAL_ATTEMPTS} retries."
)
def create_campaign_feed(
client, customer_id, campaign_id, feed_mapping, feed_resource_name, chain_id
):
"""Creates the campaign feed.
Args:
client: The Google Ads API client.
customer_id: The Google Ads customer ID.
campaign_id: The campaign ID to which the affiliate location extensions
will be added.
feed_mapping: The affiliate location extension feedmapping for the feed
resource name.
feed_resource_name: The feed resource name.
chain_id: The retail chain ID.
"""
# Get the CampaignFeedService.
campaign_feed_service = client.get_service("CampaignFeedService")
feed_service = client.get_service("FeedService")
attribute_id_for_chain_id = get_attribute_id_for_chain_id(
client, feed_mapping
)
feed_id = feed_service.parse_feed_path(feed_resource_name)["feed_id"]
matching_function = (
f"IN(FeedAttribute[{feed_id}, {attribute_id_for_chain_id}], {chain_id})"
)
# Add a CampaignFeed that associates the feed with this campaign for
# the AFFILIATE_LOCATION placeholder type.
campaign_feed_operation = client.get_type("CampaignFeedOperation")
campaign_feed = campaign_feed_operation.create
campaign_feed.feed = feed_resource_name
campaign_feed.placeholder_types.append(
client.enums.PlaceholderTypeEnum.AFFILIATE_LOCATION
)
campaign_feed.matching_function.function_string = matching_function
campaign_feed.campaign = client.get_service(
"CampaignService"
).campaign_path(customer_id, campaign_id)
mutate_campaign_feeds_response = campaign_feed_service.mutate_campaign_feeds(
customer_id=customer_id, operations=[campaign_feed_operation]
)
# Display the result.
print(
"Campaign feed created with resource name: "
f"{mutate_campaign_feeds_response.results[0].resource_name}."
)
def get_attribute_id_for_chain_id(client, feed_mapping):
"""Gets the feed attribute ID for the retail chain ID.
Args:
client: The Google Ads API client.
feed_mapping: The FeedMapping in which to search.
Returns:
The feed attribute ID.
Raises:
Exception: If no AffiliateLocationField with a retail chain ID is found
in the FeedMapping.
"""
for field_mapping in feed_mapping.attribute_field_mappings:
if (
field_mapping.affiliate_location_field
== client.enums.AffiliateLocationPlaceholderFieldEnum.CHAIN_ID
):
return field_mapping.feed_attribute_id
raise Exception(
"No AffiliateLocationField with a retail chain ID was "
"found in the FeedMapping."
)
if __name__ == "__main__":
# will read the google-ads.yaml configuration file in the
# home directory if none is specified.
googleads_client = GoogleAdsClient.load_from_storage(version="v13")
parser = argparse.ArgumentParser(
description="Demonstrates how to add Affiliate Location extensions."
)
# 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",
"--chain_id",
type=int,
required=True,
help="The retail chain ID. See: "
"https://developers.google.com/google-ads/api/reference/data/codes-formats#chain-ids "
"for a complete list of valid retail chain IDs.",
)
parser.add_argument(
"-i",
"--campaign_id",
type=int,
required=True,
help="The campaign ID for which the affiliate location extensions will "
"be added.",
)
args = parser.parse_args()
try:
main(
googleads_client, args.customer_id, args.chain_id, args.campaign_id,
)
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)
রুবি
#!/usr/bin/env ruby
# Encoding: utf-8
#
# 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.
#
# This code example adds a feed that syncs retail addresses for a given retail
# chain ID and associates the feed with a campaign for serving affiliate
# location extensions.
require 'optparse'
require 'google/ads/google_ads'
require 'date'
def add_affiliate_location_extensions(
customer_id,
chain_id,
campaign_id,
should_delete_existing_feeds)
# GoogleAdsClient will read a config file from
# ENV['HOME']/google_ads_config.rb when called without parameters
client = Google::Ads::GoogleAds::GoogleAdsClient.new
if should_delete_existing_feeds
delete_location_extension_feeds(client, customer_id)
end
feed_resource_name = create_affiliate_location_extension_feed(
client,
customer_id,
chain_id,
)
# After the completion of the feed creation operation above the added feed
# will not be available for usage in a campaign feed until the feed mapping
# is created. We then need to wait for the feed mapping to be created.
feed_mapping = wait_for_feed_to_be_ready(
client,
customer_id,
feed_resource_name,
)
create_campaign_feed(
client,
customer_id,
campaign_id,
feed_mapping,
feed_resource_name,
chain_id,
)
end
# Deletes the existing location extension feeds.
def delete_location_extension_feeds(client, customer_id)
# To delete a location extension feed, you need to
# 1. Delete the customer feed so that the location extensions from the feed
# stop serving.
# 2. Delete the feed so that Google Ads will no longer sync from the Business
# Profile account.
customer_feeds = get_location_extension_customer_feeds(client, customer_id)
unless customer_feeds.empty?
# Optional: You may also want to delete the campaign and ad group feeds.
remove_customer_feeds(client, customer_id, customer_feeds)
end
feeds = get_location_extension_feeds(client, customer_id)
unless feeds.empty?
remove_feeds(client, customer_id, customer_feeds)
end
end
# Gets the existing location extension customer feeds.
def get_location_extension_customer_feeds(client, customer_id)
customer_feeds = []
# Creates the query. A location extension customer feed can be identified
# by filtering for placeholder_types as LOCATION (location extension feeds) or
# placeholder_types as AFFILIATE_LOCATION (affiliate location extension feeds).
query = <<~QUERY
SELECT customer_feed.resource_name
FROM customer_feed
WHERE customer_feed.placeholder_types CONTAINS ANY(LOCATION, AFFILIATE_LOCATION)
AND customer_feed.status = ENABLED
QUERY
# Issues a search stream request.
responses = client.service.google_ads.search_stream(
customer_id: customer_id,
query: query,
)
# Iterates over all rows in all messages to collect the results.
responses.each do |response|
response.results.each do |row|
customer_feeds << row.customer_feed
end
end
customer_feeds
end
# Removes the customer feeds.
def remove_customer_feeds(client, customer_id, customer_feeds)
operations = []
customer_feeds.each do |customer_feed|
operations << client.operation.remove_resource.customer_feed(
customer_feed.resource_name)
end
# Issues a mutate request to remove the customer feeds.
client.service.customer_feed.mutate_customer_feeds(customer_id, operations)
end
# Gets the existing location extension feeds.
def get_location_extension_feeds(client, customer_id)
feeds = []
# Creates the query.
query = <<~QUERY
SELECT feed.resource_name
FROM feed
WHERE feed.status = ENABLED
AND feed.origin = USER
QUERY
# Issues a search stream request.
responses = client.service.google_ads.search_stream(
customer_id: customer_id,
query: query,
)
# Iterates over all rows in all messages to collect the results.
responses.each do |response|
response.results.each do |row|
feeds << row.feed
end
end
feeds
end
# Removes the feeds.
def remove_feeds(client, customer_id, feeds)
operations = []
feeds.each do |feed|
operations << client.operation.remove_resource.feed(feed.resource_name)
end
# Issues a mutate request to remove the feeds.
client.service.feed.mutate_feeds(customer_id, operations)
end
# Creates the affiliate location extension feed.
def create_affiliate_location_extension_feed(client, customer_id, chain_id)
# Creates a feed that will sync to retail addresses for a given retail
# chain ID.
# Do not add feed attributes, Google Ads will add them automatically because
# this will be a system generated feed.
operation = client.operation.create_resource.feed do |feed|
feed.name = "Affiliate Location Extension feed ##{(Time.new.to_f * 1000).to_i}"
feed.affiliate_location_feed_data = client.resource.affiliate_location_feed_data do |data|
data.chain_ids << chain_id
data.relationship_type = :GENERAL_RETAILER
end
# Since this feed's contents will be managed by Google, you must set its
# origin to GOOGLE.
feed.origin = :GOOGLE
end
# Issues a mutate request to add the feed and prints some information.
response = client.service.feed.mutate_feeds(
customer_id: customer_id,
operations: [operation],
)
feed_resource_name = response.results.first.resource_name
puts "Affiliate location extension feed created with resource name: #{feed_resource_name}"
feed_resource_name
end
# Waits for the affiliate location extension feed to be ready. An exponential
# back-off policy with a maximum number of attempts is used to poll the server.
def wait_for_feed_to_be_ready(client, customer_id, feed_resource_name)
number_of_attempts = 0
while number_of_attempts < MAX_FEEDMAPPING_RETRIEVAL_ATTEMPTS
# Once you create a feed, Google's servers will setup the feed by creating
# feed attributes and feed mapping. Once the feed mapping is created, it is
# ready to be used for creating customer feed.
# This process is asynchronous, so we wait until the feed mapping is
# created, performing exponential backoff.
feed_mapping = get_affiliated_location_extension_feed_mapping(
client, customer_id, feed_resource_name)
if feed_mapping.nil?
number_of_attempts += 1
sleep_seconds = POLL_FREQUENCY_SECONDS * (2 ** number_of_attempts)
puts "Checked #{number_of_attempts} time(s). Feed is not ready yet. " \
"Waiting #{sleep_seconds} seconds before trying again."
sleep sleep_seconds
else
puts "Feed #{feed_resource_name} is now ready."
return feed_mapping
end
end
raise "The affiliate location feed mapping is still not ready after " \
"#{MAX_FEEDMAPPING_RETRIEVAL_ATTEMPTS} attempt(s)."
end
# Gets the affiliate location extension feed mapping.
def get_affiliated_location_extension_feed_mapping(
client,
customer_id,
feed_resource_name)
# Creates a query that retrieves the feed mapping.
query = <<~QUERY
SELECT feed_mapping.resource_name,
feed_mapping.attribute_field_mappings,
feed_mapping.status
FROM feed_mapping
WHERE feed_mapping.feed = '#{feed_resource_name}'
AND feed_mapping.status = ENABLED
AND feed_mapping.placeholder_type = AFFILIATE_LOCATION
LIMIT 1
QUERY
# Issues a search request
responses = client.service.google_ads.search(
customer_id: customer_id,
query: query,
return_total_results_count: true,
)
response = responses.page.response
response.total_results_count == 1 ? response.results.first.feed_mapping : nil
end
# Creates the campaign feed.
def create_campaign_feed(
client,
customer_id,
campaign_id,
feed_mapping,
feed_resource_name,
chain_id)
matching_function = "IN(FeedAttribute[#{feed_resource_name.split('/')[3]}, " \
"#{get_attribute_id_for_chain_id(feed_mapping)}], #{chain_id})"
# Adds a campaign feed that associates the feed with this campaign for the
# AFFILIATE_LOCATION placeholder type.
operation = client.operation.create_resource.campaign_feed do |cf|
cf.feed = feed_resource_name
cf.placeholder_types << :AFFILIATE_LOCATION
cf.matching_function = client.resource.matching_function do |m|
m.function_string = matching_function
end
cf.campaign = client.path.campaign(customer_id, campaign_id)
end
# Issues a mutate request to add the campaign feed and prints some information.
response = client.service.campaign_feed.mutate_campaign_feeds(
customer_id: customer_id,
operations: [operation],
)
puts "Campaign feed created with resource name: " \
"#{response.results.first.resource_name}"
end
# Gets the feed attribute ID for the retail chain ID.
def get_attribute_id_for_chain_id(feed_mapping)
feed_mapping.attribute_field_mappings.each do |fm|
if fm.affiliate_location_field == :CHAIN_ID
return fm.feed_attribute_id
end
end
raise "Affiliate location feed mapping isn't setup correctly."
end
if __FILE__ == $0
POLL_FREQUENCY_SECONDS = 5
MAX_FEEDMAPPING_RETRIEVAL_ATTEMPTS = 10
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[:chain_id] = 'INSERT_CHAIN_ID_HERE'
options[:campaign_id] = 'INSERT_CAMPAIGN_ID_HERE'
options[:should_delete_existing_feeds] = false
OptionParser.new do |opts|
opts.banner = sprintf('Usage: %s [options]', File.basename(__FILE__))
opts.separator ''
opts.separator 'Options:'
opts.on('-C', '--customer-id CUSTOMER-ID', String, 'Customer ID') do |v|
options[:customer_id] = v
end
opts.on('-N', '--chain-id CHAIN-ID', String, 'Chain ID') do |v|
options[:chain_id] = v
end
opts.on('-c', '--campaign-id CAMPAIGN-ID', String, 'Campaign ID') do |v|
options[:campaign_id] = v
end
opts.on('-D', '--should-delete-existing-feeds SHOULD-DELETE-EXISTING-FEEDS',
TrueClass, 'Should delete existing feeds') do |v|
options[:should_delete_existing_feeds] = v
end
opts.separator ''
opts.separator 'Help:'
opts.on_tail('-h', '--help', 'Show this message') do
puts opts
exit
end
end.parse!
begin
add_affiliate_location_extensions(
options.fetch(:customer_id).tr("-", ""),
options.fetch(:chain_id).to_i,
options.fetch(:campaign_id),
options[:should_delete_existing_feeds])
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
পার্ল
#!/usr/bin/perl -w
#
# 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
#
# 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 code example adds a feed that syncs retail addresses for a given retail
# chain ID and associates the feed with a campaign for serving affiliate location
# extensions.
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::SearchStreamHandler;
use Google::Ads::GoogleAds::V13::Resources::Feed;
use Google::Ads::GoogleAds::V13::Resources::AffiliateLocationFeedData;
use Google::Ads::GoogleAds::V13::Resources::CampaignFeed;
use Google::Ads::GoogleAds::V13::Common::MatchingFunction;
use
Google::Ads::GoogleAds::V13::Enums::AffiliateLocationFeedRelationshipTypeEnum
qw(GENERAL_RETAILER);
use Google::Ads::GoogleAds::V13::Enums::FeedOriginEnum qw(GOOGLE);
use Google::Ads::GoogleAds::V13::Enums::PlaceholderTypeEnum
qw(AFFILIATE_LOCATION);
use Google::Ads::GoogleAds::V13::Enums::AffiliateLocationPlaceholderFieldEnum
qw(CHAIN_ID);
use
Google::Ads::GoogleAds::V13::Services::CustomerFeedService::CustomerFeedOperation;
use Google::Ads::GoogleAds::V13::Services::FeedService::FeedOperation;
use
Google::Ads::GoogleAds::V13::Services::CampaignFeedService::CampaignFeedOperation;
use Google::Ads::GoogleAds::V13::Utils::ResourceNames;
use Getopt::Long qw(:config auto_help);
use Pod::Usage;
use Cwd qw(abs_path);
use Data::Uniqid qw(uniqid);
use Time::HiRes qw(sleep);
# The maximum number of attempts to make to retrieve the feed mapping before
# throwing an exception.
use constant MAX_FEED_MAPPING_RETRIEVAL_ATTEMPTS => 10;
# 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";
# The retail chain ID. For a complete list of valid retail chain IDs, see
# https://developers.google.com/google-ads/api/reference/data/codes-formats#chain-ids.
my $chain_id = "INSERT_CHAIN_ID_HERE";
# The campaign ID for which the affiliate location extensions are added.
my $campaign_id = "INSERT_CAMPAIGN_ID_HERE";
# Optional: Delete all existing location extension feeds. This is required for
# this code example to run correctly more than once.
# 1. Google Ads only allows one location extension feed per email address.
# 2. A Google Ads account cannot have a location extension feed and an affiliate
# location extension feed at the same time.
my $delete_existing_feeds = 0;
sub add_affiliate_location_extensions {
my ($api_client, $customer_id, $chain_id, $campaign_id,
$delete_existing_feeds)
= @_;
if ($delete_existing_feeds) {
delete_location_extension_feeds($api_client, $customer_id);
}
my $feed_resource_name =
create_affiliate_location_extension_feed($api_client, $customer_id,
$chain_id);
# After the completion of the feed creation operation above the added feed
# will not be available for usage in a campaign feed until the feed mapping
# is created.
# We will wait with an exponential back-off policy until the feed mapping has
# been created.
my $feed_mapping =
wait_for_feed_to_be_ready($api_client, $customer_id, $feed_resource_name);
create_campaign_feed($api_client, $customer_id, $campaign_id, $feed_mapping,
$feed_resource_name, $chain_id);
return 1;
}
# Deletes the existing location extension feeds.
sub delete_location_extension_feeds {
my ($api_client, $customer_id) = @_;
# To delete a location extension feed, you need to
# 1. Delete the customer feed so that the location extensions from the feed stop serving.
# 2. Delete the feed so that Google Ads will no longer sync from the Business Profile account.
my $customer_feeds =
get_location_extension_customer_feeds($api_client, $customer_id);
if (scalar @$customer_feeds > 0) {
# Optional: You may also want to delete the campaign and ad group feeds.
remove_customer_feeds($api_client, $customer_id, $customer_feeds);
}
my $feeds = get_location_extension_feeds($api_client, $customer_id);
if (scalar @$feeds > 0) {
remove_feeds($api_client, $customer_id, $feeds);
}
}
# Gets the existing location extension customer feeds.
sub get_location_extension_customer_feeds {
my ($api_client, $customer_id) = @_;
my $customer_feeds = [];
my $google_ads_service = $api_client->GoogleAdsService();
# Create the query. A location extension customer feed can be identified by
# filtering for placeholder_types as LOCATION (location extension feeds) or
# placeholder_types as AFFILIATE_LOCATION (affiliate location extension feeds).
my $search_query =
"SELECT customer_feed.resource_name FROM customer_feed " .
"WHERE customer_feed.placeholder_types CONTAINS " .
"ANY(LOCATION, AFFILIATE_LOCATION) AND customer_feed.status = ENABLED";
my $search_stream_handler =
Google::Ads::GoogleAds::Utils::SearchStreamHandler->new({
service => $google_ads_service,
request => {
customerId => $customer_id,
query => $search_query
}});
# Issue a search stream request.
$search_stream_handler->process_contents(
sub {
my $google_ads_row = shift;
push @$customer_feeds, $google_ads_row->{customerFeed};
});
return $customer_feeds;
}
# Removes the customer feeds.
sub remove_customer_feeds {
my ($api_client, $customer_id, $customer_feeds) = @_;
my $operations = [];
foreach my $customer_feed (@$customer_feeds) {
push @$operations,
Google::Ads::GoogleAds::V13::Services::CustomerFeedService::CustomerFeedOperation
->new({remove => $customer_feed->{resourceName}});
}
# Issue a mutate request to remove the customer feeds.
$api_client->CustomerFeedService()->mutate({
customerId => $customer_id,
operations => $operations
});
}
# Gets the existing location extension feeds.
sub get_location_extension_feeds {
my ($api_client, $customer_id) = @_;
my $feeds = [];
my $google_ads_service = $api_client->GoogleAdsService();
# Create the query.
my $search_query = "SELECT feed.resource_name FROM feed " .
"WHERE feed.status = ENABLED AND feed.origin = USER";
my $search_stream_handler =
Google::Ads::GoogleAds::Utils::SearchStreamHandler->new({
service => $google_ads_service,
request => {
customerId => $customer_id,
query => $search_query
}});
# Issue a search stream request.
$search_stream_handler->process_contents(
sub {
my $google_ads_row = shift;
push @$feeds, $google_ads_row->{feed};
});
return $feeds;
}
# Removes the feeds.
sub remove_feeds {
my ($api_client, $customer_id, $feeds) = @_;
my $operations = [];
foreach my $feed (@$feeds) {
push @$operations,
Google::Ads::GoogleAds::V13::Services::FeedService::FeedOperation->new(
{remove => $feed->{resourceName}});
}
# Issue a mutate request to remove the feeds.
$api_client->FeedService()->mutate({
customerId => $customer_id,
operations => $operations
});
}
# Creates the affiliate location extension feed.
sub create_affiliate_location_extension_feed {
my ($api_client, $customer_id, $chain_id) = @_;
# Create a feed that will sync to retail addresses for a given retail chain ID.
# Do not add feed attributes, Google Ads will add them automatically because
# this will be a system generated feed.
my $feed = Google::Ads::GoogleAds::V13::Resources::Feed->new({
name => "Affiliate Location Extension feed #" . uniqid(),
affiliateLocationFeedData =>
Google::Ads::GoogleAds::V13::Resources::AffiliateLocationFeedData->new({
chainIds => [$chain_id],
relationshipType => GENERAL_RETAILER
}
),
# Since this feed's contents will be managed by Google, you must set its
# origin to GOOGLE.
origin => GOOGLE
});
# Create the feed operation.
my $operation =
Google::Ads::GoogleAds::V13::Services::FeedService::FeedOperation->new({
create => $feed
});
# Issue a mutate request to add the feed and print some information.
my $response = $api_client->FeedService()->mutate({
customerId => $customer_id,
operations => [$operation]});
my $feed_resource_name = $response->{results}[0]{resourceName};
printf
"Affiliate location extension feed created with resource name: '%s'.\n",
$feed_resource_name;
return $feed_resource_name;
}
# Waits for the affiliate location extension feed to be ready.
sub wait_for_feed_to_be_ready {
my ($api_client, $customer_id, $feed_resource_name) = @_;
my $num_attempts = 0;
while ($num_attempts < MAX_FEED_MAPPING_RETRIEVAL_ATTEMPTS) {
# Once you create a feed, Google's servers will setup the feed by creating
# feed attributes and feed mapping. Once the feed mapping is created, it is
# ready to be used for creating customer feed.
# This process is asynchronous, so we wait until the feed mapping is created,
# performing exponential backoff.
my $feed_mapping =
get_affiliate_location_extension_feed_mapping($api_client, $customer_id,
$feed_resource_name);
if (!$feed_mapping) {
$num_attempts++;
my $sleep_seconds = 5 * (2**$num_attempts);
printf "Checked: %d time(s). Feed is not ready yet. " .
"Waiting %d seconds before trying again.\n",
$num_attempts,
$sleep_seconds;
sleep($sleep_seconds);
} else {
printf "Feed '%s' is now ready.\n", $feed_resource_name;
return $feed_mapping;
}
}
die(
sprintf "The affiliate location feed mapping is still not ready " .
"after %d attempt(s).\n",
MAX_FEED_MAPPING_RETRIEVAL_ATTEMPTS
);
}
# Gets the affiliate location extension feed mapping.
sub get_affiliate_location_extension_feed_mapping {
my ($api_client, $customer_id, $feed_resource_name) = @_;
# Create a query that retrieves the feed mapping.
my $search_query =
"SELECT feed_mapping.resource_name, " .
"feed_mapping.attribute_field_mappings, " .
"feed_mapping.status FROM feed_mapping " .
"WHERE feed_mapping.feed = '$feed_resource_name' " .
"AND feed_mapping.status = ENABLED " .
"AND feed_mapping.placeholder_type = AFFILIATE_LOCATION LIMIT 1";
# Issue a search request.
my $response = $api_client->GoogleAdsService()->search({
customerId => $customer_id,
query => $search_query,
returnTotalResultsCount => "true"
});
return $response->{totalResultsCount} && $response->{totalResultsCount} == 1
? $response->{results}[0]{feedMapping}
: undef;
}
# Create the campaign feed.
sub create_campaign_feed {
my ($api_client, $customer_id, $campaign_id, $feed_mapping,
$feed_resource_name, $chain_id)
= @_;
my $feed_id = $1 if $feed_resource_name =~ /(\d+)$/;
my $attribute_id_for_chain_id = get_attribute_id_for_chain_id($feed_mapping);
my $matching_function =
"IN(FeedAttribute[$feed_id, $attribute_id_for_chain_id], $chain_id)";
# Add a campaign feed that associates the feed with this campaign for the
# AFFILIATE_LOCATION placeholder type.
my $campaign_feed = Google::Ads::GoogleAds::V13::Resources::CampaignFeed->new(
{
feed => $feed_resource_name,
placeholderTypes => AFFILIATE_LOCATION,
matchingFunction =>
Google::Ads::GoogleAds::V13::Common::MatchingFunction->new({
functionString => $matching_function
}
),
campaign => Google::Ads::GoogleAds::V13::Utils::ResourceNames::campaign(
$customer_id, $campaign_id
)});
# Create the campaign feed operation.
my $operation =
Google::Ads::GoogleAds::V13::Services::CampaignFeedService::CampaignFeedOperation
->new({
create => $campaign_feed
});
# Issue a mutate request to add the campaign feed and print some information.
my $response = $api_client->CampaignFeedService()->mutate({
customerId => $customer_id,
operations => [$operation]});
printf
"Campaign feed created with resource name: '%s'.\n",
$response->{results}[0]{resourceName};
}
# Gets the feed attribute ID for the retail chain ID.
sub get_attribute_id_for_chain_id {
my ($feed_mapping) = @_;
foreach my $field_mapping (@{$feed_mapping->{attributeFieldMappings}}) {
if ($field_mapping->{affiliateLocationField} eq CHAIN_ID) {
return $field_mapping->{feedAttributeId};
}
}
die "Affiliate location feed mapping isn't setup correctly.";
}
# 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,
"chain_id=i" => \$chain_id,
"campaign_id=i" => \$campaign_id,
"delete_existing_feeds=i" => \$delete_existing_feeds,
);
# 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, $chain_id, $campaign_id);
# Call the example.
add_affiliate_location_extensions($api_client, $customer_id =~ s/-//gr,
$chain_id, $campaign_id, $delete_existing_feeds);
=pod
=head1 NAME
add_affiliate_location_extensions
=head1 DESCRIPTION
This code example adds a feed that syncs retail addresses for a given retail
chain ID and associates the feed with a campaign for serving affiliate location
extensions.
=head1 SYNOPSIS
add_affiliate_location_extensions.pl [options]
-help Show the help message.
-customer_id The Google Ads customer ID.
-chain_id The retail chain ID.
-campaign_id The campaign ID for which the affiliate
location extensions are added.
-delete_existing_feeds [optional] Non-zero if it should delete
the existing feeds.
=cut