附加信息设置服务

使用附加信息设置服务

假设您要通过 AdWords 投放广告来宣传一家餐厅。您已经制作了一个 AdWords 广告系列,但想要显示与餐厅相关的如下这些额外信息:

  • 营业时间:此链接可将用户转至 http://www.example.com/storehours。
  • 营养数据:此链接可将用户转至 http://www.example.com/menu/nutritiondata,让用户了解菜品的营养信息。
  • 欢乐时光:此链接可将用户转至 http://www.example.com/happyhours,链接只在以下时段显示:周一至周五下午 6 点到晚上 9 点;周六下午 5 点到晚上 8 点。
  • 感恩特惠:您计划在 11 月 27 日到 28 日推出一份感恩特惠菜单。此链接只在 11 月 20 日到 27 日期间显示,用于引导用户访问 http://www.example.com/thanksgiving 订餐。

以上每项信息都是 AdWords 中的一种广告附加信息。您可以使用 AdWords API 中的附加信息设置服务管理附加信息。

添加广告附加信息

广告附加信息可在帐号、广告系列或广告组一级添加,但不是每个级别都能使用所有附加信息类型。如需添加新的广告附加信息,请使用 ADDSET 运算符。如果使用 SET 运算符而相关的广告附加信息不存在,系统将添加新的广告附加信息。广告附加信息有多种格式。

使用附加链接时,除了可以链接到您的主着陆页之外,还可以链接到您网站中的特定子网页,从而让用户更轻松地浏览您的网站。

以下代码段展示了如何使用 CampaignExtensionSettingService 来向广告系列添加新的广告附加信息。

// Get the CampaignExtensionSettingService.
CampaignExtensionSettingService campaignExtensionSettingService =
    (CampaignExtensionSettingService) user.GetService(
         AdWordsService.v201705.CampaignExtensionSettingService);

CampaignExtensionSetting campaignExtensionSetting =
    new CampaignExtensionSetting();
campaignExtensionSetting.campaignId = campaignId;
campaignExtensionSetting.extensionType = FeedType.SITELINK;

SitelinkFeedItem link1 = new SitelinkFeedItem() {
    sitelinkText = "Store Hours",
    sitelinkUrl = "http://www.example.com/storehours"
};

SitelinkFeedItem link2 = new SitelinkFeedItem() {
    sitelinkText = "Thanksgiving Specials",
    sitelinkUrl = "http://www.example.com/thanksgiving",
    startTime = "20141120 000000 EST",
    endTime = "20141127 235959 EST",

    // Target this sitelink for United States only. See
    // https://developers.google.com/adwords/api/docs/appendix/geotargeting
    // for valid geolocation codes.
    geoTargeting = new Location () {
      id = 2840
    };
};

SitelinkFeedItem link3 = new SitelinkFeedItem() {
    sitelinkText = "Nutrition Data",
    sitelinkUrl = "http://www.example.com/menu/nutritiondata"
};

SitelinkFeedItem link4 = new SitelinkFeedItem() {
    sitelinkText = "Happy hours",
    sitelinkUrl = "http://www.example.com/happyhours",
    scheduling = new FeedItemSchedule[] {
        new FeedItemSchedule() {
            dayOfWeek = AdWords.v201705.DayOfWeek.MONDAY,
            startHour = 18,
            startMinute = MinuteOfHour.ZERO,
            endHour = 21,
            endMinute = MinuteOfHour.ZERO
        },
        new FeedItemSchedule() {
            dayOfWeek = AdWords.v201705.DayOfWeek.TUESDAY,
            startHour = 18,
            startMinute = MinuteOfHour.ZERO,
            endHour = 21,
            endMinute = MinuteOfHour.ZERO
        },
        new FeedItemSchedule() {
            dayOfWeek = AdWords.v201705.DayOfWeek.WEDNESDAY,
            startHour = 18,
            startMinute = MinuteOfHour.ZERO,
            endHour = 21,
            endMinute = MinuteOfHour.ZERO
        },
        new FeedItemSchedule() {
            dayOfWeek = AdWords.v201705.DayOfWeek.THURSDAY,
            startHour = 18,
            startMinute = MinuteOfHour.ZERO,
            endHour = 21,
            endMinute = MinuteOfHour.ZERO
        },
        new FeedItemSchedule() {
            dayOfWeek = AdWords.v201705.DayOfWeek.FRIDAY,
            startHour = 18,
            startMinute = MinuteOfHour.ZERO,
            endHour = 21,
            endMinute = MinuteOfHour.ZERO
        },
        new FeedItemSchedule() {
            dayOfWeek = AdWords.v201705.DayOfWeek.SATURDAY,
            startHour = 17,
            startMinute = MinuteOfHour.ZERO,
            endHour = 21,
            endMinute = MinuteOfHour.ZERO
        }
    }
};

campaignExtensionSetting.extensionSetting = new ExtensionSetting() {
    extensions = new ExtensionFeedItem[] {
        link1, link2, link3, link4
    },
};

