Add Real Estate Feed

Java

// 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.

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

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.v16.enums.FeedAttributeTypeEnum.FeedAttributeType;
import com.google.ads.googleads.v16.enums.PlaceholderTypeEnum.PlaceholderType;
import com.google.ads.googleads.v16.enums.RealEstatePlaceholderFieldEnum.RealEstatePlaceholderField;
import com.google.ads.googleads.v16.errors.GoogleAdsError;
import com.google.ads.googleads.v16.errors.GoogleAdsException;
import com.google.ads.googleads.v16.resources.AttributeFieldMapping;
import com.google.ads.googleads.v16.resources.Feed;
import com.google.ads.googleads.v16.resources.FeedAttribute;
import com.google.ads.googleads.v16.resources.FeedItem;
import com.google.ads.googleads.v16.resources.FeedItemAttributeValue;
import com.google.ads.googleads.v16.resources.FeedMapping;
import com.google.ads.googleads.v16.services.FeedItemOperation;
import com.google.ads.googleads.v16.services.FeedItemServiceClient;
import com.google.ads.googleads.v16.services.FeedMappingOperation;
import com.google.ads.googleads.v16.services.FeedMappingServiceClient;
import com.google.ads.googleads.v16.services.FeedOperation;
import com.google.ads.googleads.v16.services.FeedServiceClient;
import com.google.ads.googleads.v16.services.GoogleAdsRow;
import com.google.ads.googleads.v16.services.GoogleAdsServiceClient;
import com.google.ads.googleads.v16.services.GoogleAdsServiceClient.SearchPagedResponse;
import com.google.ads.googleads.v16.services.MutateFeedItemResult;
import com.google.ads.googleads.v16.services.MutateFeedItemsResponse;
import com.google.ads.googleads.v16.services.MutateFeedMappingResult;
import com.google.ads.googleads.v16.services.MutateFeedMappingsResponse;
import com.google.ads.googleads.v16.services.MutateFeedsResponse;
import com.google.ads.googleads.v16.services.SearchGoogleAdsRequest;
import com.google.common.collect.ImmutableList;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/** Adds a real estate feed, creates the feed mapping, and adds items to the feed. */
public class AddRealEstateFeed {
  private static final int PAGE_SIZE = 1_000;

  private static class AddRealEstateFeedParams extends CodeSampleParams {

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

  public static void main(String[] args) {
    AddRealEstateFeedParams params = new AddRealEstateFeedParams();
    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");
    }

    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 AddRealEstateFeed().runExample(googleAdsClient, params);
    } 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 params the AddRealEstateFeedParams for the example.
   * @throws GoogleAdsException if an API request failed with one or more service errors.
   */
  private void runExample(GoogleAdsClient googleAdsClient, AddRealEstateFeedParams params) {
    // Creates a new feed, but you can fetch and re-use an existing feed by skipping the
    // createFeed method and inserting the feed resource name of the existing feed into the
    // getFeed method.
    String feedResourceName = createFeed(googleAdsClient, params.customerId);
    // Gets the page feed details.
    Map<RealEstatePlaceholderField, FeedAttribute> feedAttributes =
        getFeed(googleAdsClient, params.customerId, feedResourceName);
    // Creates the feed mapping.
    createFeedMapping(googleAdsClient, params.customerId, feedAttributes, feedResourceName);
    // Creates feed items and adds them to the feed.
    createFeedItems(googleAdsClient, params.customerId, feedAttributes, feedResourceName);
  }

  /**
   * Creates a feed.
   *
   * @param googleAdsClient the Google Ads API client.
   * @param customerId the client customer ID.
   * @return a String of the feed resource name.
   */
  private String createFeed(GoogleAdsClient googleAdsClient, long customerId) {
    // Creates a Listing ID attribute.
    FeedAttribute listingIdAttribute =
        FeedAttribute.newBuilder().setType(FeedAttributeType.STRING).setName("Listing ID").build();

    // Creates a Listing Name attribute.
    FeedAttribute listingNameAttribute =
        FeedAttribute.newBuilder()
            .setType(FeedAttributeType.STRING)
            .setName("Listing Name")
            .build();

    // Creates a Final URLs attribute.
    FeedAttribute finalUrlsAttribute =
        FeedAttribute.newBuilder()
            .setType(FeedAttributeType.URL_LIST)
            .setName("Final URLs")
            .build();

    // Creates an Image URL attribute
    FeedAttribute imageUrlAttribute =
        FeedAttribute.newBuilder().setType(FeedAttributeType.URL).setName("Image URL").build();

    // Creates a Contextual Keywords attribute
    FeedAttribute contextualKeywordsAttribute =
        FeedAttribute.newBuilder()
            .setType(FeedAttributeType.STRING_LIST)
            .setName("Contextual Keywords")
            .build();

    // Creates the feed.
    Feed feed =
        Feed.newBuilder()
            .setName("Real Estate Feed #" + getPrintableDateTime())
            .addAttributes(listingIdAttribute)
            .addAttributes(listingNameAttribute)
            .addAttributes(finalUrlsAttribute)
            .addAttributes(imageUrlAttribute)
            .addAttributes(contextualKeywordsAttribute)
            .build();

    // Creates the operation.
    FeedOperation operation = FeedOperation.newBuilder().setCreate(feed).build();

    // Creates the feed service client.
    try (FeedServiceClient feedServiceClient =
        googleAdsClient.getLatestVersion().createFeedServiceClient()) {
      // Adds the feed.
      MutateFeedsResponse response =
          feedServiceClient.mutateFeeds(String.valueOf(customerId), ImmutableList.of(operation));
      String feedResourceName = response.getResults(0).getResourceName();
      // Displays the result.
      System.out.printf("Feed with resource name '%s' was created.%n", feedResourceName);
      return feedResourceName;
    }
  }

  /**
   * Retrieves details about a feed. The initial query retrieves the FeedAttributes, or columns, of
   * the feed. Each FeedAttribute will also include the FeedAttributeId, which will be used in a
   * subsequent step. The example then inserts a new key, value pair into a map for each
   * FeedAttribute, which is the return value of the method. The keys are the placeholder types that
   * the columns will be. The values are the FeedAttributes.
   *
   * @param googleAdsClient the Google Ads API client.
   * @param customerId the client customer ID.
   * @param feedResourceName the resource name of the feed.
   * @return a Map containing the RealEstatePlaceholderField and FeedAttribute.
   */
  private Map<RealEstatePlaceholderField, FeedAttribute> getFeed(
      GoogleAdsClient googleAdsClient, long customerId, String feedResourceName) {
    // Constructs the query.
    String query =
        "SELECT feed.attributes FROM feed WHERE feed.resource_name = '" + feedResourceName + "'";

    // Constructs the request.
    SearchGoogleAdsRequest request =
        SearchGoogleAdsRequest.newBuilder()
            .setCustomerId(String.valueOf(customerId))
            .setPageSize(PAGE_SIZE)
            .setQuery(query)
            .build();

    // Issues the search request.
    try (GoogleAdsServiceClient googleAdsServiceClient =
        googleAdsClient.getLatestVersion().createGoogleAdsServiceClient()) {
      SearchPagedResponse searchPagedResponse = googleAdsServiceClient.search(request);
      // Gets the first result because we only need the single feed item we created previously.
      GoogleAdsRow googleAdsRow = searchPagedResponse.getPage().getResponse().getResults(0);
      // Gets the attributes list from the feed and creates a map with keys of each attribute and
      // values of each corresponding ID.
      List<FeedAttribute> feedAttributeList = googleAdsRow.getFeed().getAttributesList();
      // Creates a map to return.
      Map<RealEstatePlaceholderField, FeedAttribute> feedAttributes = new HashMap<>();
      // Loops through each of the feed attributes and populates the map.
      for (FeedAttribute feedAttribute : feedAttributeList) {
        switch (feedAttribute.getName()) {
          case "Listing ID":
            feedAttributes.put(RealEstatePlaceholderField.LISTING_ID, feedAttribute);
            break;
          case "Listing Name":
            feedAttributes.put(RealEstatePlaceholderField.LISTING_NAME, feedAttribute);
            break;
          case "Final URLs":
            feedAttributes.put(RealEstatePlaceholderField.FINAL_URLS, feedAttribute);
            break;
          case "Image URL":
            feedAttributes.put(RealEstatePlaceholderField.IMAGE_URL, feedAttribute);
            break;
          case "Contextual Keywords":
            feedAttributes.put(RealEstatePlaceholderField.CONTEXTUAL_KEYWORDS, feedAttribute);
            break;
            // Optionally add other RealEstatePlaceholderFields.
          default:
            throw new Error("Invalid attribute name.");
        }
      }
      return feedAttributes;
    }
  }