CampaignExtensionSettingOperation operation = new CampaignExtensionSettingOperation() {
    operand = campaignExtensionSetting,
    @operator = Operator.ADD,
};

CampaignExtensionSettingReturnValue retVal = campaignExtensionSettingService.mutate(
    new CampaignExtensionSettingOperation[] {operation});

附加电话信息

您可以使用 CallFeedItem 附加信息来在广告旁边列出商家电话号码,让客户可以直接从广告中致电给您。以下代码段展示了如何实现此目的:

CallFeedItem callFeedItem = new CallFeedItem() {
    callCountryCode = "US",
    callPhoneNumber = "212-565-0000",
};

CampaignExtensionSetting campaignExtensionSetting =
    new CampaignExtensionSetting();
campaignExtensionSetting.campaignId = campaignId;

campaignExtensionSetting.extensionSetting = new ExtensionSetting() {
    extensions = new ExtensionFeedItem[] { callFeedItem },
};

附加评价信息

您可以使用附加评价信息来在广告旁边列出客户对商家的评价。以下代码段展示了如何创建附加评价信息:

ReviewFeedItem reviewFeeditem = new ReviewFeedItem() {
    reviewSourceName = "Example Food review magazine",
    reviewSourceUrl =
        "http://www.example.com/reviews/2014/03/the-amazing-example-hotel",
    reviewText = "The best food in New York city!",
    reviewTextExactlyQuoted = true
};

CampaignExtensionSetting campaignExtensionSetting =
    new CampaignExtensionSetting();
campaignExtensionSetting.campaignId = campaignId;

campaignExtensionSetting.extensionSetting = new ExtensionSetting() {
    extensions = new ExtensionFeedItem[] { reviewFeeditem },
};

附加宣传信息

通过广告附加宣传信息,您可以在搜索广告下方以文字形式提供额外的详情(例如所提供的产品与服务)。以下代码段展示了如何创建附加宣传信息:

CalloutFeedItem freeDeliveryCallout = new CalloutFeedItem() {
   calloutText = "Free delivery",
};
CalloutFeedItem kidsCallout = new CalloutFeedItem() {
   calloutText = "Kids eat free",
};

CampaignExtensionSetting campaignExtensionSetting = new CampaignExtensionSetting();
campaignExtensionSetting.campaignId = campaignId;
campaignExtensionSetting.extensionType = FeedType.CALLOUT;
campaignExtensionSetting.extensionSetting = new ExtensionSetting() {
    extensions = new ExtensionFeedItem[] {
        freeDeliveryCallout, kidsCallout
    }
};

附加应用信息

如果您的企业针对移动用户开发了 Android 或 iOS 应用,您可以使用附加应用信息来在广告旁边显示应用链接。附加应用信息只会向当前已登录 Google 帐号且尚未安装您应用的用户显示。用户只需点击附加应用信息链接,即可转到您的应用在 Google Play 或 Apple iTunes 上的页面。以下代码段展示了如何为 Google Play 上的应用创建附加应用信息:

AppFeedItem appFeedItem = new AppFeedItem() {
    appId = "com.example.mobileapp",
    appStore = AppFeedItemAppStore.GOOGLE_PLAY,
    appLinkText = "Install our mobile app!",
    appUrl = "https://play.google.com/store/apps/details?id=com.example.mobileapp"
};

CampaignExtensionSetting campaignExtensionSetting =
    new CampaignExtensionSetting();
campaignExtensionSetting.campaignId = campaignId;

campaignExtensionSetting.extensionSetting = new ExtensionSetting() {
    extensions = new ExtensionFeedItem[] { appFeedItem },
};

附加短信信息

通过附加短信信息,用户可以看到您的广告,点击图标,然后直接发短信与您取得联系。只需点按一下您的广告,用户就可以联系您并提出预约请求,获得报价,索要资料,或请求服务。以下代码段展示了如何使用 MessageFeedItem 实现这一目的:

MessageFeedItem messageFeedItem = new MessageFeedItem() {
    messageBusinessName = "Travel Here",
    messageCountryCode = "US",
    messagePhoneNumber = "212-565-0000",
    messageText = "I want to know more.",
    messageExtensionText = "Ask us about travel.",
};

CampaignExtensionSetting campaignExtensionSetting =
    new CampaignExtensionSetting();
campaignExtensionSetting.campaignId = campaignId;

campaignExtensionSetting.extensionSetting = new ExtensionSetting() {
    extensions = new ExtensionFeedItem[] { messageFeedItem },
};

附加价格信息

附加价格信息是一种可向用户提供有关产品或服务的比较详情和价格信息的附加信息。通过附加价格信息,您可以输入服务、产品、活动或其他内容的列表,以及要显示给用户的价格列表。

与其他类型的附加信息一样,附加价格信息也是完全可配置、可定位的。此类附加信息可显示最少 3 项(最多 8 项)产品或服务的名称、说明信息和价格详情。

您可以在帐号、广告系列或广告组一级添加附加价格信息。

以下代码段展示了如何创建附加价格信息:

// Create the price extension feed item.
PriceFeedItem priceFeedItem = new PriceFeedItem();
priceFeedItem.setPriceExtensionType(PriceExtensionType.SERVICES);

// Price qualifier is optional.
priceFeedItem.setPriceQualifier(PriceExtensionPriceQualifier.FROM);
priceFeedItem.setTrackingUrlTemplate("http://tracker.example.com/?u={lpurl}");
priceFeedItem.setLanguage("en");
FeedItemCampaignTargeting campaignTargeting = new FeedItemCampaignTargeting();
campaignTargeting.setTargetingCampaignId(campaignId);
priceFeedItem.setCampaignTargeting(campaignTargeting);
priceFeedItem.setScheduling(
    new FeedItemScheduling(
        new FeedItemSchedule[] {
          new FeedItemSchedule(DayOfWeek.SUNDAY, 10, MinuteOfHour.ZERO, 18, MinuteOfHour.ZERO),
          new FeedItemSchedule(DayOfWeek.SATURDAY, 10, MinuteOfHour.ZERO, 22, MinuteOfHour.ZERO)
        }));

// To create a price extension, at least three table rows are needed.
List<PriceTableRow> priceTableRows = new ArrayList<>();
String currencyCode = "USD";
priceTableRows.add(
    createPriceTableRow(
        "Scrubs",
        "Body Scrub, Salt Scrub",
        "http://www.example.com/scrubs",
        "http://m.example.com/scrubs",
        60000000,
        currencyCode,
        PriceExtensionPriceUnit.PER_HOUR));
priceTableRows.add(
    createPriceTableRow(
        "Hair Cuts",
        "Once a month",
        "http://www.example.com/haircuts",
        "http://m.example.com/haircuts",
        75000000,
        currencyCode,
        PriceExtensionPriceUnit.PER_MONTH));
priceTableRows.add(
    createPriceTableRow(
        "Skin Care Package",
        "Four times a month",
        "http://www.example.com/skincarepackage",
        null,
        250000000,
        currencyCode,
        PriceExtensionPriceUnit.PER_MONTH));
priceFeedItem.setTableRows(priceTableRows.toArray(new PriceTableRow[priceTableRows.size()]));

// Create your campaign extension settings. This associates the sitelinks
// to your campaign.
CustomerExtensionSetting customerExtensionSetting = new CustomerExtensionSetting();
customerExtensionSetting.setExtensionType(FeedType.PRICE);
ExtensionSetting extensionSetting = new ExtensionSetting();
extensionSetting.setExtensions(new ExtensionFeedItem[] {priceFeedItem});
customerExtensionSetting.setExtensionSetting(extensionSetting);

createPriceTableRow 的引用定义如下:

/**
 * Creates a new {@link PriceTableRow} with the specified attributes.
 *
 * @param header the header for the row
 * @param description the description for the row
 * @param finalUrl the final URL for the row
 * @param finalMobileUrl the final mobile URL for the row, or null if this field should not be set
 * @param priceInMicros the price for the row, in micros
 * @param currencyCode the currency for the row
 * @param priceUnit the price unit for the row
 * @return a new {@link PriceTableRow}
 */
private static PriceTableRow createPriceTableRow(
    String header,
    String description,
    String finalUrl,
    String finalMobileUrl,
    long priceInMicros,
    String currencyCode,
    PriceExtensionPriceUnit priceUnit) {
  PriceTableRow priceTableRow = new PriceTableRow();
  priceTableRow.setHeader(header);
  priceTableRow.setDescription(description);

  UrlList finalUrls = new UrlList();
  finalUrls.setUrls(new String[] {finalUrl});
  priceTableRow.setFinalUrls(finalUrls);

  if (finalMobileUrl != null) {
    UrlList finalMobileUrls = new UrlList();
    finalMobileUrls.setUrls(new String[] {finalMobileUrl});
    priceTableRow.setFinalMobileUrls(finalMobileUrls);
  }

  MoneyWithCurrency price = new MoneyWithCurrency();
  Money priceMoney = new Money();
  price.setCurrencyCode(currencyCode);
  priceMoney.setMicroAmount(priceInMicros);
  price.setMoney(priceMoney);
  priceTableRow.setPrice(price);
  priceTableRow.setPriceUnit(priceUnit);

  return priceTableRow;
}

附加促销信息

通过附加促销信息,您可以突出显示销售信息和其他促销活动,让用户了解到他们现在购买可以享受的优惠。您可以使用多个字段来准确自定义要在附加信息中显示哪些内容,但必须填写的字段包括:

  • promotionTarget - 显示附加信息时在广告上显示的文字。
  • percentOffmoneyAmountOff - 必须填写任一字段。这些字段向用户展示折扣的力度。

    • percentOff 采用以百万分之一表示的值,其中 100 万个百万分之一表示 1%,呈现时显示为百分比。例如,值 10000000 将呈现为“10%”。
    • moneyAmountOff 同样以百万分之一表示。它需要币种和金额。
  • finalUrls - 您的着陆页的网址目标(如果某个用户点击附件信息)。