  /**
   * Creates a feed mapping for a given feed.
   *
   * @param googleAdsClient the Google Ads API client.
   * @param customerId the client customer ID.
   * @param feedAttributes the feed attributes.
   * @param feedResourceName the feed resource name.
   */
  private void createFeedMapping(
      GoogleAdsClient googleAdsClient,
      long customerId,
      Map<RealEstatePlaceholderField, FeedAttribute> feedAttributes,
      String feedResourceName) {
    // Maps the FeedAttributeIds to the placeholder values. The FeedAttributeId is the ID of the
    // FeedAttribute created in the createdFeed method. This can be thought of as the generic ID of
    // the column of the new feed. The placeholder value specifies the type of column this is in
    // the context of a real estate feed (e.g. a LISTING_ID or LISTING_NAME). The FeedMapping
    // associates the feed column by ID to this type and controls how the feed attributes are
    // presented in dynamic content.
    // See
    // https://developers.google.com/google-ads/api/reference/rpc/latest/RealEstatePlaceholderFieldEnum.RealEstatePlaceholderField
    // for the full list of placeholder values.
    AttributeFieldMapping listingIdMapping =
        AttributeFieldMapping.newBuilder()
            .setFeedAttributeId(feedAttributes.get(RealEstatePlaceholderField.LISTING_ID).getId())
            .setRealEstateField(RealEstatePlaceholderField.LISTING_ID)
            .build();
    AttributeFieldMapping listingNameMapping =
        AttributeFieldMapping.newBuilder()
            .setFeedAttributeId(feedAttributes.get(RealEstatePlaceholderField.LISTING_NAME).getId())
            .setRealEstateField(RealEstatePlaceholderField.LISTING_NAME)
            .build();
    AttributeFieldMapping finalUrlsMapping =
        AttributeFieldMapping.newBuilder()
            .setFeedAttributeId(feedAttributes.get(RealEstatePlaceholderField.FINAL_URLS).getId())
            .setRealEstateField(RealEstatePlaceholderField.FINAL_URLS)
            .build();
    AttributeFieldMapping imageUrlMapping =
        AttributeFieldMapping.newBuilder()
            .setFeedAttributeId(feedAttributes.get(RealEstatePlaceholderField.IMAGE_URL).getId())
            .setRealEstateField(RealEstatePlaceholderField.IMAGE_URL)
            .build();
    AttributeFieldMapping contextualKeywordsMapping =
        AttributeFieldMapping.newBuilder()
            .setFeedAttributeId(
                feedAttributes.get(RealEstatePlaceholderField.CONTEXTUAL_KEYWORDS).getId())
            .setRealEstateField(RealEstatePlaceholderField.CONTEXTUAL_KEYWORDS)
            .build();

    // Creates the feed mapping.
    FeedMapping feedMapping =
        FeedMapping.newBuilder()
            .setPlaceholderType(PlaceholderType.DYNAMIC_REAL_ESTATE)
            .setFeed(feedResourceName)
            .addAttributeFieldMappings(listingIdMapping)
            .addAttributeFieldMappings(listingNameMapping)
            .addAttributeFieldMappings(finalUrlsMapping)
            .addAttributeFieldMappings(imageUrlMapping)
            .addAttributeFieldMappings(contextualKeywordsMapping)
            .build();

    // Creates the operation.
    FeedMappingOperation operation =
        FeedMappingOperation.newBuilder().setCreate(feedMapping).build();

    // Adds the FeedMapping.
    try (FeedMappingServiceClient feedMappingServiceClient =
        googleAdsClient.getLatestVersion().createFeedMappingServiceClient()) {
      MutateFeedMappingsResponse response =
          feedMappingServiceClient.mutateFeedMappings(
              Long.toString(customerId), ImmutableList.of(operation));

      // Displays the results.
      for (MutateFeedMappingResult result : response.getResultsList()) {
        System.out.printf(
            "Created feed mapping with resource name '%s'.%n", result.getResourceName());
      }
    }
  }

  /**
   * Adds the new items to the feed.
   *
   * @param googleAdsClient the Google Ads API client.
   * @param customerId the client customer ID.
   * @param feedAttributes the feed attributes.
   * @param feedResourceName the feed resource name.
   */
  private void createFeedItems(
      GoogleAdsClient googleAdsClient,
      long customerId,
      Map<RealEstatePlaceholderField, FeedAttribute> feedAttributes,
      String feedResourceName) {

    // Creates the listing ID feed attribute value.
    FeedItemAttributeValue listingId =
        FeedItemAttributeValue.newBuilder()
            .setFeedAttributeId(feedAttributes.get(RealEstatePlaceholderField.LISTING_ID).getId())
            .setStringValue("ABC123DEF")
            .build();
    // Creates the listing name feed attribute value.
    FeedItemAttributeValue listingName =
        FeedItemAttributeValue.newBuilder()
            .setFeedAttributeId(feedAttributes.get(RealEstatePlaceholderField.LISTING_NAME).getId())
            .setStringValue("Two bedroom with magnificent views")
            .build();
    // Creates the final URLs feed attribute value.
    FeedItemAttributeValue finalUrls =
        FeedItemAttributeValue.newBuilder()
            .setFeedAttributeId(feedAttributes.get(RealEstatePlaceholderField.FINAL_URLS).getId())
            .addStringValues("http://www.example.com/listings/")
            .build();

    // Optionally insert additional attributes here, such as address, city, description, etc.

    // Creates the image URL feed attribute value.
    FeedItemAttributeValue imageUrl =
        FeedItemAttributeValue.newBuilder()
            .setFeedAttributeId(feedAttributes.get(RealEstatePlaceholderField.IMAGE_URL).getId())
            .setStringValue("http://www.example.com/listings/images?listing_id=ABC123DEF")
            .build();
    // Creates the contextual keywords feed attribute value.
    FeedItemAttributeValue contextualKeywords =
        FeedItemAttributeValue.newBuilder()
            .setFeedAttributeId(
                feedAttributes.get(RealEstatePlaceholderField.CONTEXTUAL_KEYWORDS).getId())
            .addStringValues("beach community")
            .addStringValues("ocean view")
            .addStringValues("two bedroom")
            .build();

    // Creates the FeedItem, specifying the Feed ID and the attributes created above.
    FeedItem feedItem =
        FeedItem.newBuilder()
            .setFeed(feedResourceName)
            .addAttributeValues(listingId)
            .addAttributeValues(listingName)
            .addAttributeValues(finalUrls)
            // Optionally include additional attributes.
            .addAttributeValues(imageUrl)
            .addAttributeValues(contextualKeywords)
            .build();

    // Creates an operation to add the FeedItem. You can include multiple feed items in a single
    // operation.
    FeedItemOperation operation = FeedItemOperation.newBuilder().setCreate(feedItem).build();
    // Creates the feed item service client.
    try (FeedItemServiceClient feedItemServiceClient =
        googleAdsClient.getLatestVersion().createFeedItemServiceClient()) {
      // Adds the feed items.
      MutateFeedItemsResponse response =
          feedItemServiceClient.mutateFeedItems(
              Long.toString(customerId), ImmutableList.of(operation));
      for (MutateFeedItemResult result : response.getResultsList()) {
        System.out.printf("Created feed item with resource name '%s'.%n", result.getResourceName());
      }
    }
  }
}

      

C#

// 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.V16.Errors;
using Google.Ads.GoogleAds.V16.Resources;
using Google.Ads.GoogleAds.V16.Services;
using System;
using System.Collections.Generic;
using System.Linq;
using static Google.Ads.GoogleAds.V16.Enums.FeedAttributeTypeEnum.Types;
using static Google.Ads.GoogleAds.V16.Enums.PlaceholderTypeEnum.Types;
using static Google.Ads.GoogleAds.V16.Enums.RealEstatePlaceholderFieldEnum.Types;

namespace Google.Ads.GoogleAds.Examples.V16
{
    /// <summary>
    /// This code example adds a real estate feed, creates the feed mapping, and adds items to
    /// the feed. To update feeds, see UpdateFeedItemAttributeValue.cs.
    /// </summary>
    public class AddRealEstateFeed : ExampleBase
    {
        /// <summary>
        /// Command line options for running the <see cref="AddRealEstateFeed"/> example.
        /// </summary>
        public class Options : OptionsBase
        {
            /// <summary>
            /// The Google Ads customer ID for which the real estate feed is added.
            /// </summary>
            [Option("customerId", Required = true, HelpText =
                "The Google Ads customer ID for which the real estate feed is added.")]
            public long CustomerId { 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);

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

        /// <summary>
        /// Returns a description about the code example.
        /// </summary>
        public override string Description =>
            "This code example adds a real estate feed, creates the feed mapping, and adds items " +
            "to the feed. To update feeds, see UpdateFeedItemAttributeValue.cs.";