选填字段:

  • occasion - 例如 NEW_YEARSHALLOWEEN

    • 在不使用附加信息设置服务的情况下使用 occasion 时,请确保相应的值与 PromotionFeedItem 的已记录的枚举值完全匹配。
  • discountModifier - 允许您向促销信息中添加“高达”等措辞(如果您有可变的促销价格)。

    • 在不使用附加信息设置服务的情况下使用 discountModifier 时,请确保相应的值与 PromotionFeedItem 的已记录的枚举值完全匹配。
  • promotionCode - 供用户输入相应内容以便享受折扣。

  • ordersOverAmount - 表示用户至少需要支出多少金额才能参加促销活动。

    • 请注意,每个 PromotionFeedItem 只能使用一个 promotionCodeordersOverAmount
  • promotionStartpromotionEnd - 确保附加信息仅在促销活动期间显示。这些字段应采用日期时间格式,不过仅支持午夜时间。例如,对于仅在 6 月进行的促销活动,您可以将 promotionStart 设置为“20170601 000000”,并将 promotionEnd 设置为“20170701 000000”。

    • 您可以通过设置特殊值“00000101 000000”来清除这些字段。

要详细了解其余字段情,请查看 PromotionFeedItem 文档

以下示例代码段展示了如何创建附加促销信息:

PromotionFeedItem promotionFeedItem = new PromotionFeedItem() {
    promotionTarget = "Wool Socks",
    percentOff = 10000000,
    promotionCode = "WinterSocksDeal",
    finalUrls = new string[] { "http://www.example.com/socks" },
};

CampaignExtensionSetting campaignExtensionSetting =
    new CampaignExtensionSetting();
campaignExtensionSetting.campaignId = campaignId;

campaignExtensionSetting.extensionSetting = new ExtensionSetting() {
    extensions = new ExtensionFeedItem[] { promotionFeedItem },
};

更新广告附加信息

假设您决定将餐厅周六的欢乐时光改为下午 5 点到晚上 10 点。

首先,获取现有设置的列表:

// Get the CampaignExtensionSettingService.
CampaignExtensionSettingService campaignExtensionSettingService =
    (CampaignExtensionSettingService) user.GetService(
         AdWordsService.v201705.CampaignExtensionSettingService);

Selector selector = new Selector() {
    fields = new string[] { "CampaignId", "ExtensionType", "Extensions" },
    predicates = new Predicate[] {
        new Predicate() {
            field = "CampaignId",
            @operator = PredicateOperator.EQUALS,
            values = new string[] {campaignId.ToString()}
        },
        new Predicate() {
            field = "ExtensionType",
            @operator = PredicateOperator.EQUALS,
            values = new string[] {"SITELINK"}
        },
    }
};

CampaignExtensionSettingPage page = campaignExtensionSettingService.get(selector);

接着,更新所需的附加链接:

CampaignExtensionSetting campaignExtensionSetting = page.entries[0];
foreach (SitelinkFeedItem siteLink in
     campaignExtensionSetting.extensionSetting.extensions) {
  if (siteLink.sitelinkText == "Happy hours") {
    foreach (FeedItemSchedule schedule in siteLink.scheduling) {
      if (schedule.dayOfWeek == AdWords.v201705.DayOfWeek.SATURDAY) {
         schedule.startHour = 17;
         schedule.startMinute = MinuteOfHour.ZERO;
         schedule.endHour = 22;
         schedule.endMinute = MinuteOfHour.ZERO;
      }
    }
  }
}

最后,将修改过的 campaignExtensionSetting 发送到服务器。

CampaignExtensionSettingOperation operation = new CampaignExtensionSettingOperation() {
  operand = campaignExtensionSetting,
  @operator = Operator.SET,
};

为避免新设置覆盖原有设置,请记得要一起传回所有 Feed 项,哪怕您只是修改了其中一项。

移除广告附加信息

附加信息设置服务在后台运行时仍会使用 Feed 来控制您的广告附加信息。您创建新的附加信息设置后,该服务会在相应的 Feed 中为您创建 Feed 项,并根据您使用的具体服务将其与指定的广告系列、广告组或帐号相关联。

同样,当您从附加信息设置中移除 ExtensionFeedItem 或整体移除附加信息设置后,该服务会移除 Feed 项与附加实体之间的关联,但不会移除 Feed 项,因为它们可能与其他实体相关联。

通过以下两种方式可以移除 Feed 项与实体之间的关联:

  1. 您可以使用 REMOVE 运算符移除整个附加信息设置。这样一来,将移除相应实体与附加信息设置中所有 Feed 项之间的关联。
  2. 您可以移除附加信息设置中的单个 ExtensionFeedItem,为此,请指定一组新的 ExtensionFeedItem(不包含您要移除的那一个)。