        /// <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 real estate feed is
        /// added.</param>
        public void Run(GoogleAdsClient client, long customerId)
        {
            try
            {
                // Creates a new real estate feed.
                string feedResourceName = CreateFeed(client, customerId);

                // Get the newly creates feed's attributes and packages them into a map. This read
                // operation is required to retrieve the attribute IDs.
                Dictionary<RealEstatePlaceholderField, FeedAttribute> feedAttributes =
                    GetFeed(client, customerId, feedResourceName);

                // Creates the feed mapping.
                CreateFeedMapping(client, customerId, feedAttributes, feedResourceName);

                // Creates a feed item.
                CreateFeedItem(client, customerId, feedAttributes, feedResourceName);
            }
            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 feed.
        /// </summary>
        /// <param name="client">The Google Ads client.</param>
        /// <param name="customerId">The Google Ads customer ID for which the real estate feed is
        /// added.</param>
        /// <returns>Resource name of the newly created feed.</returns>
        private string CreateFeed(GoogleAdsClient client, long customerId)
        {
            // Get the FeedService.
            FeedServiceClient feedService = client.GetService(Services.V16.FeedService);

            // Creates a Listing ID attribute.
            FeedAttribute listingIdAttribute = new FeedAttribute()
            {
                Type = FeedAttributeType.String,
                Name = "Listing ID"
            };

            // Creates a Listing Name attribute.
            FeedAttribute listingNameAttribute = new FeedAttribute()
            {
                Type = FeedAttributeType.String,
                Name = "Listing Name"
            };

            // Creates a Final URLs attribute.
            FeedAttribute finalUrlsAttribute = new FeedAttribute()
            {
                Type = FeedAttributeType.UrlList,
                Name = "Final URLs"
            };

            // Creates an Image URL attribute
            FeedAttribute imageUrlAttribute = new FeedAttribute()
            {
                Type = FeedAttributeType.Url,
                Name = "Image URL"
            };

            // Creates a Contextual Keywords attribute
            FeedAttribute contextualKeywordsAttribute = new FeedAttribute()
            {
                Type = FeedAttributeType.StringList,
                Name = "Contextual Keywords"
            };

            // Creates the feed.
            Feed feed = new Feed()
            {
                Name = "Real Estate Feed #" + ExampleUtilities.GetRandomString(),
                Attributes =
                {
                    listingIdAttribute,
                    listingNameAttribute,
                    finalUrlsAttribute,
                    imageUrlAttribute,
                    contextualKeywordsAttribute
                }
            };

            // Creates the operation.
            FeedOperation operation = new FeedOperation()
            {
                Create = feed
            };

            // Adds the feed.
            MutateFeedsResponse response =
                feedService.MutateFeeds(customerId.ToString(), new[] { operation });

            string feedResourceName = response.Results[0].ResourceName;

            // Displays the result.
            Console.WriteLine($"Feed with resource name '{feedResourceName}' was created.");
            return feedResourceName;
        }

        /// <summary>
        /// Retrieves details about a feed. The initial query retrieves the FeedAttributes,
        /// or columns, of the feed. Each FeedAttribute will also include the FeedAttributeId,
        /// which will be used in a subsequent step. The example then inserts a new key, value
        /// pair into a map for each FeedAttribute, which is the return value of the method.
        /// The keys are the placeholder types that the columns will be. The values are the
        /// FeedAttributes.
        /// </summary>
        /// <param name="client">The Google Ads client.</param>
        /// <param name="customerId">The Google Ads customer ID for which the real estate feed is
        /// added.</param>
        /// <param name="feedResourceName">The resource name of the feed.</param>
        /// <returns>
        /// A Map containing the RealEstatePlaceholderField and FeedAttribute.
        /// </returns>
        public Dictionary<RealEstatePlaceholderField, FeedAttribute> GetFeed(
            GoogleAdsClient client, long customerId, string feedResourceName)
        {
            // Get the GoogleAdsService.
            GoogleAdsServiceClient googleAdsService = client.GetService(
                Services.V16.GoogleAdsService);

            // Constructs the query.
            string query = $"SELECT feed.attributes FROM feed WHERE feed.resource_name = " +
                $"'{feedResourceName}'";

            // Constructs the request.
            SearchGoogleAdsRequest request = new SearchGoogleAdsRequest()
            {
                CustomerId = customerId.ToString(),
                Query = query
            };

            // Issues the search request and get the first result, since we only need the
            // single feed item we created previously.
            GoogleAdsRow googleAdsRow = googleAdsService.Search(request).First();

            // Gets the attributes list from the feed and creates a map with keys of each
            // attribute and values of each corresponding ID.

            Dictionary<RealEstatePlaceholderField, FeedAttribute> feedAttributes =
                new Dictionary<RealEstatePlaceholderField, FeedAttribute>();

            // Loops through the feed attributes to populate the map.
            foreach (FeedAttribute feedAttribute in googleAdsRow.Feed.Attributes)
            {
                switch (feedAttribute.Name)
                {
                    case "Listing ID":
                        feedAttributes[RealEstatePlaceholderField.ListingId] = feedAttribute;
                        break;

                    case "Listing Name":
                        feedAttributes[RealEstatePlaceholderField.ListingName] = feedAttribute;
                        break;

                    case "Final URLs":
                        feedAttributes[RealEstatePlaceholderField.FinalUrls] = feedAttribute;
                        break;

                    case "Image URL":
                        feedAttributes[RealEstatePlaceholderField.ImageUrl] = feedAttribute;
                        break;

                    case "Contextual Keywords":
                        feedAttributes[RealEstatePlaceholderField.ContextualKeywords] = feedAttribute;
                        break;
                    // The full list of RealEstatePlaceholderField can be found here
                    // https://developers.google.com/google-ads/api/reference/rpc/latest/RealEstatePlaceholderFieldEnum.RealEstatePlaceholderField
                    default:
                        throw new Exception("Invalid attribute name.");
                }
            }
            return feedAttributes;
        }

        /// <summary>
        /// Creates a feed mapping for a given feed.
        /// </summary>
        /// <param name="client">The Google Ads client.</param>
        /// <param name="customerId">The Google Ads customer ID for which the real estate feed is
        /// added.</param>
        /// <param name="feedAttributes">The feed attributes.</param>
        /// <param name="feedResourceName">The resource name of the feed.</param>
        private void CreateFeedMapping(GoogleAdsClient client, long customerId,
            Dictionary<RealEstatePlaceholderField, FeedAttribute> feedAttributes,
            string feedResourceName)
        {
            // Get the FeedMappingServiceClient.
            FeedMappingServiceClient feedMappingService = client.GetService(
                Services.V16.FeedMappingService);

            // Maps the FeedAttributeIds to the placeholder values. The FeedAttributeId is the
            // ID of the FeedAttribute created in the CreatedFeed method. This can be thought of
            // as the generic ID of the column of the new feed. The placeholder value specifies
            // the type of column this is in the context of a real estate feed (e.g.
            // a LISTING_ID or LISTING_NAME). The FeedMapping associates the feed column by ID to
            // this type and controls how the feed attributes are presented in dynamic content.
            // See https://developers.google.com/google-ads/api/reference/rpc/latest/RealEstatePlaceholderFieldEnum.RealEstatePlaceholderField
            // for the full list of placeholder values.

            AttributeFieldMapping listingIdMapping = new AttributeFieldMapping()
            {
                FeedAttributeId = feedAttributes[RealEstatePlaceholderField.ListingId].Id,
                RealEstateField = RealEstatePlaceholderField.ListingId
            };

            AttributeFieldMapping listingNameMapping = new AttributeFieldMapping()
            {
                FeedAttributeId = feedAttributes[RealEstatePlaceholderField.ListingName].Id,
                RealEstateField = RealEstatePlaceholderField.ListingName
            };

            AttributeFieldMapping finalUrlsMapping = new AttributeFieldMapping()
            {
                FeedAttributeId = feedAttributes[RealEstatePlaceholderField.FinalUrls].Id,
                RealEstateField = RealEstatePlaceholderField.FinalUrls
            };

            AttributeFieldMapping imageUrlMapping = new AttributeFieldMapping()
            {
                FeedAttributeId = feedAttributes[RealEstatePlaceholderField.ImageUrl].Id,
                RealEstateField = RealEstatePlaceholderField.ImageUrl
            };

            AttributeFieldMapping contextualKeywordsMapping = new AttributeFieldMapping()
            {
                FeedAttributeId = feedAttributes[RealEstatePlaceholderField.ContextualKeywords].Id,
                RealEstateField = RealEstatePlaceholderField.ContextualKeywords
            };

            // Creates the feed mapping.
            FeedMapping feedMapping = new FeedMapping()
            {
                PlaceholderType = PlaceholderType.DynamicRealEstate,
                Feed = feedResourceName,
                AttributeFieldMappings =
                {
                    listingIdMapping,
                    listingNameMapping,
                    finalUrlsMapping,
                    imageUrlMapping,
                    contextualKeywordsMapping
                }
            };

            // Creates the operation.
            FeedMappingOperation operation = new FeedMappingOperation()
            {
                Create = feedMapping
            };

            // Adds the FeedMapping.
            MutateFeedMappingsResponse response = feedMappingService.MutateFeedMappings(
                customerId.ToString(), new[] { operation });

            // Displays the results.
            foreach (MutateFeedMappingResult result in response.Results)
            {
                Console.WriteLine($"Created feed mapping with resource name" +
                    $" '{result.ResourceName}'.");
            }
        }

        /// <summary>
        /// Adds a new item to the feed.
        /// </summary>
        /// <param name="client">The Google Ads client.</param>
        /// <param name="customerId">The Google Ads customer ID for which the real estate feed is
        /// added.</param>
        /// <param name="feedAttributes">The feed attributes.</param>
        /// <param name="feedResourceName">The resource name of the feed.</param>
        private void CreateFeedItem(GoogleAdsClient client, long customerId,
            Dictionary<RealEstatePlaceholderField, FeedAttribute> feedAttributes,
            string feedResourceName)
        {
            // Get the FeedItemServiceClient.
            FeedItemServiceClient feedItemService = client.GetService(
                Services.V16.FeedItemService);

            // Creates the listing ID feed attribute value.
            FeedItemAttributeValue listingId = new FeedItemAttributeValue()
            {
                FeedAttributeId = feedAttributes[RealEstatePlaceholderField.ListingId].Id,
                StringValue = "ABC123DEF"
            };

            // Creates the listing name feed attribute value.
            FeedItemAttributeValue listingName = new FeedItemAttributeValue()
            {
                FeedAttributeId = feedAttributes[RealEstatePlaceholderField.ListingName].Id,
                StringValue = "Two bedroom with magnificent views"
            };

            // Creates the final URLs feed attribute value.
            FeedItemAttributeValue finalUrls = new FeedItemAttributeValue()
            {
                FeedAttributeId = feedAttributes[RealEstatePlaceholderField.FinalUrls].Id,
                StringValue = "http://www.example.com/listings/"
            };

            // Creates the image URL feed attribute value.
            FeedItemAttributeValue imageUrl = new FeedItemAttributeValue()
            {
                FeedAttributeId = feedAttributes[RealEstatePlaceholderField.ImageUrl].Id,
                StringValue = "http://www.example.com/listings/images?listing_id=ABC123DEF"
            };

            // Creates the contextual keywords feed attribute value.
            FeedItemAttributeValue contextualKeywords = new FeedItemAttributeValue()
            {
                FeedAttributeId = feedAttributes[RealEstatePlaceholderField.ContextualKeywords].Id,
                StringValues =
                {
                    "beach community",
                    "ocean view",
                    "two bedroom",
                }
            };

            // Creates the FeedItem, specifying the Feed ID and the attributes created above.
            FeedItem feedItem = new FeedItem()
            {
                Feed = feedResourceName,
                AttributeValues =
                {
                    listingId,
                    listingName,
                    finalUrls,
                    imageUrl,
                    contextualKeywords
                }
            };

            // Creates an operation to add the FeedItem.
            FeedItemOperation operation = new FeedItemOperation()
            {
                Create = feedItem
            };

            // Adds the feed item.
            MutateFeedItemsResponse response =
                feedItemService.MutateFeedItems(customerId.ToString(),
                    new FeedItemOperation[] { operation });

            foreach (MutateFeedItemResult result in response.Results)
            {
                Console.WriteLine($"Created feed item with resource name " +
                    $"'{result.ResourceName}'.");
            }
        }
    }
}

      

PHP

<?php

/**
 * 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.
 */

namespace Google\Ads\GoogleAds\Examples\Remarketing;

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\Feeds;
use Google\Ads\GoogleAds\Examples\Utils\Helper;
use Google\Ads\GoogleAds\Lib\OAuth2TokenBuilder;
use Google\Ads\GoogleAds\Lib\V16\GoogleAdsClient;
use Google\Ads\GoogleAds\Lib\V16\GoogleAdsClientBuilder;
use Google\Ads\GoogleAds\Lib\V16\GoogleAdsException;
use Google\Ads\GoogleAds\V16\Enums\FeedAttributeTypeEnum\FeedAttributeType;
use Google\Ads\GoogleAds\V16\Enums\PlaceholderTypeEnum\PlaceholderType;
use Google\Ads\GoogleAds\V16\Enums\RealEstatePlaceholderFieldEnum\RealEstatePlaceholderField;
use Google\Ads\GoogleAds\V16\Errors\GoogleAdsError;
use Google\Ads\GoogleAds\V16\Resources\AttributeFieldMapping;
use Google\Ads\GoogleAds\V16\Resources\Feed;
use Google\Ads\GoogleAds\V16\Resources\FeedAttribute;
use Google\Ads\GoogleAds\V16\Resources\FeedItem;
use Google\Ads\GoogleAds\V16\Resources\FeedItemAttributeValue;
use Google\Ads\GoogleAds\V16\Resources\FeedMapping;
use Google\Ads\GoogleAds\V16\Services\FeedItemOperation;
use Google\Ads\GoogleAds\V16\Services\FeedMappingOperation;
use Google\Ads\GoogleAds\V16\Services\FeedOperation;
use Google\Ads\GoogleAds\V16\Services\MutateFeedItemsRequest;
use Google\Ads\GoogleAds\V16\Services\MutateFeedMappingsRequest;
use Google\Ads\GoogleAds\V16\Services\MutateFeedsRequest;
use Google\ApiCore\ApiException;

/** Adds a real estate feed, creates the feed mapping, and adds items to the feed. */
class AddRealEstateFeed
{
    private const CUSTOMER_ID = 'INSERT_CUSTOMER_ID_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
        ]);