在这两种情况下,基础 Feed 项都不会被移除。因此,如果 Feed 项不再与任何其他实体相关联,则应考虑删除 Feed 项,这样可以释放空间并使您日后能够生成新的附加信息。或者,您也可以在其他附加信息设置中重复使用 Feed 项

移除附加信息后,如果您既没有移除也没有重复使用通过附加信息设置服务中创建的 Feed 项,那么这些 Feed 项将随时间累积,最终可能会达到您帐号中所允许的 Feed 项数量的上限

删除 Feed 项

如果要在取消基础 Feed 项与实体的关联之后将其删除,您可以从删除的附加信息中获取 feedIdfeedItemId,然后删除相应的 FeedItem

CampaignExtensionSettingOperation operation = new CampaignExtensionSettingOperation() {
  operand = campaignExtensionSetting,
  @operator = Operator.REMOVE,
};

campaignExtensionSettingService.mutate(new CampaignExtensionSettingOperation[] {operation});

List<FeedItemOperation> operations = new List<FeedItemOperation>();
foreach(ExtensionFeedItem extensionFeedItem in
    campaignExtensionSetting.extensionSetting.extensions) {
  FeedItemOperation operation = new FeedItemOperation() {
    @operator = Operator.REMOVE,
    operand = new FeedItem() {
      feedItemId = extensionFeedItem.feedItemId,
      feedId = extensionFeedItem.feedId
    }
  };
  operations.Add(operation);
}

feedItemService.mutate(operations.ToArray());

CampaignExtensionSettingService 中的第一个 REMOVE 会移除该附加信息与广告系列之间的关联。FeedItemService 中的第二个 REMOVE 会移除基础 Feed 项,从而释放空间,这样,您日后便可以使用新的附加信息。

重复使用 Feed 项

您可以将同一个 Feed 项与多个实体相关联。例如,如果您希望在多个广告系列上显示同一附加链接,则可以将各个广告系列与同一组 Feed 项相关联。

同样,从某个实体中移除广告附加信息之后,您可以通过从响应中提取 feedItemId 将基础 Feed 项与其他实体相关联。

例如,如果您将之前移除的附加信息设置中的原有 feedItemId 存储在变量 storedFeedItemId 中,则只需在 SitelinkFeedItem 中填充 feedItemId,便可以重复使用该项:

SitelinkFeedItem link = new SitelinkFeedItem() {
  feedItemId = storedFeedItemId
};

CampaignExtensionSetting campaignExtensionSetting = new CampaignExtensionSetting();
campaignExtensionSetting.extensionSetting = new ExtensionSetting() {
  extensions = new ExtensionFeedItem[] {
    link
  }
};

CampaignExtensionSettingOperation operation = new CampaignExtensionSettingOperation() {
  operand = campaignExtensionSetting,
  @operator = Operator.ADD,
};

CampaignExtensionSettingReturnValue retVal = campaignExtensionSettingService.mutate(
    new CampaignExtensionSettingOperation[] {operation});

附加信息的定位选项

除了使用 ExtensionSetting客户广告系列广告组一级定位附加信息之外,您还可以通过设置 campaignTargetingadGroupTargetingkeywordTargetinggeoTargeting 属性来为单个 ExtensionFeedItem 设置定位选项。

系统会将这些定位选项与 ExtensionSetting 属性相结合,以选择在某个展示机会中使用的附加信息 Feed 项。

例如,假设您创建了采用如下定位选项的 SitelinkFeedItem

adGroupTargeting.TargetingAdGroupId = 12345
keywordTargeting.id = 7890

此外,您将 AdGroupExtensionSetting广告平台限制设为了 MOBILE

在展示此广告组时,只有当展示机会属性与 AdGroupExtensionSettingSitelinkFeedItem 对象的定位选项都相符时,AdWords 才会投放来自 SitelinkFeedItem 的附加链接。

情形 展示机会属性 结果
1
  • 广告组 ID:12345
  • 关键字:7890
  • 桌面设备用户
不会使用 SitelinkFeedItem,因为广告平台(桌面设备)与 AdGroupExtensionSetting 的定位选项不相符。
2
  • 广告组 ID:12345
  • 关键字:8910
  • 移动设备用户
不会使用 SitelinkFeedItem,因为关键字 (7890) 与 SitelinkFeedItem 的定位选项不相符。
3
  • 广告组 ID:12345
  • 关键字:7890
  • 移动设备用户
会使用 SitelinkFeedItem,因为各个属性与 AdGroupExtensionSettingSitelinkFeedItem 的定位选项都相符。

跟踪广告附加信息效果

您可使用占位符报告占位符 Feed 项报告来跟踪广告附加信息的效果。请通过 FeedItemId 列识别您的广告附加信息。

将广告附加信息迁移至附加信息设置服务