        // 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
            );
        } 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
     */
    public static function runExample(GoogleAdsClient $googleAdsClient, int $customerId)
    {
        // Creates a new feed, but you can fetch and re-use an existing feed by skipping the
        // createFeed method and inserting the feed resource name of the existing feed into the
        // getFeed method.
        $feedResourceName = self::createFeed($googleAdsClient, $customerId);
        // Gets the page feed details.
        $placeHoldersToFeedAttributesMap = Feeds::realEstatePlaceholderFieldsMapFor(
            $feedResourceName,
            $customerId,
            $googleAdsClient
        );
        // Creates the feed mapping.
        self::createFeedMapping(
            $googleAdsClient,
            $customerId,
            $feedResourceName,
            $placeHoldersToFeedAttributesMap
        );
        // Creates the feed item and adds it to the feed.
        self::createFeedItem(
            $googleAdsClient,
            $customerId,
            $feedResourceName,
            $placeHoldersToFeedAttributesMap
        );
    }

    /**
     * Creates a feed.
     *
     * @param GoogleAdsClient $googleAdsClient the Google Ads API client
     * @param int $customerId the customer ID
     * @return string the feed resource name
     */
    private static function createFeed(GoogleAdsClient $googleAdsClient, int $customerId)
    {
        // Creates a listing ID attribute.
        $listingIdAttribute = new FeedAttribute([
            'type' =>  FeedAttributeType::STRING,
            'name' => 'Listing ID'
        ]);
        // Creates a listing name attribute.
        $listingNameAttribute = new FeedAttribute([
            'type' =>  FeedAttributeType::STRING,
            'name' => 'Listing Name'
        ]);
        // Creates a final URLs attribute.
        $finalUrlsAttribute = new FeedAttribute([
            'type' =>  FeedAttributeType::URL_LIST,
            'name' => 'Final URLs'
        ]);
        // Creates an image URL attribute.
        $imageUrlAttribute = new FeedAttribute([
            'type' =>  FeedAttributeType::URL,
            'name' => 'Image URL'
        ]);
        // Creates a contextual keywords attribute.
        $contextualKeywordsAttribute = new FeedAttribute([
            'type' =>  FeedAttributeType::STRING_LIST,
            'name' => 'Contextual Keywords'
        ]);

        // Creates the feed with the newly created feed attributes.
        $feed = new Feed([
            'name' => 'Real Estate Feed #' . Helper::getPrintableDatetime(),
            'attributes' => [
                $listingIdAttribute,
                $listingNameAttribute,
                $finalUrlsAttribute,
                $imageUrlAttribute,
                $contextualKeywordsAttribute
            ]
        ]);

        // Creates the feed operation.
        $operation = new FeedOperation();
        $operation->setCreate($feed);

        // Issues a mutate request to add the feed and print some information.
        $feedServiceClient = $googleAdsClient->getFeedServiceClient();
        $response =
            $feedServiceClient->mutateFeeds(MutateFeedsRequest::build($customerId, [$operation]));
        $feedResourceName = $response->getResults()[0]->getResourceName();
        printf("Feed with resource name '%s' was created.%s", $feedResourceName, PHP_EOL);

        return $feedResourceName;
    }

    /**
     * Creates a feed mapping for a given feed.
     *
     * @param GoogleAdsClient $googleAdsClient the Google Ads API client
     * @param int $customerId the customer ID
     * @param string $feedResourceName the feed resource name for creating a feed mapping
     * @param array $placeHoldersToFeedAttributesMap the map from placeholder fields to feed
     *      attributes
     */
    private static function createFeedMapping(
        GoogleAdsClient $googleAdsClient,
        int $customerId,
        string $feedResourceName,
        array $placeHoldersToFeedAttributesMap
    ) {
        // Maps the feed attribute IDs to the placeholder values. The feed attribute ID is the ID
        // of the feed attribute created in the createdFeed method. This can be thought of as the
        // generic ID of the column of the new feed. The placeholder value specifies the type of
        // column this is in the context of a real estate feed (e.g. a LISTING_ID or
        // LISTING_NAME). The feed mapping associates the feed column by ID to this type and
        // controls how the feed attributes are presented in dynamic content.
        // See RealEstatePlaceholderField.php for the full list of placeholder values.
        $listingIdMapping = new AttributeFieldMapping([
            'feed_attribute_id' => $placeHoldersToFeedAttributesMap[
                RealEstatePlaceholderField::LISTING_ID]->getId(),
            'real_estate_field' => RealEstatePlaceholderField::LISTING_ID
        ]);
        $listingNameMapping = new AttributeFieldMapping([
            'feed_attribute_id' => $placeHoldersToFeedAttributesMap[
                RealEstatePlaceholderField::LISTING_NAME]->getId(),
            'real_estate_field' => RealEstatePlaceholderField::LISTING_NAME
        ]);
        $finalUrlsMapping = new AttributeFieldMapping([
            'feed_attribute_id' => $placeHoldersToFeedAttributesMap[
                RealEstatePlaceholderField::FINAL_URLS]->getId(),
            'real_estate_field' => RealEstatePlaceholderField::FINAL_URLS
        ]);
        $imageUrlMapping = new AttributeFieldMapping([
            'feed_attribute_id' => $placeHoldersToFeedAttributesMap[
                RealEstatePlaceholderField::IMAGE_URL]->getId(),
            'real_estate_field' => RealEstatePlaceholderField::IMAGE_URL
        ]);
        $contextualKeywordsMapping = new AttributeFieldMapping([
            'feed_attribute_id' => $placeHoldersToFeedAttributesMap[
                RealEstatePlaceholderField::CONTEXTUAL_KEYWORDS]->getId(),
            'real_estate_field' => RealEstatePlaceholderField::CONTEXTUAL_KEYWORDS
        ]);

        // Creates the feed mapping.
        $feedMapping = new FeedMapping([
            'placeholder_type' => PlaceholderType::DYNAMIC_REAL_ESTATE,
            'feed' => $feedResourceName,
            'attribute_field_mappings' => [
                $listingIdMapping,
                $listingNameMapping,
                $finalUrlsMapping,
                $imageUrlMapping,
                $contextualKeywordsMapping
            ]
        ]);

        // Creates the feed mapping operation.
        $operation = new FeedMappingOperation();
        $operation->setCreate($feedMapping);

        // Issues a mutate request to add the feed mapping and print some information.
        $feedMappingServiceClient = $googleAdsClient->getFeedMappingServiceClient();
        $response = $feedMappingServiceClient->mutateFeedMappings(
            MutateFeedMappingsRequest::build($customerId, [$operation])
        );
        printf(
            "Feed mapping with resource name '%s' was created.%s",
            $response->getResults()[0]->getResourceName(),
            PHP_EOL
        );
    }

    /**
     * Adds a new item to the feed.
     *
     * @param GoogleAdsClient $googleAdsClient the Google Ads API client
     * @param int $customerId the customer ID
     * @param string $feedResourceName the feed resource name for creating a feed item
     * @param array $placeHoldersToFeedAttributesMap the map from placeholder fields to feed
     *      attributes
     */
    private static function createFeedItem(
        GoogleAdsClient $googleAdsClient,
        int $customerId,
        string $feedResourceName,
        array $placeHoldersToFeedAttributesMap
    ) {
        // Creates the listing ID feed attribute value.
        $listingIdAttributeValue = new FeedItemAttributeValue([
            'feed_attribute_id' => $placeHoldersToFeedAttributesMap[
                RealEstatePlaceholderField::LISTING_ID]->getId(),
            'string_value' => 'ABC123DEF'
        ]);
        // Creates the listing name feed attribute value.
        $listingNameAttributeValue = new FeedItemAttributeValue([
            'feed_attribute_id' => $placeHoldersToFeedAttributesMap[
                RealEstatePlaceholderField::LISTING_NAME]->getId(),
            'string_value' => 'Two bedroom with magnificent views'
        ]);
        // Creates the final URLs feed attribute value.
        $finalUrlsAttributeValue = new FeedItemAttributeValue([
            'feed_attribute_id' => $placeHoldersToFeedAttributesMap[
                RealEstatePlaceholderField::FINAL_URLS]->getId(),
            'string_values' => ['http://www.example.com/listings/']
        ]);
        // Creates the image URL feed attribute value.
        $imageUrlAttributeValue = new FeedItemAttributeValue([
            'feed_attribute_id'
                => $placeHoldersToFeedAttributesMap[RealEstatePlaceholderField::IMAGE_URL]->getId(),
            'string_value' => 'http://www.example.com/listings/images?listing_id=ABC123DEF'
        ]);
        // Creates the contextual keywords feed attribute value.
        $contextualKeywordsAttributeValue = new FeedItemAttributeValue([
            'feed_attribute_id' => $placeHoldersToFeedAttributesMap[
                RealEstatePlaceholderField::CONTEXTUAL_KEYWORDS]->getId(),
            'string_values' => ['beach community', 'ocean view', 'two bedroom']
        ]);

        // Creates the feed item, specifying the feed ID and the attributes created above.
        $feedItem = new FeedItem([
            'feed' => $feedResourceName,
            'attribute_values' => [
                $listingIdAttributeValue,
                $listingNameAttributeValue,
                $finalUrlsAttributeValue,
                $imageUrlAttributeValue,
                $contextualKeywordsAttributeValue
            ]
        ]);

        // Creates the feed item operation.
        $operation = new FeedItemOperation();
        $operation->setCreate($feedItem);

        // Issues a mutate request to add the feed item and print some information.
        $feedItemServiceClient = $googleAdsClient->getFeedItemServiceClient();
        $response = $feedItemServiceClient->mutateFeedItems(
            MutateFeedItemsRequest::build($customerId, [$operation])
        );
        printf(
            "Feed item with resource name '%s' was created.%s",
            $response->getResults()[0]->getResourceName(),
            PHP_EOL
        );
    }
}

AddRealEstateFeed::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 real estate feed, creates the field mapping, and adds items to feed.
"""


import argparse
import sys
from uuid import uuid4

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

_DEFAULT_PAGE_SIZE = 10000


def main(client, customer_id):
    """The main method that creates all necessary entities for the example.

    Args:
        client: an initialized GoogleAdsClient instance.
        customer_id: a client customer ID.
    """
    # Creates a new feed, but you can fetch and re-use an existing feed by
    # skipping the _create_feed method and inserting the feed resource name of
    # the existing feed.
    feed_resource_name = create_feed(client, customer_id)

    print(f"Feed with resource name '{feed_resource_name}' was created.")

    # Gets the newly created feed's attributes and packages them into a map.
    # This read operation is required to retrieve the attribute IDs.
    placeholders_to_feed_attributes_map = get_placeholder_fields_map(
        client, customer_id, feed_resource_name
    )

    # Creates the feed mapping.
    feed_mapping_resource_name = create_feed_mapping(
        client,
        customer_id,
        feed_resource_name,
        placeholders_to_feed_attributes_map,
    )

    print(
        f"Feed mapping with resource name '{feed_mapping_resource_name}' "
        "was created."
    )

    # Creates the feed item and adds it to the feed.
    feed_item_resource_name = create_feed_item(
        client,
        customer_id,
        feed_resource_name,
        placeholders_to_feed_attributes_map,
    )

    print(
        f"Feed item with resource name '{feed_item_resource_name}' was "
        "created."
    )


def create_feed(client, customer_id):
    """Creates a feed that will be used as a real estate feed.

    Args:
        client: An initialized GoogleAds client.
        customer_id: The Google Ads customer ID.

    Returns:
        A str resource name of the newly created feed.
    """
    feed_service = client.get_service("FeedService")

    # Creates the feed operation.
    feed_operation = client.get_type("FeedOperation")

    # Create the feed with feed attributes defined below.
    feed = feed_operation.create
    feed.name = f"Real Estate Feed #{uuid4()}"

    feed_attribute_type_enum = client.enums.FeedAttributeTypeEnum

    # Creates a listing ID attribute.
    listing_id_attribute = client.get_type("FeedAttribute")
    listing_id_attribute.name = "Listing ID"
    listing_id_attribute.type_ = feed_attribute_type_enum.STRING

    # Creates a listing name attribute.
    listing_name_attribute = client.get_type("FeedAttribute")
    listing_name_attribute.name = "Listing Name"
    listing_name_attribute.type_ = feed_attribute_type_enum.STRING

    # Creates a final URLs attribute.
    final_urls_attribute = client.get_type("FeedAttribute")
    final_urls_attribute.name = "Final URLs"
    final_urls_attribute.type_ = feed_attribute_type_enum.URL_LIST

    # Creates an image URL attribute.
    image_url_attribute = client.get_type("FeedAttribute")
    image_url_attribute.name = "Image URL"
    image_url_attribute.type_ = feed_attribute_type_enum.URL

    # Creates a contextual keywords attribute.
    contextual_keywords_attribute = client.get_type("FeedAttribute")
    contextual_keywords_attribute.name = "Contextual Keywords"
    contextual_keywords_attribute.type_ = feed_attribute_type_enum.STRING_LIST

    feed.attributes.extend(
        [
            listing_id_attribute,
            listing_name_attribute,
            final_urls_attribute,
            image_url_attribute,
            contextual_keywords_attribute,
        ]
    )

    try:
        # Issues a mutate request to add the feed.
        feed_response = feed_service.mutate_feeds(
            customer_id=customer_id, operations=[feed_operation]
        )
    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)

    return feed_response.results[0].resource_name


def create_feed_mapping(
    client, customer_id, feed_resource_name, placeholders_to_feed_attribute_map
):
    """Creates a feed mapping for a given real estate feed.

    Args:
        client: An initialized GoogleAds client.
        customer_id: The Google Ads customer ID.
        feed_resource_name: A str feed resource name for creating a feed
            mapping.
        placeholders_to_feed_attribute_map: A dict mapping placeholder feeds to
            feed attributes.

    Returns:
        A str resource name of the newly created feed mapping.
    """
    feed_mapping_service = client.get_service("FeedMappingService")

    # Creates the feed mapping operation.
    feed_mapping_operation = client.get_type("FeedMappingOperation")

    # Creates the feed mapping.
    feed_mapping = feed_mapping_operation.create
    feed_mapping.feed = feed_resource_name
    feed_mapping.placeholder_type = (
        client.enums.PlaceholderTypeEnum.DYNAMIC_REAL_ESTATE
    )

    # Returns a new instance of AttributeFieldMapping when called.
    # This prevents the need to repeat these lines every time we need a new
    # AttributeFieldMapping. Instead, we call attribute_field_mapping()
    attribute_field_mapping = lambda: client.get_type("AttributeFieldMapping")

    # Maps the feed attribute IDs to the placeholder values. The feed attribute
    # ID is the ID of the feed attribute created in the created_feed method.
    # This can be thought of as the generic ID of the column of the new feed.
    # The placeholder value specifies the type of column this is in the context
    # of a real estate feed (e.g. a LISTING_ID or LISTING_NAME). The feed
    # mapping associates the feed column by ID to this type and controls how
    # the feed attributes are presented in dynamic content.
    placeholder_field_enum = client.enums.RealEstatePlaceholderFieldEnum
    listing_id_enum_value = placeholder_field_enum.LISTING_ID
    listing_id_mapping = attribute_field_mapping()
    listing_id_mapping.feed_attribute_id = placeholders_to_feed_attribute_map[
        listing_id_enum_value
    ].id
    listing_id_mapping.real_estate_field = listing_id_enum_value

    listing_name_enum_value = placeholder_field_enum.LISTING_NAME
    listing_name_mapping = attribute_field_mapping()
    listing_name_mapping.feed_attribute_id = placeholders_to_feed_attribute_map[
        listing_name_enum_value
    ].id
    listing_name_mapping.real_estate_field = listing_name_enum_value

    final_urls_enum_value = placeholder_field_enum.FINAL_URLS
    final_urls_mapping = attribute_field_mapping()
    final_urls_mapping.feed_attribute_id = placeholders_to_feed_attribute_map[
        final_urls_enum_value
    ].id
    final_urls_mapping.real_estate_field = final_urls_enum_value

    image_url_enum_value = placeholder_field_enum.IMAGE_URL
    image_url_mapping = attribute_field_mapping()
    image_url_mapping.feed_attribute_id = placeholders_to_feed_attribute_map[
        image_url_enum_value
    ].id
    image_url_mapping.real_estate_field = image_url_enum_value

    contextual_keywords_enum_value = placeholder_field_enum.CONTEXTUAL_KEYWORDS
    contextual_keywords_mapping = attribute_field_mapping()
    contextual_keywords_mapping.feed_attribute_id = (
        placeholders_to_feed_attribute_map[contextual_keywords_enum_value].id
    )
    contextual_keywords_mapping.real_estate_field = (
        contextual_keywords_enum_value
    )

    feed_mapping.attribute_field_mappings.extend(
        [
            listing_id_mapping,
            listing_name_mapping,
            final_urls_mapping,
            image_url_mapping,
            contextual_keywords_mapping,
        ]
    )

    try:
        # Issues a mutate request to add the feed mapping.
        feed_mapping_response = feed_mapping_service.mutate_feed_mappings(
            customer_id=customer_id, operations=[feed_mapping_operation]
        )
    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)

    return feed_mapping_response.results[0].resource_name


def create_feed_item(
    client, customer_id, feed_resource_name, placeholders_to_feed_attribute_map
):
    """Adds a new item to the feed.

    Args:
        client: An initialized GoogleAds client.
        customer_id: The Google Ads customer ID.
        feed_resource_name: A str feed resource name for creating a feed item.
        placeholders_to_feed_attribute_map: A dict mapping placeholder feeds to
            feed attributes.

    Returns:
        A str resource name of the newly created feed item.
    """
    feed_item_service = client.get_service("FeedItemService")

    # Creates the feed mapping operation.
    feed_item_operation = client.get_type("FeedItemOperation")

    # Create the feed item, with feed attributes created below.
    feed_item = feed_item_operation.create
    feed_item.feed = feed_resource_name

    placeholder_field_enum = client.enums.RealEstatePlaceholderFieldEnum

    # Creates the listing ID feed attribute value.
    listing_id_enum_value = placeholder_field_enum.LISTING_ID
    listing_id_mapping = client.get_type("FeedItemAttributeValue")
    listing_id_mapping.feed_attribute_id = placeholders_to_feed_attribute_map[
        listing_id_enum_value
    ].id
    listing_id_mapping.string_value = "ABC123DEF"

    # Creates the listing name feed attribute value.
    listing_name_enum_value = placeholder_field_enum.LISTING_NAME
    listing_name_mapping = client.get_type("FeedItemAttributeValue")
    listing_name_mapping.feed_attribute_id = placeholders_to_feed_attribute_map[
        listing_name_enum_value
    ].id
    listing_name_mapping.string_value = "Two bedroom with magnificent views"

    # Creates the final URLs feed attribute value.
    final_urls_enum_value = placeholder_field_enum.FINAL_URLS
    final_urls_mapping = client.get_type("FeedItemAttributeValue")
    final_urls_mapping.feed_attribute_id = placeholders_to_feed_attribute_map[
        final_urls_enum_value
    ].id
    final_urls_mapping.string_values.append("http://www.example.com/listings/")

    # Creates the image URL feed attribute value.
    image_url_enum_value = placeholder_field_enum.IMAGE_URL
    image_url_mapping = client.get_type("FeedItemAttributeValue")
    image_url_mapping.feed_attribute_id = placeholders_to_feed_attribute_map[
        image_url_enum_value
    ].id
    image_url_mapping.string_value = (
        "http://www.example.com/listings/images?listing_id=ABC123DEF"
    )

    # Creates the contextual keywords feed attribute value.
    contextual_keywords_enum_value = placeholder_field_enum.CONTEXTUAL_KEYWORDS
    contextual_keywords_mapping = client.get_type("FeedItemAttributeValue")
    contextual_keywords_mapping.feed_attribute_id = (
        placeholders_to_feed_attribute_map[contextual_keywords_enum_value].id
    )
    contextual_keywords_mapping.string_values.extend(
        ["beach community", "ocean view", "two bedroom"]
    )

    feed_item.attribute_values.extend(
        [
            listing_id_mapping,
            listing_name_mapping,
            final_urls_mapping,
            image_url_mapping,
            contextual_keywords_mapping,
        ]
    )

    try:
        # Issues a mutate request to add the feed item.
        feed_item_response = feed_item_service.mutate_feed_items(
            customer_id=customer_id, operations=[feed_item_operation]
        )
    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)

    return feed_item_response.results[0].resource_name


def get_placeholder_fields_map(client, customer_id, feed_resource_name):
    """Get mapping of placeholder fields to feed attributes.

    Note that this is only intended to produce a mapping for real estate feeds.

    Args:
        client: An initialized GoogleAds client.
        customer_id: The Google Ads customer ID.
        feed_resource_name: A str feed resource name to get attributes from.

    Returns:
        A dict mapping placeholder fields to feed attributes.
    """
    googleads_service = client.get_service("GoogleAdsService")

    # Constructs the query to get the feed attributes for the specified
    # resource name.
    query = f"""
        SELECT
          feed.attributes
        FROM
          feed
        WHERE
          feed.resource_name = '{feed_resource_name}'"""

    # Issues a search request by specifying a page size.
    search_request = client.get_type("SearchGoogleAdsRequest")
    search_request.customer_id = customer_id
    search_request.query = query
    search_request.page_size = _DEFAULT_PAGE_SIZE
    response = googleads_service.search(request=search_request)

    try:
        # Gets the first result because we only need the single feed we created
        # previously.
        row = list(response)[0]
        feed_attributes = row.feed.attributes

        real_estate_placeholder_field_enum = (
            client.enums.RealEstatePlaceholderFieldEnum
        )
        feed_attribute_names_map = {
            "Listing ID": real_estate_placeholder_field_enum.LISTING_ID,
            "Listing Name": real_estate_placeholder_field_enum.LISTING_NAME,
            "Final URLs": real_estate_placeholder_field_enum.FINAL_URLS,
            "Image URL": real_estate_placeholder_field_enum.IMAGE_URL,
            "Contextual Keywords": real_estate_placeholder_field_enum.CONTEXTUAL_KEYWORDS,
        }

        # Creates map with keys of placeholder fields and values of feed
        # attributes.
        placeholder_fields_map = {
            feed_attribute_names_map[feed_attribute.name]: feed_attribute
            for feed_attribute in feed_attributes
        }
    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)

    return placeholder_fields_map


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

    parser = argparse.ArgumentParser(
        description="Adds a real estate feed for specified customer."
    )
    # 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.",
    )
    args = parser.parse_args()

    main(googleads_client, args.customer_id)

      

Ruby

#!/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 real estate feed, creates the feed mapping,
# and adds items to the feed.

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

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

  # Creates a new real estate feed.
  feed_resource_name = create_feed(client, customer_id)

  # Gets the newly created feed's attributes and packages them into a map.
  # This read operation is required to retrieve the attribute IDs.
  placeholders_to_feed_attribute_map = real_estate_placeholder_fields_map_for(
    client, customer_id, feed_resource_name)

  # Creates the feed mapping.
  create_feed_mapping(
    client,
    customer_id,
    feed_resource_name,
    placeholders_to_feed_attribute_map,
  )

  # Creates a feed item.
  create_feed_item(
    client,
    customer_id,
    feed_resource_name,
    placeholders_to_feed_attribute_map,
  )
end

# Creates a feed that will be used as a real estate feed.
def create_feed(client, customer_id)
  # Creates the feed operation.
  operation = client.operation.create_resource.feed do |feed|
    feed.name = "Real Estate Feed ##{(Time.new.to_f * 1000).to_i}"
    feed.attributes << client.resource.feed_attribute do |fa|
      fa.type = :STRING
      fa.name = "Listing ID"
    end
    feed.attributes << client.resource.feed_attribute do |fa|
      fa.type = :STRING
      fa.name = "Listing Name"
    end
    feed.attributes << client.resource.feed_attribute do |fa|
      fa.type = :URL_LIST
      fa.name = "Final URLs"
    end
    feed.attributes << client.resource.feed_attribute do |fa|
      fa.type = :URL
      fa.name = "Image URL"
    end
    feed.attributes << client.resource.feed_attribute do |fa|
      fa.type = :STRING_LIST
      fa.name = "Contextual Keywords"
    end
  end

  # Issues a mutate request to add the feed and print some information.
  response = client.service.feed.mutate_feeds(
    customer_id: customer_id,
    operations: [operation],
  )
  feed_resource_name = response.results.first.resource_name
  puts "Feed with resource name #{feed_resource_name} was created."

  feed_resource_name
end

# Retrieves the place holder fields to feed attributes map for a real estate feed.
def real_estate_placeholder_fields_map_for(
  client,
  customer_id,
  feed_resource_name
)
  # Constructs the query to get the feed attributes for the specified feed
  # resource name.
  query = <<~QUERY
    SELECT feed.attributes
    FROM feed
    WHERE feed.resource_name = '#{feed_resource_name}'
  QUERY

  # Issues a search request by specifying page size.
  response = client.service.google_ads.search(
    customer_id: customer_id,
    query: query,
    page_size: PAGE_SIZE,
  )

  # Real estate feed attribute names map.
  feed_attribute_names_map = {
    :'Listing ID' => :LISTING_ID,
    :'Listing Name' => :LISTING_NAME,
    :'Final URLs' => :FINAL_URLS,
    :'Image URL' => :IMAGE_URL,
    :'Contextual Keywords' => :CONTEXTUAL_KEYWORDS,
  }

  # Gets the attributes list from the feed and creates a map with keys of
  # placeholder fields and values of feed attributes.
  feed_attributes = response.first.feed.attributes
  placeholder_fields = []
  feed_attributes.each do |feed_attribute|
    unless feed_attribute_names_map.has_key?(feed_attribute.name.to_sym)
      raise "Invalid feed attribute name."
    end
    placeholder_fields << feed_attribute_names_map[feed_attribute.name.to_sym]
  end

  fields_map = {}
  placeholder_fields.zip(feed_attributes) {|a, b| fields_map[a.to_sym] = b }

  fields_map
end

# Creates a feed mapping for a given feed.
def create_feed_mapping(
  client,
  customer_id,
  feed_resource_name,
  placeholders_to_feed_attribute_map
)
  # Creates the feed mapping operation.
  operation = client.operation.create_resource.feed_mapping do |fm|
    fm.placeholder_type = :DYNAMIC_REAL_ESTATE
    fm.feed = feed_resource_name
    fm.attribute_field_mappings << client.resource.attribute_field_mapping do |afm|
      afm.feed_attribute_id = placeholders_to_feed_attribute_map[:LISTING_ID].id
      afm.real_estate_field = :LISTING_ID
    end
    fm.attribute_field_mappings << client.resource.attribute_field_mapping do |afm|
      afm.feed_attribute_id = placeholders_to_feed_attribute_map[:LISTING_NAME].id
      afm.real_estate_field = :LISTING_NAME
    end
    fm.attribute_field_mappings << client.resource.attribute_field_mapping do |afm|
      afm.feed_attribute_id = placeholders_to_feed_attribute_map[:FINAL_URLS].id
      afm.real_estate_field = :FINAL_URLS
    end
    fm.attribute_field_mappings << client.resource.attribute_field_mapping do |afm|
      afm.feed_attribute_id = placeholders_to_feed_attribute_map[:IMAGE_URL].id
      afm.real_estate_field = :IMAGE_URL
    end
    fm.attribute_field_mappings << client.resource.attribute_field_mapping do |afm|
      afm.feed_attribute_id = placeholders_to_feed_attribute_map[:CONTEXTUAL_KEYWORDS].id
      afm.real_estate_field = :CONTEXTUAL_KEYWORDS
    end
  end

  # Issues a mutate request to add the feed mapping and print some information.
  response = client.service.feed_mapping.mutate_feed_mappings(
    customer_id: customer_id,
    operations: [operation],
  )
  puts "Feed mapping with resource name " \
    "#{response.results.first.resource_name} was created."
end

# Adds a new item to the feed.
def create_feed_item(
  client,
  customer_id,
  feed_resource_name,
  placeholders_to_feed_attribute_map
)
  # Creates the feed item operation.
  operation = client.operation.create_resource.feed_item do |fi|
    fi.feed = feed_resource_name
    fi.attribute_values << client.resource.feed_item_attribute_value do |v|
      v.feed_attribute_id = placeholders_to_feed_attribute_map[:LISTING_ID].id
      v.string_value = "ABC123DEF"
    end
    fi.attribute_values << client.resource.feed_item_attribute_value do |v|
      v.feed_attribute_id = placeholders_to_feed_attribute_map[:LISTING_NAME].id
      v.string_value = "Two bedroom with magnificent views"
    end
    fi.attribute_values << client.resource.feed_item_attribute_value do |v|
      v.feed_attribute_id = placeholders_to_feed_attribute_map[:FINAL_URLS].id
      v.string_values << "http://www.example.com/listings/"
    end
    fi.attribute_values << client.resource.feed_item_attribute_value do |v|
      v.feed_attribute_id = placeholders_to_feed_attribute_map[:IMAGE_URL].id
      v.string_value = "http://www.example.com/listings/images?listing_id=ABC123DEF"
    end
    fi.attribute_values << client.resource.feed_item_attribute_value do |v|
      v.feed_attribute_id = placeholders_to_feed_attribute_map[:CONTEXTUAL_KEYWORDS].id
      v.string_values += ["beach community", "ocean view", "two bedroom"]
    end
  end

  # Issues a mutate request to add the feed item and print some information.
  response = client.service.feed_item.mutate_feed_items(
    customer_id: customer_id,
    operations: [operation],
  )
  puts "Feed item with resource name " \
    "#{response.results.first.resource_name} was created."
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'

  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.separator ''
    opts.separator 'Help:'

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

  begin
    add_real_estate_feed(options.fetch(:customer_id).tr("-", ""))
  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.
#
# The example adds a real estate feed, creates the feed mapping, and adds items
# to the feed.

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::V16::Resources::FeedAttribute;
use Google::Ads::GoogleAds::V16::Resources::Feed;
use Google::Ads::GoogleAds::V16::Resources::AttributeFieldMapping;
use Google::Ads::GoogleAds::V16::Resources::FeedMapping;
use Google::Ads::GoogleAds::V16::Resources::FeedItemAttributeValue;
use Google::Ads::GoogleAds::V16::Resources::FeedItem;
use Google::Ads::GoogleAds::V16::Enums::FeedAttributeTypeEnum
  qw(STRING STRING_LIST URL URL_LIST);
use Google::Ads::GoogleAds::V16::Enums::RealEstatePlaceholderFieldEnum
  qw(LISTING_ID LISTING_NAME FINAL_URLS IMAGE_URL CONTEXTUAL_KEYWORDS);
use Google::Ads::GoogleAds::V16::Enums::PlaceholderTypeEnum
  qw(DYNAMIC_REAL_ESTATE);
use Google::Ads::GoogleAds::V16::Services::FeedService::FeedOperation;
use
  Google::Ads::GoogleAds::V16::Services::FeedMappingService::FeedMappingOperation;
use Google::Ads::GoogleAds::V16::Services::FeedItemService::FeedItemOperation;

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

use constant PAGE_SIZE => 1000;

# 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";

sub add_real_estate_feed {
  my ($api_client, $customer_id) = @_;

  # Create a new feed, but you can fetch and re-use an existing feed by skipping the
  # create_feed method and inserting the feed resource name of the existing feed into the
  # get_feed method.
  my $feed_resource_name = create_feed($api_client, $customer_id);

  # Get the page feed details.
  my $feed_attributes =
    get_feed($api_client, $customer_id, $feed_resource_name);

  # Create the feed mapping.
  create_feed_mapping($api_client, $customer_id, $feed_attributes,
    $feed_resource_name);

  # Create a feed item.
  create_feed_item($api_client, $customer_id, $feed_attributes,
    $feed_resource_name);

  return 1;
}

# Creates a feed.
sub create_feed {
  my ($api_client, $customer_id) = @_;

  # Create a Listing ID attribute.
  my $listing_id_attribute =
    Google::Ads::GoogleAds::V16::Resources::FeedAttribute->new({
      type => STRING,
      name => "Listing ID"
    });
  # Create a Listing Name attribute.
  my $listing_name_attribute =
    Google::Ads::GoogleAds::V16::Resources::FeedAttribute->new({
      type => STRING,
      name => "Listing Name"
    });
  # Create a Final URLs attribute.
  my $final_urls_attribute =
    Google::Ads::GoogleAds::V16::Resources::FeedAttribute->new({
      type => URL_LIST,
      name => "Final URLs"
    });
  # Create an Image URL attribute.
  my $image_url_attribute =
    Google::Ads::GoogleAds::V16::Resources::FeedAttribute->new({
      type => URL,
      name => "Image URL"
    });
  # Create a Contextual Keywords attribute.
  my $contextual_keywords_attribute =
    Google::Ads::GoogleAds::V16::Resources::FeedAttribute->new({
      type => STRING_LIST,
      name => "Contextual Keywords"
    });

  # Create a feed.
  my $feed = Google::Ads::GoogleAds::V16::Resources::Feed->new({
      name       => "Real Estate Feed #" . uniqid(),
      attributes => [
        $listing_id_attribute, $listing_name_attribute,
        $final_urls_attribute, $image_url_attribute,
        $contextual_keywords_attribute
      ]});

  # Create a feed operation.
  my $feed_operation =
    Google::Ads::GoogleAds::V16::Services::FeedService::FeedOperation->new(({
      create => $feed
    }));

  # Add the feed.
  my $feeds_response = $api_client->FeedService()->mutate({
      customerId => $customer_id,
      operations => [$feed_operation]});

  my $feed_resource_name = $feeds_response->{results}[0]{resourceName};

  printf "Feed with resource name '%s' was created.\n", $feed_resource_name;

  return $feed_resource_name;
}

# Retrieves details about a feed. The initial query retrieves the FeedAttributes, or columns,
# of the feed. Each FeedAttribute will also include the FeedAttributeId, which will be used in
# a subsequent step. The example then inserts a new key, value pair into a hash for each
# FeedAttribute, which is the return value of the method. The keys are the placeholder types
# that the columns will be. The values are the FeedAttributes.
sub get_feed {
  my ($api_client, $customer_id, $feed_resource_name) = @_;

  # Construct the search query.
  my $search_query =
    sprintf "SELECT feed.attributes FROM feed WHERE feed.resource_name = '%s'",
    $feed_resource_name;

  my $search_response = $api_client->GoogleAdsService()->search({
    customerId => $customer_id,
    query      => $search_query,
    pageSize   => PAGE_SIZE
  });

  # Get the first result because we only need the single feed item we created previously.
  my $google_ads_row = $search_response->{results}[0];

  # Get the attributes list from the feed and create a hash with keys of each attribute and
  # values of each corresponding ID.
  my $feed_attribute_list = $google_ads_row->{feed}{attributes};

  # Create a hash to return.
  my $feed_attributes = {};
  # Loop through each of the feed attributes and populates the hash.
  foreach my $feed_attribute (@$feed_attribute_list) {
    my $feed_attribute_name = $feed_attribute->{name};

    if ($feed_attribute_name eq "Listing ID") {
      $feed_attributes->{LISTING_ID} = $feed_attribute;
    } elsif ($feed_attribute_name eq "Listing Name") {
      $feed_attributes->{LISTING_NAME} = $feed_attribute;
    } elsif ($feed_attribute_name eq "Final URLs") {
      $feed_attributes->{FINAL_URLS} = $feed_attribute;
    } elsif ($feed_attribute_name eq "Image URL") {
      $feed_attributes->{IMAGE_URL} = $feed_attribute;
    } elsif ($feed_attribute_name eq "Contextual Keywords") {
      $feed_attributes->{CONTEXTUAL_KEYWORDS} = $feed_attribute;
    } else {
      die("Invalid attribute name.");
    }
  }

  return $feed_attributes;
}

# Creates a feed mapping for a given feed.
sub create_feed_mapping {
  my ($api_client, $customer_id, $feed_attributes, $feed_resource_name) = @_;

  # Map the FeedAttributeIds to the placeholder values. The FeedAttributeId is the ID of the
  # FeedAttribute created in the create_feed method. This can be thought of as the generic ID of
  # the column of the new feed. The placeholder value specifies the type of column this is in
  # the context of a real estate feed (e.g. a LISTING_ID or LISTING_NAME). The FeedMapping
  # associates the feed column by ID to this type and controls how the feed attributes are
  # presented in dynamic content.
  # See https://developers.google.com/google-ads/api/reference/rpc/latest/RealEstatePlaceholderFieldEnum.RealEstatePlaceholderField
  # for the full list of placeholder values.
  my $listing_id_mapping =
    Google::Ads::GoogleAds::V16::Resources::AttributeFieldMapping->new({
      feedAttributeId => $feed_attributes->{LISTING_ID}{id},
      realEstateField => LISTING_ID
    });
  my $listing_name_mapping =
    Google::Ads::GoogleAds::V16::Resources::AttributeFieldMapping->new({
      feedAttributeId => $feed_attributes->{LISTING_NAME}{id},
      realEstateField => LISTING_NAME
    });
  my $final_urls_mapping =
    Google::Ads::GoogleAds::V16::Resources::AttributeFieldMapping->new({
      feedAttributeId => $feed_attributes->{FINAL_URLS}{id},
      realEstateField => FINAL_URLS
    });
  my $image_url_mapping =
    Google::Ads::GoogleAds::V16::Resources::AttributeFieldMapping->new({
      feedAttributeId => $feed_attributes->{IMAGE_URL}{id},
      realEstateField => IMAGE_URL
    });
  my $contextual_keywords_mapping =
    Google::Ads::GoogleAds::V16::Resources::AttributeFieldMapping->new({
      feedAttributeId => $feed_attributes->{CONTEXTUAL_KEYWORDS}{id},
      realEstateField => CONTEXTUAL_KEYWORDS
    });

  # Create a feed mapping.
  my $feed_mapping = Google::Ads::GoogleAds::V16::Resources::FeedMapping->new({
      placeholderType        => DYNAMIC_REAL_ESTATE,
      feed                   => $feed_resource_name,
      attributeFieldMappings => [
        $listing_id_mapping, $listing_name_mapping,
        $final_urls_mapping, $image_url_mapping,
        $contextual_keywords_mapping
      ]});

  # Create a feed mapping operation.
  my $feed_mapping_operation =
    Google::Ads::GoogleAds::V16::Services::FeedMappingService::FeedMappingOperation
    ->new({
      create => $feed_mapping
    });

  # Add the feed mapping.
  my $feed_mappings_response = $api_client->FeedMappingService()->mutate({
      customerId => $customer_id,
      operations => [$feed_mapping_operation]});

  printf "Created feed mapping with resource name '%s'.\n",
    $feed_mappings_response->{results}[0]{resourceName};
}

# Adds a new item to the feed.
sub create_feed_item {
  my ($api_client, $customer_id, $feed_attributes, $feed_resource_name) = @_;

  # Create the listing ID feed attribute value.
  my $listing_id =
    Google::Ads::GoogleAds::V16::Resources::FeedItemAttributeValue->new({
      feedAttributeId => $feed_attributes->{LISTING_ID}{id},
      stringValue     => "ABC123DEF"
    });
  # Create the listing name feed attribute value.
  my $listing_name =
    Google::Ads::GoogleAds::V16::Resources::FeedItemAttributeValue->new({
      feedAttributeId => $feed_attributes->{LISTING_NAME}{id},
      stringValue     => "Two bedroom with magnificent views"
    });
  # Create the final URLs feed attribute value.
  my $final_urls =
    Google::Ads::GoogleAds::V16::Resources::FeedItemAttributeValue->new({
      feedAttributeId => $feed_attributes->{FINAL_URLS}{id},
      stringValue     => "http://www.example.com/listings/"
    });

  # Optionally insert additional attributes here, such as address, city, description, etc.

  # Create the image URL feed attribute value.
  my $image_url =
    Google::Ads::GoogleAds::V16::Resources::FeedItemAttributeValue->new({
      feedAttributeId => $feed_attributes->{IMAGE_URL}{id},
      stringValue     =>
        "http://www.example.com/listings/images?listing_id=ABC123DEF"
    });
  # Create the contextual keywords feed attribute value.
  my $contextual_keywords =
    Google::Ads::GoogleAds::V16::Resources::FeedItemAttributeValue->new({
      feedAttributeId => $feed_attributes->{CONTEXTUAL_KEYWORDS}{id},
      stringValues    => ["beach community", "ocean view", "two bedroom"]});

  # Create a feed item, specifying the Feed ID and the attributes created above.
  my $feed_item = Google::Ads::GoogleAds::V16::Resources::FeedItem->new({
      feed            => $feed_resource_name,
      attributeValues => [
        $listing_id, $listing_name, $final_urls,
        $image_url,  $contextual_keywords
      ]});

  # Create a feed item operation.
  my $feed_item_operation =
    Google::Ads::GoogleAds::V16::Services::FeedItemService::FeedItemOperation->
    new({
      create => $feed_item
    });

  # Add the feed item.
  my $feed_items_response = $api_client->FeedItemService()->mutate({
      customerId => $customer_id,
      operations => [$feed_item_operation]});

  printf "Created feed item with resource name '%s'.\n",
    $feed_items_response->{results}[0]{resourceName};
}

# 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);

# 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);

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

=pod

=head1 NAME

add_real_estate_feed

=head1 DESCRIPTION

The example adds a real estate feed, creates the feed mapping, and adds items
to the feed.

=head1 SYNOPSIS

add_real_estate_feed.pl [options]

    -help                       Show the help message.
    -customer_id                The Google Ads customer ID.

=cut