本指南的其余部分将介绍附加信息设置服务的利与弊,以帮助您决定是开始使用此类服务,还是继续使用 Feed 服务。同时,我们还将说明如何迁移至新服务。

附加信息设置服务在基于 Feed 的现有广告附加信息基础上进行了简化。这项新服务具有以下特点:

  • 支持所有受支持的广告附加信息的具体类型。
  • 提供简化的 API 来帮您管理广告系列或广告组的广告附加信息。

我应该迁移吗?

附加信息设置服务涵盖 AdWords 界面中当前可用的所有广告附加信息功能。只要花点时间重新编写服务并迁移数据,即可使用简化的附加信息设置服务,大多数用户都可以获益。下列各部分将帮助您决定是否要迁移到附加信息设置服务。

什么情况下更适合使用附加信息设置服务?

如果只需为广告系列或广告组添加广告附加信息、设定其设备偏好设置,或管理其投放时间设置,我们推荐您使用附加信息设置服务。使用附加信息设置服务的一项额外优势是,我们会负责维护 Feed 的架构和数据,因此您无需更新基础 Feed 结构(这点与 Feed 服务不同)。

什么情况下更适合使用原有的 Feed 服务?

如果需要使用下面所列的一项或多项功能,我们建议您使用原有的 Feed 服务:

  • 附加地址信息:附加信息设置服务不支持附加地址信息。
  • 自定义字段或匹配函数:附加信息设置服务不支持 Feed 中的自定义字段,也不支持撰写自定义的匹配函数
  • 多个 Feed:使用附加信息设置服务时,系统管理的每一种附加信息类型只能有一个 Feed。

迁移步骤

如果您只使用在 AdWords 界面中创建的 Feed,即可直接使用附加信息设置服务。

不过,如果您利用 API 创建了自定义 Feed,则需要先执行以下操作:

  1. 获取自定义 Feed 中的 Feed 项。
  2. 找出您要保留的 Feed 项。
  3. 删除使用自定义 Feed 中的 Feed 项的 CustomerFeedCampaignFeedAdGroupFeed
  4. 创建使用新 ExtensionFeedItemCustomerExtensionSettingCampaignExtensionSettingAdGroupExtensionSetting
  5. (可选)删除不再使用的 Feed 项。

下面几个部分将重点介绍如何在广告系列一级升级广告附加信息,不过所述的流程同样适用于广告组一级。

获取自定义 Feed 中的 Feed 项

要获取自定义 Feed 中的 Feed 项,您必须首先找出您使用 AdWords API 创建的所有自定义 Feed,方法如下:

private Feed[] GetFeeds(AdWordsUser user) {
  FeedService feedService = (FeedService)user.GetService(
      AdWordsService.v201705.FeedService);
  FeedPage page = feedService.query("SELECT Id, Name, Attributes where " +
      "Origin='USER' and FeedStatus='ENABLED'");
  return page.entries;
}

接着,获取这些 Feed 中的 Feed 项。以下示例使用的是附加链接,不过适用于其他广告附加信息的方法与此相似。

private FeedItem[] GetFeedItems(AdWordsUser user, long feedId) {
  FeedItemService feedItemService = (FeedItemService) user.GetService(
      AdWordsService.v201705.FeedItemService);
  FeedItemPage page = feedItemService.query(string.Format("Select FeedItemId, " +
      "AttributeValues, Scheduling where Status = 'ENABLED' and FeedId = '{0}'", feedId));
  return page.entries;
}

为方便处理,请将值加载到在本地定义的类“SitelinkFromFeed”中:

class SiteLinkFromFeed {
  public long FeedId {get;set;}
  public long FeedItemId { get; set; }
  public string Text { get; set; }
  public string Url { get; set; }
  public string[] FinalUrls { get; set; }
  public string[] FinalMobileUrls { get; set; }
  public string TrackingUrlTemplate { get; set; }
  public string Line2 { get; set; }
  public string Line3 { get; set; }
  public FeedItemSchedule[] Scheduling { get; set; }
}

您还应定义一些常量,以帮助更好地解析 FeedMapping。您可以在 Feed 占位符页面上找到这些占位符值。

const int PLACEHOLDER_TYPE_SITELINKS = 1;

class SiteLinkFields {
  public const long TEXT = 1;
  public const long URL = 2;
  public const long LINE2 = 3;
  public const long LINE3 = 4;
  public const long FINAL_URLS = 5;
  public const long FINAL_MOBILE_URLS = 6;
  public const long TRACKING_URL_TEMPLATE = 7;
};

要将 FeedItem 转换为 SitelinksFromFeed 对象,您必须获取 Feed 的 FeedMapping,然后将每个属性映射到相应的对象属性:

private Dictionary<long, SiteLinkFromFeed> GetSiteLinksFromFeed(AdWordsUser user,
    long feedId) {
  Dictionary<long, SiteLinkFromFeed> siteLinks =
      new Dictionary<long, SiteLinkFromFeed>();

  Dictionary<long, long> feedMappings = GetFeedMapping(user, feedId,
      PLACEHOLDER_TYPE_SITELINKS);
  FeedItem[] feedItems = GetFeedItems(user, feedId);

  if (feedItems != null) {
    foreach (FeedItem feedItem in feedItems) {
      SiteLinkFromFeed sitelinkFromFeed = new SiteLinkFromFeed() {
        FeedId = feedItem.feedId,
        FeedItemId = feedItem.feedItemId
      };
      foreach (FeedItemAttributeValue attributeValue in feedItem.attributeValues) {
        switch (attributeValue.feedAttributeId) {
          case SiteLinkFields.TEXT:
            sitelinkFromFeed.Text = attributeValue.stringValue;
            break;

          case SiteLinkFields.URL:
            sitelinkFromFeed.Url = attributeValue.stringValue;
            break;

          case SiteLinkFields.FINAL_URLS:
            sitelinkFromFeed.FinalUrls = attributeValue.stringValues;
            break;

          case SiteLinkFields.FINAL_MOBILE_URLS:
            sitelinkFromFeed.FinalMobileUrls = attributeValue.stringValues;
            break;

          case SiteLinkFields.TRACKING_URL_TEMPLATE:
            sitelinkFromFeed.TrackingUrlTemplate = attributeValue.stringValue;
            break;

          case SiteLinkFields.LINE2:
            sitelinkFromFeed.Line2 = attributeValue.stringValue;
            break;

          case SiteLinkFields.LINE3:
            sitelinkFromFeed.Text = attributeValue.stringValue;
            break;
        }
      }
      sitelinkFromFeed.Scheduling = feedItem.scheduling;
      siteLinks.Add(feedItem.feedItemId, sitelinkFromFeed);
    }
  }
  return siteLinks;
}

private Dictionary<long, long> GetFeedMapping(AdWordsUser user, long feedId,
    long placeHolderType) {
  FeedMappingService feedMappingService = (FeedMappingService) user.GetService(
      AdWordsService.v201705.FeedMappingService);
  FeedMappingPage page = feedMappingService.query(string.Format(
      "SELECT FeedMappingId,AttributeFieldMappings where FeedId='{0}' " +
      "and PlaceholderType={1} and Status='ENABLED'",
      feedId, placeHolderType));

  Dictionary<long, long> attributeMappings = new Dictionary<long, long>();

  if (page.entries != null) {
    foreach (FeedMapping feedMapping in page.entries) {
      foreach (AttributeFieldMapping attributeMapping in
          feedMapping.attributeFieldMappings) {
        attributeMappings.Add(attributeMapping.feedAttributeId,
            attributeMapping.fieldId);
      }
    }
  }
  return attributeMappings;
}

找出您要保留的 Feed 项

找出与某个广告系列相关联的 Feed 项列表,方法是获取与该广告系列相关联的 CampaignFeed,然后对其 matchingFunction 进行解析。您可以利用匹配函数撰写通用的表达式树,但撰写适用于通用情景的解析器较为复杂,因此本指南不会对此进行说明。我们将挑选最简单的情景,在此情景中来自一个 Feed 的多个 Feed 项已与某个广告系列相关联。此匹配函数的格式如下:

FEEDITEM_ID IN (FEEDITEM_ID_1, FEEDITEM_ID_2…)

private CampaignFeed[] GetCampaignFeeds(AdWordsUser user, Feed feed, int placeholderType) {
  CampaignFeedService campaignFeedService = (CampaignFeedService) user.GetService(
      AdWordsService.v201705.CampaignFeedService);

  CampaignFeedPage page = campaignFeedService.query(string.Format(
      "SELECT CampaignId, MatchingFunction, PlaceholderTypes where Status='ENABLED' " +
      "and FeedId = '{0}' and PlaceholderTypes CONTAINS_ANY[{1}]", feed.id, placeholderType));
  return page.entries;
}

private List<long> GetFeedItemsForCampaign(CampaignFeed campaignFeed) {
  List<long> feedItems = new List<long>();
  if (campaignFeed.matchingFunction.lhsOperand.Length == 1 &&
      campaignFeed.matchingFunction.lhsOperand[0] is RequestContextOperand &&
      (campaignFeed.matchingFunction.lhsOperand[0] as
           RequestContextOperand).contextType ==
           RequestContextOperandContextType.FEED_ITEM_ID &&
      campaignFeed.matchingFunction.@operator == FunctionOperator.IN) {
    foreach (ConstantOperand argument in campaignFeed.matchingFunction.rhsOperand) {
      feedItems.Add(argument.longValue);
    }
  }
  return feedItems;
}

删除现有的 CampaignFeed

在为广告系列添加附加信息设置时,您必须删除广告系列现有的 CampaignFeed。之所以这么要求,是因为在一个广告系列中 AdWords 仅支持为每种附加信息类型创建一个 CampaignFeed。删除您手动创建的 CampaignFeed 后,CampaignExtensionSettingService 就能在您添加附加信息设置时新建由系统管理的 CampaignFeed

private CampaignFeed DeleteCampaignFeed(AdWordsUser user, CampaignFeed campaignFeed) {
  CampaignFeedService campaignFeedService = (CampaignFeedService) user.GetService(
      AdWordsService.v201705.CampaignFeedService);

  CampaignFeedOperation operation = new CampaignFeedOperation() {
    operand = campaignFeed,
    @operator = Operator.REMOVE,
  };

  return campaignFeedService.mutate(
       new CampaignFeedOperation[] { operation }).value[0];
}

添加附加信息设置

现在,您可以创建与原有的 Feed 项相对应的附加信息设置:

private static void CreateExtensionSetting(AdWordsUser user,
    Dictionary<long, SiteLinkFromFeed> feedItems, CampaignFeed campaignFeed,
    List<long> feedItemIds) {
  CampaignExtensionSetting extensionSetting = new CampaignExtensionSetting() {
    campaignId = campaignFeed.campaignId,
    extensionType = FeedType.SITELINK,
    extensionSetting = new ExtensionSetting() {
    }
  };

  List<ExtensionFeedItem> extensionFeedItems = new List<ExtensionFeedItem>();

  foreach (long feedItemId in feedItemIds) {
    SiteLinkFromFeed feedItem = feedItems[feedItemId];
    SitelinkFeedItem newFeedItem = new SitelinkFeedItem() {
      sitelinkText = feedItem.Text,
      sitelinkUrl = feedItem.Url,
      sitelinkFinalUrls = feedItem.FinalUrls,
      sitelinkFinalMobileUrls = feedItem.FinalMobileUrls,
      sitelinkTrackingUrlTemplate = feedItem.TrackingUrlTemplate,
      sitelinkLine2 = feedItem.Line2,
      sitelinkLine3 = feedItem.Line3,
      scheduling = feedItem.Scheduling
    };
    extensionFeedItems.Add(newFeedItem);
  }
  extensionSetting.extensionSetting.extensions = extensionFeedItems.ToArray();

  CampaignExtensionSettingService campaignExtensionSettingService =
      (CampaignExtensionSettingService) user.GetService(
          AdWordsService.v201705.CampaignExtensionSettingService);
  CampaignExtensionSettingOperation operation =
      new CampaignExtensionSettingOperation() {
        operand = extensionSetting,
        @operator = Operator.ADD
      };

  campaignExtensionSettingService.mutate(
      new CampaignExtensionSettingOperation[] {operation});
  return;
}

请注意,此流程并不会删除重复的附加信息设置;您可以强化此代码以排除重复项。

删除原有的 FeedItem

最后,删除原有的 FeedItems

private void DeleteOldFeedItems(AdWordsUser user, List<long> feedItemIds,
    long feedId) {
  if (feedItemIds.Count == 0) {
    return;
  }
  List<FeedItemOperation> operations = new List<FeedItemOperation>();
  foreach (long feedItemId in feedItemIds) {
    FeedItemOperation operation = new FeedItemOperation() {
      @operator = Operator.REMOVE,
      operand = new FeedItem() {
        feedItemId = feedItemId,
        feedId = feedId
      }
    };
    operations.Add(operation);
  }
  FeedItemService feedItemService = (FeedItemService) user.GetService(
      AdWordsService.v201705.FeedItemService);
  feedItemService.mutate(operations.ToArray());
  return;
}

此步骤是可选的,不过我们建议删除未使用的 Feed 项,使有效 Feed 项的数量不会超出系统限制

融会贯通:主要循环

以下程序的主要循环与前文讨论的步骤顺序相对应:

Feed[] feeds = GetFeeds(user);
foreach (Feed feed in feeds) {
  Dictionary<long, SiteLinkFromFeed> feedItems = GetSiteLinksFromFeed(user, feed.id);
  CampaignFeed[] campaignFeeds = GetCampaignFeeds(user, feed,
      PLACEHOLDER_TYPE_SITELINKS);

  if (campaignFeeds != null) {
    HashSet<long> allFeedItemsToDelete = new HashSet<long>();
    foreach (CampaignFeed campaignFeed in campaignFeeds) {
      // Optional: Replace with custom logic that upgrades only selected
      // feed items.
      List<long> feedItemIds = GetFeedItemsForCampaign(campaignFeed);
      DeleteCampaignFeed(user, campaignFeed);
      CreateExtensionSetting(user, feedItems, campaignFeed, feedItemIds);
      allFeedItemsToDelete.UnionWith(feedItemIds);
    }
    DeleteOldFeedItems(user, new List<long>(allFeedItemsToDelete), feed.id);
  }
}

代码示例

请参阅我们客户端库中的以下代码示例,了解有关附加信息设置服务的详细信息。

发送以下问题的反馈:

此网页
AdWords API
AdWords API
需要帮助?请访问我们的支持页面