Using extension setting services
As an example, suppose you're advertising a restaurant in Google Ads and want to add some extra information to its Google Ads campaign:
- Store hours: This link takes users to http://www.example.com/storehours.
- Nutrition data: This link takes users to http://www.example.com/menu/nutritiondata, where nutritional information about menu items is listed.
- Happy hours: This link takes users to http://www.example.com/happyhours, and should only be shown during these hours: 6pm to 9pm, Monday through Friday; and 5pm to 8pm on Saturday.
- Thanksgiving special: You plan to have a special Thanksgiving menu from November 27 to 28. This link should be displayed only from November 20 to 27 so users can make their reservation at http://www.example.com/thanksgiving.
Each of the items above is an ad extension in AdWords. You can manage extensions using the extension setting services in the AdWords API.
Adding ad extensions
Ad extensions can be added at the account, campaign, or ad group level, though not
all extension types are available at all levels. For new ad extensions, use
either the ADD
or SET
operator. If the SET
operator is used in a case
where an ad extension does not exist, a new ad extension is added. Ad
extensions come in several formats.
Sitelink extensions
You can use sitelinks to link to specific subpages within your site, aside from your main landing page, making your site easier to navigate for users.
The following code snippet shows how to add new ad extensions to a campaign using CampaignExtensionSettingService.
Java
/** * Runs the example. * * @param adWordsServices the services factory. * @param session the session. * @param campaignId the ID of the campaign where sitelinks will be added. * @throws ApiException if the API request failed with one or more service errors. * @throws RemoteException if the API request failed due to other errors. */ public static void runExample(AdWordsServicesInterface adWordsServices, AdWordsSession session, Long campaignId) throws ApiException, RemoteException { // Get the CustomerService. CustomerServiceInterface customerService = adWordsServices.get(session, CustomerServiceInterface.class); // Find the matching customer and its time zone. The getCustomers method will return // a single Customer object corresponding to the session's clientCustomerId. Customer customer = customerService.getCustomers()[0]; DateTimeZone customerTimeZone = DateTimeZone.forID(customer.getDateTimeZone()); System.out.printf( "Found customer ID %d with time zone '%s'.%n", customer.getCustomerId(), customer.getDateTimeZone()); // Get the CampaignExtensionSettingService. CampaignExtensionSettingServiceInterface campaignExtensionSettingService = adWordsServices.get(session, CampaignExtensionSettingServiceInterface.class); // Create the sitelinks. SitelinkFeedItem sitelink1 = createSiteLinkFeedItem("Store Hours", "http://www.example.com/storehours"); // Show the Thanksgiving specials link only from 20 - 27 Nov. SitelinkFeedItem sitelink2 = createSiteLinkFeedItem("Thanksgiving Specials", "http://www.example.com/thanksgiving"); // The time zone of the start and end date/times must match the time zone of the customer. DateTime startTime = new DateTime(DateTime.now().getYear(), 11, 20, 0, 0, 0, customerTimeZone); if (startTime.isBeforeNow()) { // Move the startTime to next year if the current date is past November 20th. startTime = startTime.plusYears(1); } sitelink2.setStartTime(startTime.toString("yyyyMMdd HHmmss ZZZ")); // Use the same year as startTime when creating endTime. DateTime endTime = new DateTime(startTime.getYear(), 11, 27, 23, 59, 59, customerTimeZone); sitelink2.setEndTime(endTime.toString("yyyyMMdd HHmmss ZZZ")); // Target this sitelink for United States only. See // https://developers.google.com/adwords/api/docs/appendix/geotargeting // for valid geolocation codes. Location unitedStates = new Location(); unitedStates.setId(2840L); sitelink2.setGeoTargeting(unitedStates); // Restrict targeting only to people physically within the United States. // Otherwise, this could also show to people interested in the United States // but not physically located there. FeedItemGeoRestriction geoTargetingRestriction = new FeedItemGeoRestriction(); geoTargetingRestriction.setGeoRestriction(GeoRestriction.LOCATION_OF_PRESENCE); sitelink2.setGeoTargetingRestriction(geoTargetingRestriction); // Show the wifi details primarily for high end mobile users. SitelinkFeedItem sitelink3 = createSiteLinkFeedItem("Wifi available", "http://www.example.com/mobile/wifi"); // See https://developers.google.com/adwords/api/docs/appendix/platforms for device criteria // IDs. FeedItemDevicePreference devicePreference = new FeedItemDevicePreference(30001L); sitelink3.setDevicePreference(devicePreference); // Target this sitelink for the keyword "free wifi". Keyword wifiKeyword = new Keyword(); wifiKeyword.setText("free wifi"); wifiKeyword.setMatchType(KeywordMatchType.BROAD); sitelink3.setKeywordTargeting(wifiKeyword); // Show the happy hours link only during Mon - Fri 6PM to 9PM. SitelinkFeedItem sitelink4 = createSiteLinkFeedItem("Happy hours", "http://www.example.com/happyhours"); sitelink4.setScheduling(new FeedItemScheduling(new FeedItemSchedule[] { new FeedItemSchedule(DayOfWeek.MONDAY, 18, MinuteOfHour.ZERO, 21, MinuteOfHour.ZERO), new FeedItemSchedule(DayOfWeek.TUESDAY, 18, MinuteOfHour.ZERO, 21, MinuteOfHour.ZERO), new FeedItemSchedule(DayOfWeek.WEDNESDAY, 18, MinuteOfHour.ZERO, 21, MinuteOfHour.ZERO), new FeedItemSchedule(DayOfWeek.THURSDAY, 18, MinuteOfHour.ZERO, 21, MinuteOfHour.ZERO), new FeedItemSchedule(DayOfWeek.FRIDAY, 18, MinuteOfHour.ZERO, 21, MinuteOfHour.ZERO)})); // Create your campaign extension settings. This associates the sitelinks // to your campaign. CampaignExtensionSetting campaignExtensionSetting = new CampaignExtensionSetting(); campaignExtensionSetting.setCampaignId(campaignId); campaignExtensionSetting.setExtensionType(FeedType.SITELINK); ExtensionSetting extensionSetting = new ExtensionSetting(); extensionSetting.setExtensions( new ExtensionFeedItem[] {sitelink1, sitelink2, sitelink3, sitelink4}); campaignExtensionSetting.setExtensionSetting(extensionSetting); CampaignExtensionSettingOperation operation = new CampaignExtensionSettingOperation(); operation.setOperand(campaignExtensionSetting); operation.setOperator(Operator.ADD); // Add the extensions. CampaignExtensionSettingReturnValue returnValue = campaignExtensionSettingService.mutate(new CampaignExtensionSettingOperation[] {operation}); if (returnValue.getValue() != null && returnValue.getValue().length > 0) { CampaignExtensionSetting newExtensionSetting = returnValue.getValue(0); System.out.printf("Extension setting with type '%s' was added to campaign ID %d.%n", newExtensionSetting.getExtensionType().getValue(), newExtensionSetting.getCampaignId()); } else { System.out.println("No extension settings were created."); } } /** * Creates a new {@link SitelinkFeedItem} with the specified attributes. * * @param sitelinkText the text for the sitelink * @param sitelinkUrl the URL for the sitelink * @return a new SitelinkFeedItem */ private static SitelinkFeedItem createSiteLinkFeedItem(String sitelinkText, String sitelinkUrl) { SitelinkFeedItem sitelinkFeedItem = new SitelinkFeedItem(); sitelinkFeedItem.setSitelinkText(sitelinkText); sitelinkFeedItem.setSitelinkFinalUrls(new UrlList(new String[] {sitelinkUrl})); return sitelinkFeedItem; }
C#
using (CampaignExtensionSettingService campaignExtensionSettingService = (CampaignExtensionSettingService) user.GetService(AdWordsService.v201809 .CampaignExtensionSettingService)) { Customer customer = null; using (CustomerService customerService = (CustomerService) user.GetService(AdWordsService.v201809.CustomerService)) { // Find the matching customer and its time zone. The getCustomers method // will return a single Customer object corresponding to the session's // clientCustomerId. customer = customerService.getCustomers()[0]; Console.WriteLine("Found customer ID {0:###-###-####} with time zone '{1}'.", customer.customerId, customer.dateTimeZone); } List<ExtensionFeedItem> extensions = new List<ExtensionFeedItem>(); // Create your sitelinks. SitelinkFeedItem sitelink1 = new SitelinkFeedItem() { sitelinkText = "Store Hours", sitelinkFinalUrls = new UrlList() { urls = new string[] { "http://www.example.com/storehours" } } }; extensions.Add(sitelink1); DateTime startOfThanksGiving = new DateTime(DateTime.Now.Year, 11, 20, 0, 0, 0); DateTime endOfThanksGiving = new DateTime(DateTime.Now.Year, 11, 27, 23, 59, 59); // Add check to make sure we don't create a sitelink with end date in the // past. if (DateTime.Now < endOfThanksGiving) { // Show the Thanksgiving specials link only from 20 - 27 Nov. SitelinkFeedItem sitelink2 = new SitelinkFeedItem() { sitelinkText = "Thanksgiving Specials", sitelinkFinalUrls = new UrlList() { urls = new string[] { "http://www.example.com/thanksgiving" } }, startTime = string.Format("{0} {1}", startOfThanksGiving.ToString("yyyyMMdd HHmmss"), customer.dateTimeZone), endTime = string.Format("{0} {1}", endOfThanksGiving.ToString("yyyyMMdd HHmmss"), customer.dateTimeZone), // 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 }, // Restrict targeting only to people physically within the United States. // Otherwise, this could also show to people interested in the United States // but not physically located there. geoTargetingRestriction = new FeedItemGeoRestriction() { geoRestriction = GeoRestriction.LOCATION_OF_PRESENCE } }; extensions.Add(sitelink2); } // Show the wifi details primarily for high end mobile users. SitelinkFeedItem sitelink3 = new SitelinkFeedItem() { sitelinkText = "Wifi available", sitelinkFinalUrls = new UrlList() { urls = new string[] { "http://www.example.com/mobile/wifi" } }, devicePreference = new FeedItemDevicePreference() { // See https://developers.google.com/adwords/api/docs/appendix/platforms // for device criteria IDs. devicePreference = 30001 }, // Target this sitelink for the keyword "free wifi". keywordTargeting = new Keyword() { text = "free wifi", matchType = KeywordMatchType.BROAD } }; extensions.Add(sitelink3); // Show the happy hours link only during Mon - Fri 6PM to 9PM. SitelinkFeedItem sitelink4 = new SitelinkFeedItem() { sitelinkText = "Happy hours", sitelinkFinalUrls = new UrlList() { urls = new string[] { "http://www.example.com/happyhours" }, }, scheduling = new FeedItemSchedule[] { new FeedItemSchedule() { dayOfWeek = DayOfWeek.MONDAY, startHour = 18, startMinute = MinuteOfHour.ZERO, endHour = 21, endMinute = MinuteOfHour.ZERO }, new FeedItemSchedule() { dayOfWeek = DayOfWeek.TUESDAY, startHour = 18, startMinute = MinuteOfHour.ZERO, endHour = 21, endMinute = MinuteOfHour.ZERO }, new FeedItemSchedule() { dayOfWeek = DayOfWeek.WEDNESDAY, startHour = 18, startMinute = MinuteOfHour.ZERO, endHour = 21, endMinute = MinuteOfHour.ZERO }, new FeedItemSchedule() { dayOfWeek = DayOfWeek.THURSDAY, startHour = 18, startMinute = MinuteOfHour.ZERO, endHour = 21, endMinute = MinuteOfHour.ZERO }, new FeedItemSchedule() { dayOfWeek = DayOfWeek.FRIDAY, startHour = 18, startMinute = MinuteOfHour.ZERO, endHour = 21, endMinute = MinuteOfHour.ZERO } } }; extensions.Add(sitelink4); // Create your campaign extension settings. This associates the sitelinks // to your campaign. CampaignExtensionSetting campaignExtensionSetting = new CampaignExtensionSetting { campaignId = campaignId, extensionType = FeedType.SITELINK, extensionSetting = new ExtensionSetting() { extensions = extensions.ToArray() } }; CampaignExtensionSettingOperation operation = new CampaignExtensionSettingOperation() { operand = campaignExtensionSetting, @operator = Operator.ADD }; try { // Add the extensions. CampaignExtensionSettingReturnValue retVal = campaignExtensionSettingService.mutate( new CampaignExtensionSettingOperation[] { operation }); // Display the results. if (retVal.value != null && retVal.value.Length > 0) { CampaignExtensionSetting newExtensionSetting = retVal.value[0]; Console.WriteLine( "Extension setting with type = {0} was added to campaign ID {1}.", newExtensionSetting.extensionType, newExtensionSetting.campaignId); } else { Console.WriteLine("No extension settings were created."); } } catch (Exception e) { throw new System.ApplicationException("Failed to create extension settings.", e); } }
Python
# Initialize appropriate services. campaign_extension_setting_service = client.GetService( 'CampaignExtensionSettingService', version='v201809') customer_service = client.GetService('CustomerService', version='v201809') # Find the matching customer and its time zone. The getCustomers method will # return a single Customer object corresponding to the configured # clientCustomerId. customer = customer_service.getCustomers()[0] customer_tz = timezone(customer['dateTimeZone']) time_fmt = '%s %s' % ('%Y%m%d %H%M%S', customer_tz) print('Found customer ID %d with time zone "%s".' % (customer['customerId'], customer['dateTimeZone'])) # Create the sitelinks sitelink1 = { 'xsi_type': 'SitelinkFeedItem', 'sitelinkText': 'Store Hours', 'sitelinkFinalUrls': {'urls': ['http://www.example.com/storehours']} } # Show the Thanksgiving specials link only from 20 - 27 Nov. sitelink2 = { 'xsi_type': 'SitelinkFeedItem', 'sitelinkText': 'Thanksgiving Specials', 'sitelinkFinalUrls': {'urls': ['http://www.example.com/thanksgiving']}, # The time zone of the start and end date/times must match the time zone # of the customer. 'startTime': datetime(datetime.now().year, 11, 20, 0, 0, 0, 0, customer_tz).strftime(time_fmt), 'endTime': datetime(datetime.now().year, 11, 27, 23, 59, 59, 59, customer_tz).strftime(time_fmt), # Target this sitelink for United States only. For valid geolocation # codes, see: # https://developers.google.com/adwords/api/docs/appendix/geotargeting 'geoTargeting': {'id': 2840}, # Restrict targeting only to people physically within the United States. # Otherwise, this could also show to people interested in the United # States, but not physically located there. 'geoTargetingRestriction': { 'geoRestriction': 'LOCATION_OF_PRESENCE' } } # Show the wifi details primarily for high end mobile users. sitelink3 = { 'xsi_type': 'SitelinkFeedItem', 'sitelinkText': 'Wifi Available', 'sitelinkFinalUrls': {'urls': ['http://www.example.com/mobile/wifi']}, # See https://developers.google.com/adwords/api/docs/appendix/platforms # for device criteria IDs. 'devicePreference': {'devicePreference': '30001'}, # Target this sitelink only when the ad is triggered by the keyword # "free wifi." 'keywordTargeting': { 'text': 'free wifi', 'matchType': 'BROAD' } } # Show the happy hours link only during Mon - Fri 6PM to 9PM. sitelink4 = { 'xsi_type': 'SitelinkFeedItem', 'sitelinkText': 'Happy hours', 'sitelinkFinalUrls': {'urls': ['http://www.example.com/happyhours']}, 'scheduling': { 'feedItemSchedules': [ { 'dayOfWeek': day, 'startHour': '18', 'startMinute': 'ZERO', 'endHour': '21', 'endMinute': 'ZERO' } for day in ['MONDAY', 'TUESDAY', 'WEDNESDAY', 'THURSDAY', 'FRIDAY'] ] } } # Create your Campaign Extension Settings. This associates the sitelinks # to your campaign. campaign_extension_setting = { 'campaignId': campaign_id, 'extensionType': 'SITELINK', 'extensionSetting': { 'extensions': [sitelink1, sitelink2, sitelink3, sitelink4] } } operation = { 'operator': 'ADD', 'operand': campaign_extension_setting } # Add the extensions. response = campaign_extension_setting_service.mutate([operation]) if 'value' in response: print('Extension setting with type "%s" was added to campaignId "%d".' % (response['value'][0]['extensionType'], response['value'][0]['campaignId'])) else: raise errors.GoogleAdsError('No extension settings were added.')
PHP
$campaignExtensionSettingService = $adWordsServices->get($session, CampaignExtensionSettingService::class); $customerService = $adWordsServices->get($session, CustomerService::class); // Find the matching customer and its time zone. The getCustomers method // will return a single Customer object corresponding to the user's // clientCustomerId. $customers = $customerService->getCustomers(); $customer = $customers[0]; printf( "Found customer ID %d with time zone %s.\n", $customer->getCustomerId(), $customer->getDateTimeZone() ); $sitelinks = []; // Create a simple sitelink. $sitelink1 = new SitelinkFeedItem(); $sitelink1->setSitelinkText('Store Hours'); $sitelink1->setSitelinkFinalUrls( new UrlList(['http://www.example.com/storehours']) ); $sitelinks[] = $sitelink1; // This one to show the Thanksgiving specials link only from 20 - 27 Nov. $sitelink2 = new SitelinkFeedItem(); $sitelink2->setSitelinkText('Thanksgiving Specials'); $sitelink2->setSitelinkFinalUrls( new UrlList(['http://www.example.com/thanksgiving']) ); $sitelink2->setStartTime( date('Y') . '1120 000000 ' . $customer->getDateTimeZone() ); $sitelink2->setEndTime( date('Y') . '1127 235959 ' . $customer->getDateTimeZone() ); // Target this sitelink for United States only. See // https://developers.google.com/adwords/api/docs/appendix/geotargeting // for valid geolocation codes. $location = new Location(); $location->setId(2840); $sitelink2->setGeoTargeting($location); // Restrict targeting only to people physically within the United States. // Otherwise, this could also show to people interested in the United States // but not physically located there. $sitelink2->setGeoTargetingRestriction( new FeedItemGeoRestriction(GeoRestriction::LOCATION_OF_PRESENCE) ); $sitelinks[] = $sitelink2; // Sitelink targetted on high end mobile. $sitelink3 = new SitelinkFeedItem(); $sitelink3->setSitelinkText('Wifi available'); $sitelink3->setSitelinkFinalUrls( new UrlList(['http://www.example.com/mobile/wifi']) ); $sitelink3->setDevicePreference(new FeedItemDevicePreference(30001)); // Target this sitelink only when the ad is triggered by the keyword // "free wifi". $keyword = new Keyword(); $keyword->setText('free wifi'); $keyword->setMatchType(KeywordMatchType::BROAD); $sitelink3->setKeywordTargeting($keyword); $sitelinks[] = $sitelink3; // Show the happy hours link only during Mon - Fri 6PM to 9PM. $sitelink4 = new SitelinkFeedItem(); $sitelink4->setSitelinkText('Happy Hours Now!'); $sitelink4->setSitelinkFinalUrls( new UrlList(['http://www.example.com/happyhours']) ); $sitelink4->setScheduling( new FeedItemScheduling( [ new FeedItemSchedule('MONDAY', 18, 'ZERO', 21, 'ZERO'), new FeedItemSchedule('TUESDAY', 18, 'ZERO', 21, 'ZERO'), new FeedItemSchedule('WEDNESDAY', 18, 'ZERO', 21, 'ZERO'), new FeedItemSchedule('THURSDAY', 18, 'ZERO', 21, 'ZERO'), new FeedItemSchedule('FRIDAY', 18, 'ZERO', 21, 'ZERO') ] ) ); $sitelinks[] = $sitelink4; // Create your campaign extension settings. This associates the sitelinks // to your campaign. $campaignExtensionSetting = new CampaignExtensionSetting(); $campaignExtensionSetting->setCampaignId($campaignId); $campaignExtensionSetting->setExtensionType(FeedType::SITELINK); $campaignExtensionSetting->setExtensionSetting(new ExtensionSetting()); $campaignExtensionSetting->getExtensionSetting()->setExtensions($sitelinks); // Create a campaign extension setting operation and add it to the list. $operation = new CampaignExtensionSettingOperation(); $operation->setOperator(Operator::ADD); $operation->setOperand($campaignExtensionSetting); $operations = [$operation]; // Add the sitelinks on the server. $result = $campaignExtensionSettingService->mutate($operations); // Print out some information about the added extension setting. $newExtensionSetting = $result->getValue()[0]; printf( "Extension setting with type '%s' was added to campaign ID %d\n", $newExtensionSetting->getExtensionType(), $newExtensionSetting->getCampaignId() );
Perl
my ($client, $campaign_id) = @_; my $customer = $client->CustomerService()->getCustomers()->[0]; my $customer_time_zone = $customer->get_dateTimeZone(); printf( "Found customer ID %d with time zone %s.\n", $customer->get_customerId(), $customer_time_zone ); # Create the site links. my $site_link_1 = Google::Ads::AdWords::v201809::SitelinkFeedItem->new({ sitelinkText => 'Store Hours', sitelinkFinalUrls => Google::Ads::AdWords::v201809::UrlList->new( {urls => ['http://www.example.com/storehours']})}); # Set the startTime and endTime to show the Thanksgiving specials link only # from 20 - 27 Nov. my $site_link_2 = Google::Ads::AdWords::v201809::SitelinkFeedItem->new({ sitelinkText => 'Thanksgiving Specials', sitelinkFinalUrls => Google::Ads::AdWords::v201809::UrlList->new( {urls => ['http://www.example.com/thanksgiving']})}); # The time zone of the start and end date/times must match the time zone of # the customer. my ($sec, $min, $hour, $mday, $mon, $year) = localtime(time - (60 * 60 * 24)); my $start_time = sprintf("%d1120 000000 %s", ($year + 1900), $customer_time_zone); my $end_time = sprintf("%d1127 235959 %s", ($year + 1900), $customer_time_zone); $site_link_2->set_startTime($start_time); $site_link_2->set_endTime($end_time); # Target this sitelink for United States only. See # https://developers.google.com/adwords/api/docs/appendix/geotargeting # for valid geolocation codes. my $location = Google::Ads::AdWords::v201809::Location->new({ id => 2840 # United States }); $site_link_2->set_geoTargeting($location); # Restrict targeting only to people physically within the United States. # Otherwise, this could also show to people interested in the United States # but not physically located there. my $geo_targeting_restriction = Google::Ads::AdWords::v201809::FeedItemGeoRestriction->new({ geoRestriction => "LOCATION_OF_PRESENCE" }); $site_link_2->set_geoTargetingRestriction($geo_targeting_restriction); # Set the devicePreference to show the wifi details primarily for high end # mobile users. # Target this sitelink for the keyword "free wifi". my $keyword = Google::Ads::AdWords::v201809::Keyword->new({ text => "free wifi", matchType => "BROAD" }); my $site_link_3 = Google::Ads::AdWords::v201809::SitelinkFeedItem->new({ sitelinkText => 'Wifi available', keywordTargeting => $keyword, sitelinkFinalUrls => Google::Ads::AdWords::v201809::UrlList->new( {urls => ['http://www.example.com/mobile/wifi']} ), devicePreference => Google::Ads::AdWords::v201809::FeedItemDevicePreference->new({ # See https://developers.google.com/adwords/api/docs/appendix/platforms # for device criteria IDs. devicePreference => '30001' })}); # Set the feedItemSchedules to show the happy hours link only during Mon - Fri # 6PM to 9PM. my $site_link_4 = Google::Ads::AdWords::v201809::SitelinkFeedItem->new({ sitelinkText => 'Happy hours', sitelinkFinalUrls => Google::Ads::AdWords::v201809::UrlList->new( {urls => ['http://www.example.com/mobile/happyhours']} ), }); my @schedules = (); foreach my $day_name ('MONDAY', 'TUESDAY', 'WEDNESDAY', 'THURSDAY', 'FRIDAY') { push @schedules, Google::Ads::AdWords::v201809::FeedItemSchedule->new({ 'dayOfWeek' => $day_name, 'startHour' => 18, 'startMinute' => 'ZERO', 'endHour' => 21, 'endMinute' => 'ZERO', }); } $site_link_4->set_scheduling( Google::Ads::AdWords::v201809::FeedItemScheduling->new( {feedItemSchedules => \@schedules})); my $campaign_extension_setting = Google::Ads::AdWords::v201809::CampaignExtensionSetting->new({ campaignId => $campaign_id, extensionType => 'SITELINK', extensionSetting => Google::Ads::AdWords::v201809::ExtensionSetting->new({ extensions => [$site_link_1, $site_link_2, $site_link_3, $site_link_4] })}); my $mutate_result = $client->CampaignExtensionSettingService()->mutate({ operations => [ Google::Ads::AdWords::v201809::CampaignExtensionSettingOperation->new({ operand => $campaign_extension_setting, operator => 'ADD' })]}); my $added_extension_setting = $mutate_result->get_value(0); printf "Extension setting with type = %s was added to campaign ID %d.\n", $added_extension_setting->get_extensionType(), $added_extension_setting->get_campaignId();
Ruby
customer_srv = adwords.service(:CustomerService, API_VERSION) # Find the matching customer and its time zone. The get_customers method will # return a single customer corresponding to the configured client_customer_id. customer = customer_srv.get_customers().first customer_time_zone = customer[:date_time_zone] puts 'Found customer ID %d with time zone "%s"' % [customer[:customer_id], customer_time_zone] if customer_time_zone.nil? raise StandardError, 'Customer not found for customer ID: ' + customer_id end campaign_extension_setting_srv = adwords.service(:CampaignExtensionSettingService, API_VERSION) sitelink_1 = { :xsi_type => "SitelinkFeedItem", :sitelink_text => "Store Hours", :sitelink_final_urls => { :urls => ["http://www.example.com/storehours"] } } sitelink_2 = { :xsi_type => "SitelinkFeedItem", :sitelink_text => "Thanksgiving Specials", :sitelink_final_urls => { :urls => ["http://www.example.com/thanksgiving"] }, :start_time => DateTime.new(Date.today.year, 11, 20, 0, 0, 0). strftime("%Y%m%d %H%M%S ") + customer_time_zone, :end_time => DateTime.new(Date.today.year, 11, 27, 23, 59, 59). strftime("%Y%m%d %H%M%S ") + customer_time_zone, # Target this sitelink for United States only. See # https://developers.google.com/adwords/api/docs/appendix/geotargeting # for valid geolocation codes. :geo_targeting => { :id => 2840 }, # Restrict targeting only to people physically within the United States. # Otherwise, this could also show to people interested in the United States # but not physically located there. :geo_targeting_restriction => { :geo_restriction => 'LOCATION_OF_PRESENCE' } } sitelink_3 = { :xsi_type => "SitelinkFeedItem", :sitelink_text => "Wifi available", :sitelink_final_urls => { :urls => ["http://www.example.com/mobile/wifi"] }, :device_preference => {:device_preference => 30001}, # Target this sitelink only when the ad is triggered by the keyword # "free wifi". :keyword_targeting => { :text => "free wifi", :match_type => 'BROAD' } } sitelink_4 = { :xsi_type => "SitelinkFeedItem", :sitelink_text => "Happy hours", :sitelink_final_urls => { :urls => ["http://www.example.com/happyhours"] }, :scheduling => { :feed_item_schedules => [ { :day_of_week => 'MONDAY', :start_hour => 18, :start_minute => 'ZERO', :end_hour => 21, :end_minute => 'ZERO' }, { :day_of_week => 'TUESDAY', :start_hour => 18, :start_minute => 'ZERO', :end_hour => 21, :end_minute => 'ZERO' }, { :day_of_week => 'WEDNESDAY', :start_hour => 18, :start_minute => 'ZERO', :end_hour => 21, :end_minute => 'ZERO' }, { :day_of_week => 'THURSDAY', :start_hour => 18, :start_minute => 'ZERO', :end_hour => 21, :end_minute => 'ZERO' }, { :day_of_week => 'FRIDAY', :start_hour => 18, :start_minute => 'ZERO', :end_hour => 21, :end_minute => 'ZERO' } ] } } campaign_extension_setting = { :campaign_id => campaign_id, :extension_type => 'SITELINK', :extension_setting => { :extensions => [sitelink_1, sitelink_2, sitelink_3, sitelink_4] } } operation = { :operand => campaign_extension_setting, :operator => 'ADD' } response = campaign_extension_setting_srv.mutate([operation]) if response and response[:value] new_extension_setting = response[:value].first puts "Extension setting with type = %s was added to campaign ID %d" % [ new_extension_setting[:extension_type], new_extension_setting[:campaign_id] ] elsif puts "No extension settings were created." end
VB.NET
Using campaignExtensionSettingService As CampaignExtensionSettingService = DirectCast(user.GetService(AdWordsService.v201809.CampaignExtensionSettingService), CampaignExtensionSettingService) Dim customerService As CustomerService = DirectCast(user.GetService(AdWordsService.v201809.CustomerService), CustomerService) ' Find the matching customer and its time zone. The getCustomers method ' will return a single Customer object corresponding to the session's ' clientCustomerId. Dim customer As Customer = customerService.getCustomers()(0) Console.WriteLine("Found customer ID {0:###-###-####} with time zone '{1}'.", customer.customerId, customer.dateTimeZone) Dim extensions As New List(Of ExtensionFeedItem) ' Create your sitelinks. Dim sitelink1 As New SitelinkFeedItem() sitelink1.sitelinkText = "Store Hours" sitelink1.sitelinkFinalUrls = New UrlList() sitelink1.sitelinkFinalUrls.urls = New String() _ {"http://www.example.com/storehours"} extensions.Add(sitelink1) Dim startOfThanksGiving As New DateTime(DateTime.Now.Year, 11, 20, 0, 0, 0) Dim endOfThanksGiving As New DateTime(DateTime.Now.Year, 11, 27, 23, 59, 59) ' Add check to make sure we don't create a sitelink with end date in the ' past. If DateTime.Now < endOfThanksGiving Then ' Show the Thanksgiving specials link only from 20 - 27 Nov. Dim sitelink2 As New SitelinkFeedItem() sitelink2.sitelinkText = "Thanksgiving Specials" sitelink2.sitelinkFinalUrls = New UrlList() sitelink2.sitelinkFinalUrls.urls = New String() _ {"http://www.example.com/thanksgiving"} sitelink2.startTime = String.Format("{0}1120 000000 {1}", DateTime.Now.Year, customer.dateTimeZone) sitelink2.endTime = String.Format("{0}1127 235959 {1}", DateTime.Now.Year, customer.dateTimeZone) ' Target this sitelink for United States only. See ' https://developers.google.com/adwords/api/docs/appendix/geotargeting ' for valid geolocation codes. sitelink2.geoTargeting = New Location() sitelink2.geoTargeting.id = 2840 ' Restrict targeting only to people physically within the United States. ' Otherwise, this could also show to people interested in the United States ' but not physically located there. Dim geoTargetingRestriction As New FeedItemGeoRestriction() geoTargetingRestriction.geoRestriction = GeoRestriction.LOCATION_OF_PRESENCE sitelink2.geoTargetingRestriction = geoTargetingRestriction extensions.Add(sitelink2) End If ' Show the wifi details primarily for high end mobile users. Dim sitelink3 As New SitelinkFeedItem() sitelink3.sitelinkText = "Wifi available" sitelink3.sitelinkFinalUrls = New UrlList() sitelink3.sitelinkFinalUrls.urls = New String() _ {"http://www.example.com/mobile/wifi"} sitelink3.devicePreference = New FeedItemDevicePreference() sitelink3.devicePreference.devicePreference = 30001 extensions.Add(sitelink3) ' Show the happy hours link only during Mon - Fri 6PM to 9PM. Dim sitelink4 As New SitelinkFeedItem() sitelink4.sitelinkText = "Happy hours" sitelink4.sitelinkFinalUrls = New UrlList() sitelink4.sitelinkFinalUrls.urls = New String() _ {"http://www.example.com/happyhours"} extensions.Add(sitelink4) Dim schedule1 As New FeedItemSchedule() schedule1.dayOfWeek = DayOfWeek.MONDAY schedule1.startHour = 18 schedule1.startMinute = MinuteOfHour.ZERO schedule1.endHour = 21 schedule1.endMinute = MinuteOfHour.ZERO Dim schedule2 As New FeedItemSchedule() schedule2.dayOfWeek = DayOfWeek.TUESDAY schedule2.startHour = 18 schedule2.startMinute = MinuteOfHour.ZERO schedule2.endHour = 21 schedule2.endMinute = MinuteOfHour.ZERO Dim schedule3 As New FeedItemSchedule() schedule3.dayOfWeek = DayOfWeek.WEDNESDAY schedule3.startHour = 18 schedule3.startMinute = MinuteOfHour.ZERO schedule3.endHour = 21 schedule3.endMinute = MinuteOfHour.ZERO Dim schedule4 As New FeedItemSchedule() schedule4.dayOfWeek = DayOfWeek.THURSDAY schedule4.startHour = 18 schedule4.startMinute = MinuteOfHour.ZERO schedule4.endHour = 21 schedule4.endMinute = MinuteOfHour.ZERO Dim schedule5 As New FeedItemSchedule() schedule5.dayOfWeek = DayOfWeek.FRIDAY schedule5.startHour = 18 schedule5.startMinute = MinuteOfHour.ZERO schedule5.endHour = 21 schedule5.endMinute = MinuteOfHour.ZERO sitelink4.scheduling = New FeedItemSchedule() { _ schedule1, schedule2, schedule3, schedule4, schedule5 } ' Create your campaign extension settings. This associates the sitelinks ' to your campaign. Dim campaignExtensionSetting As New CampaignExtensionSetting() campaignExtensionSetting.campaignId = campaignId campaignExtensionSetting.extensionType = FeedType.SITELINK campaignExtensionSetting.extensionSetting = New ExtensionSetting() campaignExtensionSetting.extensionSetting.extensions = extensions.ToArray Dim extensionOperation As New CampaignExtensionSettingOperation() extensionOperation.operand = campaignExtensionSetting extensionOperation.operator = [Operator].ADD Try ' Add the extensions. Dim retVal As CampaignExtensionSettingReturnValue = campaignExtensionSettingService.mutate( New CampaignExtensionSettingOperation() _ {extensionOperation}) ' Display the results. If Not (retVal.value Is Nothing) AndAlso retVal.value.Length > 0 Then Dim newExtensionSetting As CampaignExtensionSetting = retVal.value(0) Console.WriteLine( "Extension setting with type = {0} was added to campaign ID {1}.", newExtensionSetting.extensionType, newExtensionSetting.campaignId) Else Console.WriteLine("No extension settings were created.") End If Catch e As Exception Throw New System.ApplicationException("Failed to create extension settings.", e) End Try End Using
Call extensions
You can list a business phone number alongside your ads that customers can
call directly from the ad, using a CallFeedItem
extension. The following code
snippet shows how to do this:
Java
CallFeedItem callFeedItem = new CallFeedItem(); callFeedItem.setCallCountryCode("US"); callFeedItem.setCallPhoneNumber("212-565-0000"); CampaignExtensionSetting campaignExtensionSetting = new CampaignExtensionSetting(); campaignExtensionSetting.setCampaignId(campaignId); campaignExtensionSetting.setExtensionType(FeedType.CALL); ExtensionSetting extensionSetting = new ExtensionSetting(); extensionSetting.setExtensions(new ExtensionFeedItem[] {callFeedItem}); campaignExtensionSetting.setExtensionSetting(extensionSetting);
C#
CallFeedItem callFeedItem = new CallFeedItem(); callFeedItem.callCountryCode = "US"; callFeedItem.callPhoneNumber = "212-565-0000"; CampaignExtensionSetting campaignExtensionSetting = new CampaignExtensionSetting(); campaignExtensionSetting.campaignId = campaignId; campaignExtensionSetting.extensionType = FeedType.CALL; ExtensionSetting extensionSetting = new ExtensionSetting(); extensionSetting.extensions = new ExtensionFeedItem[] { callFeedItem }; campaignExtensionSetting.extensionSetting = extensionSetting;
Python
call_feed_item = { 'xsi_type': 'CallFeedItem', 'callCountryCode': 'US', 'callPhoneNumber': '212-565-0000' } campaign_extension_setting = { 'campaignId': campaign_id, 'extensionType': 'CALL', 'extensionSetting': { 'extensions': [call_feed_item] } }
PHP
$callFeedItem = new CallFeedItem(); $callFeedItem->setCallCountryCode("US"); $callFeedItem->setCallPhoneNumber("212-565-0000"); $campaignExtensionSetting = new CampaignExtensionSetting(); $campaignExtensionSetting->setCampaignId($campaignId); $campaignExtensionSetting->setExtensionType(FeedType::CALL); $extensionSetting = new ExtensionSetting(); $extensionSetting->setExtensions([$callFeedItem]); $campaignExtensionSetting->setExtensionSetting($extensionSetting);
Perl
my $call_feed_item = Google::Ads::AdWords::v201809::CallFeedItem->new({ callCountryCode => 'US', callPhoneNumber => '212-565-0000' }); my $campaign_extension_setting = Google::Ads::AdWords::v201809::CampaignExtensionSetting->new({ campaignId => $campaign_id, extensionType => 'CALL', extensionSetting => Google::Ads::AdWords::v201809::ExtensionSetting->new({ extensions => [$call_feed_item]})});
Ruby
call_feed_item = { :xsi_type => 'CallFeedItem', :call_country_code => 'US', :call_phone_number => '212-565-0000' } campaign_extension_setting = { :campaign_id => campaign_id, :extension_type => 'CALL', :extension_setting => { :extensions => [call_feed_item] } }
Callout extensions
The callout ad extension lets you provide additional details, such as what products or services you offer, using text right below your search ads. The following code snippet shows how to create a callout extension:
Java
CalloutFeedItem freeDeliveryCallout = new CalloutFeedItem(); freeDeliveryCallout.setCalloutText("Free delivery"); CalloutFeedItem kidsCallout = new CalloutFeedItem(); kidsCallout.setCalloutText("Kids eat free"); CampaignExtensionSetting campaignExtensionSetting = new CampaignExtensionSetting(); campaignExtensionSetting.setCampaignId(campaignId); campaignExtensionSetting.setExtensionType(FeedType.CALLOUT); ExtensionSetting extensionSetting = new ExtensionSetting(); extensionSetting.setExtensions(new ExtensionFeedItem[] {freeDeliveryCallout, kidsCallout}); campaignExtensionSetting.setExtensionSetting(extensionSetting);
C#
CalloutFeedItem freeDeliveryCallout = new CalloutFeedItem(); freeDeliveryCallout.calloutText = "Free delivery"; CalloutFeedItem kidsCallout = new CalloutFeedItem(); kidsCallout.calloutText = "Kids eat free"; CampaignExtensionSetting campaignExtensionSetting = new CampaignExtensionSetting(); campaignExtensionSetting.campaignId = campaignId; campaignExtensionSetting.extensionType = FeedType.CALLOUT; ExtensionSetting extensionSetting = new ExtensionSetting(); extensionSetting.extensions = new ExtensionFeedItem[] { freeDeliveryCallout, kidsCallout }; campaignExtensionSetting.extensionSetting = extensionSetting;
Python
free_delivery_callout = { 'xsi_type': 'CalloutFeedItem', 'calloutText': 'Free delivery' } kids_callout = { 'xsi_type': 'CalloutFeedItem', 'calloutText': 'Kids eat free' } campaign_extension_setting = { 'campaignId': campaign_id, 'extensionType': 'CALLOUT', 'extensionSetting': { 'extensions': [free_delivery_callout, kids_callout] } }
PHP
$freeDeliveryCallout = new CalloutFeedItem(); $freeDeliveryCallout->setCalloutText('Free delivery'); $kidsCallout = new CalloutFeedItem(); $kidsCallout->setCalloutText('Kids eat free'); $campaignExtensionSetting = new CampaignExtensionSetting(); $campaignExtensionSetting->setCampaignId($campaignId); $campaignExtensionSetting->setExtensionType(FeedType::CALLOUT); $extensionSetting = new ExtensionSetting(); $extensionSetting->setExtensions([$freeDeliveryCallout, $kidsCallout]); $campaignExtensionSetting->setExtensionSetting($extensionSetting);
Perl
my $free_delivery_callout = Google::Ads::AdWords::v201809::CalloutFeedItem->new({ calloutText => 'Free delivery' }); my $kids_callout = Google::Ads::AdWords::v201809::CalloutFeedItem->new({ calloutText => 'Kids eat free' }); my $campaign_extension_setting = Google::Ads::AdWords::v201809::CampaignExtensionSetting->new({ campaignId => $campaign_id, extensionType => 'CALLOUT', extensionSetting => Google::Ads::AdWords::v201809::ExtensionSetting->new({ extensions => [$free_delivery_callout, $kids_callout]})});
Ruby
free_delivery_callout = { :xsi_type => 'CalloutFeedItem', :callout_text => 'Free delivery' } kids_callout = { :xsi_type => 'CalloutFeedItem', :callout_text => 'Kids eat free' } campaign_extension_setting = { :campaign_id => campaign_id, :extension_type => 'CALLOUT', :extension_setting => { :extensions => [free_delivery_callout, kids_callout] } }
App extensions
If your business developed an Android or iOS app to target mobile users, you can display links to the app alongside your ads using an app extension. App extensions are shown only to users who are currently logged in to Google, and who haven't yet installed your app. Clicking the app extension link takes them to the Google Play or Apple iTunes page for your app. This code snippet shows how to create an app extension for an application on Google Play:
Java
AppFeedItem appFeedItem = new AppFeedItem(); appFeedItem.setAppId("com.example.mobileapp"); appFeedItem.setAppStore(AppFeedItemAppStore.GOOGLE_PLAY); appFeedItem.setAppLinkText("Install our mobile app!"); UrlList finalUrlsList = new UrlList(); finalUrlsList.setUrls( new String[] {"https://play.google.com/store/apps/details?id=com.example.mobileapp"}); appFeedItem.setAppFinalUrls(finalUrlsList); CampaignExtensionSetting campaignExtensionSetting = new CampaignExtensionSetting(); campaignExtensionSetting.setCampaignId(campaignId); campaignExtensionSetting.setExtensionType(FeedType.APP); ExtensionSetting extensionSetting = new ExtensionSetting(); extensionSetting.setExtensions(new ExtensionFeedItem[] {appFeedItem}); campaignExtensionSetting.setExtensionSetting(extensionSetting);
C#
AppFeedItem appFeedItem = new AppFeedItem(); appFeedItem.appId = "com.example.mobileapp"; appFeedItem.appStore = AppFeedItemAppStore.GOOGLE_PLAY; appFeedItem.appLinkText = "Install our mobile app!"; UrlList finalUrlsList = new UrlList(); finalUrlsList.urls = new String[] { "https://play.google.com/store/apps/details?id=com.example.mobileapp" }; appFeedItem.appFinalUrls = finalUrlsList; CampaignExtensionSetting campaignExtensionSetting = new CampaignExtensionSetting(); campaignExtensionSetting.campaignId = campaignId; campaignExtensionSetting.extensionType = FeedType.APP; ExtensionSetting extensionSetting = new ExtensionSetting(); extensionSetting.extensions = new ExtensionFeedItem[] { appFeedItem }; campaignExtensionSetting.extensionSetting = extensionSetting;
Python
ap_url = 'https://play.google.com/store/apps/details?id=com.example.mobileapp' app_feed_item = { 'xsi_type': 'AppFeedItem', 'appId': 'com.example.mobileapp', 'appStore': 'GOOGLE_PLAY', 'appLinkText': 'Install our mobile app!', 'appFinalUrls': { 'urls': [ap_url] } } campaign_extension_setting = { 'campaignId': campaign_id, 'extensionType': 'APP', 'extensionSetting': { 'extensions': [app_feed_item] } }
PHP
$appFeedItem = new AppFeedItem(); $appFeedItem->setAppId('com.example.mobileapp'); $appFeedItem->setAppStore(AppFeedItemAppStore::GOOGLE_PLAY); $appFeedItem->setAppLinkText('Install our mobile app!'); $finalUrlsList = new UrlList(); $finalUrlsList->setUrls( [ 'https://play.google.com/store/apps/details?id=com.example.mobileapp' ] ); $appFeedItem->setAppFinalUrls($finalUrlsList); $campaignExtensionSetting = new CampaignExtensionSetting(); $campaignExtensionSetting->setCampaignId($campaignId); $campaignExtensionSetting->setExtensionType(FeedType::APP); $extensionSetting = new ExtensionSetting(); $extensionSetting->setExtensions([$appFeedItem]); $campaignExtensionSetting->setExtensionSetting($extensionSetting);
Perl
my $app_feed_item = Google::Ads::AdWords::v201809::AppFeedItem->new({ appId => 'com.example.mobileapp', appStore => 'GOOGLE_PLAY', appLinkText => 'Install our mobile app!', appFinalUrls => Google::Ads::AdWords::v201809::UrlList->new({ urls => [ 'https://play.google.com/store/apps/details?id=com.example.mobileapp' ]})}); my $campaign_extension_setting = Google::Ads::AdWords::v201809::CampaignExtensionSetting->new({ campaignId => $campaign_id, extensionType => 'APP', extensionSetting => Google::Ads::AdWords::v201809::ExtensionSetting->new({ extensions => [$app_feed_item]})});
Ruby
app_feed_item = { :xsi_type => 'AppFeedItem', :app_id => 'com.example.mobileapp', :app_store => 'GOOGLE_PLAY', :app_link_text => 'Install our mobile app!', :app_final_urls => { :urls => [ 'https://play.google.com/store/apps/details?id=com.example.mobileapp' ] } } campaign_extension_setting = { :campaign_id => campaign_id, :extension_type => 'APP', :extension_setting => { :extensions => [app_feed_item] } }
Message extensions
Message extensions allow people to see your ad, click an icon, and contact
you directly by text message. With one tap on your ad, people can contact you
to book an appointment, get a quote, ask for information, or request a service.
The following code snippet shows you how to do this using a MessageFeedItem
:
Java
MessageFeedItem messageFeedItem = new MessageFeedItem(); messageFeedItem.setMessageBusinessName("Travel Here"); messageFeedItem.setMessageCountryCode("US"); messageFeedItem.setMessagePhoneNumber("212-565-0000"); messageFeedItem.setMessageText("I want to know more"); messageFeedItem.setMessageExtensionText("Ask us about travel."); CampaignExtensionSetting campaignExtensionSetting = new CampaignExtensionSetting(); campaignExtensionSetting.setCampaignId(campaignId); campaignExtensionSetting.setExtensionType(FeedType.MESSAGE); ExtensionSetting extensionSetting = new ExtensionSetting(); extensionSetting.setExtensions(new ExtensionFeedItem[] {messageFeedItem}); campaignExtensionSetting.setExtensionSetting(extensionSetting);
C#
MessageFeedItem messageFeedItem = new MessageFeedItem(); messageFeedItem.messageBusinessName = "Travel Here"; messageFeedItem.messageCountryCode = "US"; messageFeedItem.messagePhoneNumber = "212-565-0000"; messageFeedItem.messageText = "I want to know more"; messageFeedItem.messageExtensionText = "Ask us about travel."; CampaignExtensionSetting campaignExtensionSetting = new CampaignExtensionSetting(); campaignExtensionSetting.campaignId = campaignId; campaignExtensionSetting.extensionType = FeedType.MESSAGE; ExtensionSetting extensionSetting = new ExtensionSetting(); extensionSetting.extensions = new ExtensionFeedItem[] { messageFeedItem }; campaignExtensionSetting.extensionSetting = extensionSetting;
Python
message_feed_item = { 'xsi_type': 'MessageFeedItem', 'messageBusinessName': 'Travel Here', 'messageCountryCode': 'US', 'messagePhoneNumber': '212-565-0000', 'messageText': 'I want to know more', 'messageExtensionText': 'Ask us about travel.' } campaign_extension_setting = { 'campaignId': campaign_id, 'extensionType': 'MESSAGE', 'extensionSetting': { 'extensions': [message_feed_item] } }
PHP
$messageFeedItem = new MessageFeedItem(); $messageFeedItem->setMessageBusinessName('Travel Here'); $messageFeedItem->setMessageCountryCode('US'); $messageFeedItem->setMessagePhoneNumber('212-565-0000'); $messageFeedItem->setMessageText('I want to know more'); $messageFeedItem->setMessageExtensionText('Ask us about travel.'); $campaignExtensionSetting = new CampaignExtensionSetting(); $campaignExtensionSetting->setCampaignId($campaignId); $campaignExtensionSetting->setExtensionType(FeedType::MESSAGE); $extensionSetting = new ExtensionSetting(); $extensionSetting->setExtensions([$messageFeedItem]); $campaignExtensionSetting->setExtensionSetting($extensionSetting);
Perl
my $message_feed_item = Google::Ads::AdWords::v201809::MessageFeedItem->new({ messageBusinessName => 'Travel Here', messageCountryCode => 'US', messagePhoneNumber => '212-565-0000', messageText => 'I want to know more', messageExtensionText => 'Ask us about travel.' }); my $campaign_extension_setting = Google::Ads::AdWords::v201809::CampaignExtensionSetting->new({ campaignId => $campaign_id, extensionType => 'MESSAGE', extensionSetting => Google::Ads::AdWords::v201809::ExtensionSetting->new({ extensions => [$message_feed_item]})});
Ruby
message_feed_item = { :xsi_type => 'MessageFeedItem', :message_business_name => 'Travel Here', :message_country_code => 'US', :message_phone_number => '212-565-0000', :message_text => 'I want to know more', :message_extension_text => 'Ask us about travel.' } campaign_extension_setting = { :campaign_id => campaign_id, :extension_type => 'MESSAGE', :extension_setting => { :extensions => [message_feed_item] } }
Price extensions
A price extension is an extension type that provides users comparative details and pricing of your products or services. Price extensions allow you to enter a list of services, products, events, or other items, with a list of prices to display to the user.
Fully configurable and targetable like other extension types, price extensions show titles, descriptive information, and pricing details for at least three and as many as eight of your products or services.
Price extensions can be attached at the account, campaign, or ad group level.
The following code snippet shows how to create a price extension:
Java
// 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);
C#
// Create the price extension feed item. PriceFeedItem priceFeedItem = new PriceFeedItem() { priceExtensionType = PriceExtensionType.SERVICES, // Price qualifier is optional. priceQualifier = PriceExtensionPriceQualifier.FROM, trackingUrlTemplate = "http://tracker.example.com/?u={lpurl}", language = "en", campaignTargeting = new FeedItemCampaignTargeting() { TargetingCampaignId = campaignId, }, scheduling = new FeedItemSchedule[] { new FeedItemSchedule() { dayOfWeek = DayOfWeek.SATURDAY, startHour = 10, startMinute = MinuteOfHour.ZERO, endHour = 22, endMinute = MinuteOfHour.ZERO }, new FeedItemSchedule() { dayOfWeek = DayOfWeek.SUNDAY, startHour = 10, startMinute = MinuteOfHour.ZERO, endHour = 18, endMinute = MinuteOfHour.ZERO } } }; // To create a price extension, at least three table rows are needed. List<PriceTableRow> priceTableRows = new List<PriceTableRow>(); 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.tableRows = priceTableRows.ToArray(); // Create your campaign extension settings. This associates the sitelinks // to your campaign. CustomerExtensionSetting customerExtensionSetting = new CustomerExtensionSetting() { extensionType = FeedType.PRICE, extensionSetting = new ExtensionSetting() { extensions = new ExtensionFeedItem[] { priceFeedItem } } };
Python
# To create a price extension, at least three table rows are needed. table_rows = [ CreatePriceTableRow('Scrubs', 'Body Scrub, Salt Scrub', 'https://www.example.com/scrubs', 60 * MICROS_PER_DOLLAR, 'USD', 'PER_HOUR', final_mobile_url='http://m.example.com/scrubs'), CreatePriceTableRow('Hair Cuts', 'Once a month', 'https://www.example.com/haircuts', 75 * MICROS_PER_DOLLAR, 'USD', 'PER_MONTH', final_mobile_url='http://m.example.com/haircuts'), CreatePriceTableRow('Skin Care Package', 'Four times a month', 'https://www.examples.com/skincarepackage', 250 * MICROS_PER_DOLLAR, 'USD', 'PER_MONTH', final_mobile_url=( 'http://m.example.com/skincarepackage')) ] # Create the price extension feed item. customer_extension_setting = { 'extensionType': 'PRICE', 'extensionSetting': { 'extensions': [{ 'priceExtensionType': 'SERVICES', 'trackingUrlTemplate': 'http://tracker.example.com/?u={lpurl}', 'language': 'en', 'campaignTargeting': { 'TargetingCampaignId': campaign_id }, 'scheduling': { 'feedItemSchedules': [ { 'dayOfWeek': 'SATURDAY', 'startHour': 10, 'startMinute': 'ZERO', 'endHour': 22, 'endMinute': 'ZERO' }, { 'dayOfWeek': 'SUNDAY', 'startHour': 10, 'startMinute': 'ZERO', 'endHour': 18, 'endMinute': 'ZERO' } ] }, 'tableRows': table_rows, # Price qualifier is optional. 'priceQualifier': 'FROM', 'xsi_type': 'PriceFeedItem' }] } }
PHP
// Create the price extension feed item. $priceFeedItem = new PriceFeedItem(); $priceFeedItem->setPriceExtensionType(PriceExtensionType::SERVICES); // Price qualifer is optional. $priceFeedItem->setPriceQualifier(PriceExtensionPriceQualifier::FROM); $priceFeedItem->setTrackingUrlTemplate( 'http://tracker.example.com/?u={lpurl}' ); $priceFeedItem->setLanguage('en'); $priceFeedItem->setCampaignTargeting( new FeedItemCampaignTargeting($campaignId) ); $priceFeedItem->setScheduling( new FeedItemScheduling( [ 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. $tableRows = []; $tableRows[] = self::createPriceTableRow( 'Scrubs', 'Body Scrub, Salt Scrub', 'http://www.example.com/scrubs', 60 * self::MICROS_PER_DOLLAR, 'USD', PriceExtensionPriceUnit::PER_HOUR, 'http://m.example.com/scrubs' ); $tableRows[] = self::createPriceTableRow( 'Hair Cuts', 'Once a month', 'http://www.example.com/haircuts', 75 * self::MICROS_PER_DOLLAR, 'USD', PriceExtensionPriceUnit::PER_MONTH, 'http://m.example.com/haircuts' ); $tableRows[] = self::createPriceTableRow( 'Skin Care Package', 'Four times a month', 'http://www.example.com/skincarepackage', 250 * self::MICROS_PER_DOLLAR, 'USD', PriceExtensionPriceUnit::PER_MONTH ); $priceFeedItem->setTableRows($tableRows); // Create your customer extension settings. This associates the price // extension to your account. $customerExtensionSetting = new CustomerExtensionSetting(); $customerExtensionSetting->setExtensionType(FeedType::PRICE); $customerExtensionSetting->setExtensionSetting(new ExtensionSetting()); $customerExtensionSetting->getExtensionSetting()->setExtensions( [$priceFeedItem] );
Perl
# Create the price extension feed item. my $price_feed_item = Google::Ads::AdWords::v201809::PriceFeedItem->new({ priceExtensionType => "SERVICES", # Price qualifer is optional. priceQualifier => "FROM", trackingUrlTemplate => "http://tracker.example.com/?u={lpurl}", language => 'en', campaignTargeting => Google::Ads::AdWords::v201809::FeedItemCampaignTargeting->new({ TargetingCampaignId => $campaign_id } ), scheduling => Google::Ads::AdWords::v201809::FeedItemScheduling->new({ feedItemSchedules => [ Google::Ads::AdWords::v201809::FeedItemSchedule->new({ dayOfWeek => "SUNDAY", startHour => "10", startMinute => "ZERO", endHour => "18", endMinute => "ZERO" } ), Google::Ads::AdWords::v201809::FeedItemSchedule->new({ dayOfWeek => "SATURDAY", startHour => "10", startMinute => "ZERO", endHour => "22", endMinute => "ZERO" })]})}); # To create a price extension, at least three table rows are needed. my @table_rows = (); push @table_rows, create_price_table_row( "Scrubs", "Body Scrub, Salt Scrub", "http://www.example.com/scrubs", "http://m.example.com/scrubs", 60000000, # 60 USD "USD", "PER_HOUR" ); push @table_rows, create_price_table_row( "Hair Cuts", "Once a month", "http://www.example.com/haircuts", "http://m.example.com/haircuts", 75000000, # 75 USD "USD", "PER_MONTH" ); push @table_rows, create_price_table_row( "Skin Care Package", "Four times a month", "http://www.example.com/skincarepackage", undef, 250000000, # 250 USD "USD", "PER_MONTH" ); $price_feed_item->set_tableRows(\@table_rows); # Create your customer extension settings. This associates the price # extension to your account. my $customer_extension_setting = Google::Ads::AdWords::v201809::CustomerExtensionSetting->new({ extensionType => 'PRICE', extensionSetting => Google::Ads::AdWords::v201809::ExtensionSetting->new({ extensions => [$price_feed_item]})});
Ruby
price_feed_item = { :xsi_type => 'PriceFeedItem', :price_extension_type => 'SERVICES', # Price qualifier is optional. :price_qualifier => 'FROM', :tracking_url_template => 'http://tracker.example.com/?u={lpurl}', :language => 'en', :campaign_targeting => { :targeting_campaign_id => campaign_id }, :scheduling => { :feed_item_schedules => [ { :day_of_week => 'SUNDAY', :start_hour => 10, :start_minute => 'ZERO', :end_hour => 18, :end_minute => 'ZERO' }, { :day_of_week => 'SATURDAY', :start_hour => 10, :start_minute => 'ZERO', :end_hour => 22, :end_minute => 'ZERO' } ] }, # To create a price extension, at least three table rows are needed. :table_rows => [ create_price_table_row( 'Scrubs', 'Body Scrub, Salt Scrub', 'http://www.example.com/scrubs', 'http://m.example.com/scrubs', 60000000, 'USD', 'PER_HOUR' ), create_price_table_row( 'Hair Cuts', 'Once a month', 'http://www.example.com/haircuts', 'http://m.example.com/haircuts', 75000000, 'USD', 'PER_MONTH' ), create_price_table_row( 'Skin Care Package', 'Four times a month', 'http://www.example.com/skincarepackage', nil, 250000000, 'USD', 'PER_MONTH' ) ] } customer_extension_setting = { :extension_type => 'PRICE', :extension_setting => { :extensions => [price_feed_item] } }
VB.NET
' Create the price extension feed item. Dim priceFeedItem As New PriceFeedItem priceFeedItem.priceExtensionType = PriceExtensionType.SERVICES ' Price qualifier is optional. priceFeedItem.priceQualifier = PriceExtensionPriceQualifier.FROM priceFeedItem.trackingUrlTemplate = "http://tracker.example.com/?u={lpurl}" priceFeedItem.language = "en" priceFeedItem.campaignTargeting = New FeedItemCampaignTargeting() priceFeedItem.campaignTargeting.TargetingCampaignId = campaignId Dim saturdaySchedule As New FeedItemSchedule saturdaySchedule.dayOfWeek = DayOfWeek.SATURDAY saturdaySchedule.startHour = 10 saturdaySchedule.startMinute = MinuteOfHour.ZERO saturdaySchedule.endHour = 22 saturdaySchedule.endMinute = MinuteOfHour.ZERO Dim sundaySchedule As New FeedItemSchedule sundaySchedule.dayOfWeek = DayOfWeek.SUNDAY sundaySchedule.startHour = 10 sundaySchedule.startMinute = MinuteOfHour.ZERO sundaySchedule.endHour = 18 sundaySchedule.endMinute = MinuteOfHour.ZERO priceFeedItem.scheduling = New FeedItemSchedule() {saturdaySchedule, sundaySchedule} ' To create a price extension, at least three table rows are needed. Dim priceTableRows As New List(Of PriceTableRow) Dim currencyCode As String = "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", Nothing, 250000000, currencyCode, PriceExtensionPriceUnit.PER_MONTH)) priceFeedItem.tableRows = priceTableRows.ToArray() ' Create your campaign extension settings. This associates the sitelinks ' to your campaign. Dim customerExtensionSetting As New CustomerExtensionSetting customerExtensionSetting.extensionType = FeedType.PRICE customerExtensionSetting.extensionSetting = New ExtensionSetting customerExtensionSetting.extensionSetting.extensions = New ExtensionFeedItem() {priceFeedItem}
The reference to createPriceTableRow
is defined as shown below:
Java
/** * 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; }
C#
/// <summary> /// Creates a price table row. /// </summary> /// <param name="header">The row header.</param> /// <param name="description">The description text.</param> /// <param name="finalUrl">The final URL.</param> /// <param name="finalMobileUrl">The mobile final URL, or null if this field /// should not be set.</param> /// <param name="priceInMicros">The price in micros.</param> /// <param name="currencyCode">The currency code.</param> /// <param name="priceUnit">The price unit.</param> /// <returns>A price table row for creating price extension.</returns> private static PriceTableRow CreatePriceTableRow(string header, string description, string finalUrl, string finalMobileUrl, long priceInMicros, string currencyCode, PriceExtensionPriceUnit priceUnit) { PriceTableRow retval = new PriceTableRow() { header = header, description = description, finalUrls = new UrlList() { urls = new string[] { finalUrl } }, price = new MoneyWithCurrency() { currencyCode = currencyCode, money = new Money() { microAmount = priceInMicros } }, priceUnit = priceUnit }; // Optional: set the mobile final URLs. if (!string.IsNullOrEmpty(finalMobileUrl)) { retval.finalMobileUrls = new UrlList() { urls = new string[] { finalMobileUrl } }; } return retval; }
Python
def CreatePriceTableRow(header, description, final_url, price_in_micros, currency_code, price_unit, final_mobile_url=None): """Helper function to generate a single row of a price table. Args: header: A str containing the header text of this row. description: A str description of this row in the price table. final_url: A str containing the final URL after all cross domain redirects. price_in_micros: An int indicating the price of the given currency in micros. currency_code: A str indicating the currency code being used. price_unit: A str enum indicating the price unit for this row. final_mobile_url: A str containing the final mobile URL after all cross domain redirects. Returns: A dictionary containing the contents of the generated price table row. """ table_row = { 'header': header, 'description': description, 'finalUrls': {'urls': [final_url]}, 'price': { 'money': { 'microAmount': price_in_micros, }, 'currencyCode': currency_code }, 'priceUnit': price_unit, 'xsi_type': 'PriceTableRow' } if final_mobile_url: table_row['finalMobileUrls'] = { 'urls': [final_mobile_url] } return table_row
PHP
/** * Creates a new price table row with the specified attributes. * * @param string $header the header of price table row * @param string $description the description of price table row * @param string $finalUrl the final URL of price table row * @param integer $priceInMicros the price in micro amount * @param string $currencyCode the 3-character currency code * @param string $priceUnit the unit of shown price * @param string|null $finalMobileUrl the mobile final URL of price table row * @return PriceTableRow the created price table row */ private static function createPriceTableRow( $header, $description, $finalUrl, $priceInMicros, $currencyCode, $priceUnit, $finalMobileUrl = null ) { $priceTableRow = new PriceTableRow(); $priceTableRow->setHeader($header); $priceTableRow->setDescription($description); $priceTableRow->setFinalUrls(new UrlList([$finalUrl])); $money = new Money(); $money->setMicroAmount($priceInMicros); $moneyWithCurrency = new MoneyWithCurrency(); $moneyWithCurrency->setMoney($money); $moneyWithCurrency->setCurrencyCode($currencyCode); $priceTableRow->setPrice($moneyWithCurrency); $priceTableRow->setPriceUnit($priceUnit); if ($finalMobileUrl !== null) { $priceTableRow->setFinalMobileUrls(new UrlList([$finalMobileUrl])); } return $priceTableRow; }
Perl
# Creates a new price table row with the specified attributes. sub create_price_table_row { my ($header, $description, $final_url, $final_mobile_url, $price_in_micros, $currency_code, $price_unit) = @_; my $price_table_row = Google::Ads::AdWords::v201809::PriceTableRow->new({ header => $header, description => $description, finalUrls => [Google::Ads::AdWords::v201809::UrlList->new({urls => [$final_url]})], price => Google::Ads::AdWords::v201809::MoneyWithCurrency->new({ money => Google::Ads::AdWords::v201809::Money->new({ microAmount => $price_in_micros } ), currencyCode => $currency_code } ), priceUnit => $price_unit }); # Optional: set the mobile final URLs. if ($final_mobile_url) { $price_table_row->set_finalMobileUrls([ Google::Ads::AdWords::v201809::UrlList->new( {urls => [$final_mobile_url]})]); } return $price_table_row; }
Ruby
def create_price_table_row(header, description, final_url, final_mobile_url, price_in_micros, currency_code, price_unit) ret_val = { :header => header, :description => description, :final_urls => { :urls => [final_url] }, :price => { :money => { :micro_amount => price_in_micros }, :currency_code => currency_code }, :price_unit => price_unit } # Optional: Set the mobile final URLs. unless final_mobile_url.nil? or final_mobile_url.empty? ret_val[:final_mobile_urls] = {:urls => [final_mobile_url]} end end
VB.NET
''' <summary> ''' Creates a price table row. ''' </summary> ''' <param name="header">The row header.</param> ''' <param name="description">The description text.</param> ''' <param name="finalUrl">The final URL.</param> ''' <param name="finalMobileUrl">The mobile final URL, or null if this field ''' should not be set.</param> ''' <param name="priceInMicros">The price in micros.</param> ''' <param name="currencyCode">The currency code.</param> ''' <param name="priceUnit">The price unit.</param> ''' <returns>A price table row for creating price extension.</returns> Private Shared Function CreatePriceTableRow(ByVal header As String, ByVal description As String, ByVal finalUrl As String, ByVal finalMobileUrl As String, ByVal priceInMicros As Long, ByVal currencyCode As String, ByVal priceUnit As PriceExtensionPriceUnit) _ As PriceTableRow Dim retval As New PriceTableRow retval.header = header retval.description = description retval.finalUrls = New UrlList() retval.finalUrls.urls = New String() {finalUrl} Dim moneyWithCurrency As New MoneyWithCurrency moneyWithCurrency.currencyCode = currencyCode moneyWithCurrency.money = New Money moneyWithCurrency.money.microAmount = priceInMicros retval.price = moneyWithCurrency retval.priceUnit = priceUnit ' Optional: Set the mobile final URLs. If Not String.IsNullOrEmpty(finalMobileUrl) Then retval.finalMobileUrls = New UrlList() retval.finalMobileUrls.urls = New String() {finalMobileUrl} End If Return retval End Function
Promotion extensions
Promotion extensions allow you to highlight sales and other promotions that let users see how they can save by buying now. There are many fields that let you customize exactly what appears in the extension, but the required ones are:
promotionTarget
- The text that appears on the ad when the extension is shown.percentOff
ormoneyAmountOff
- One of these is required. They show the user how big the discount is.percentOff
takes a value in micros, where 1 million micros represents 1%, and is shown as a percentage when rendered. For example, the value10000000
will render as "10%".moneyAmountOff
is also in micros. It requires both a currency and an amount of money.
finalUrls
- The URL targets for your landing page if someone clicks on the extension.
Optional fields:
occasion
- For example,NEW_YEARS
orHALLOWEEN
.- When using
occasion
without using extension setting services, make sure the values exactly match the documented enum values forPromotionFeedItem
.
- When using
discountModifier
- Allows you to add "up to" verbiage to the promotion, in case you have variable promotion rates.- When using
discountModifier
without using extension setting services, make sure the values exactly match the documented enum values forPromotionFeedItem
.
- When using
promotionCode
- For your users to enter to get the discount.ordersOverAmount
- To indicate a minimum spend before the user qualifies for the promotion.- Note that only one
promotionCode
orordersOverAmount
is allowed perPromotionFeedItem
.
- Note that only one
promotionStart
andpromotionEnd
- Ensures that the extension only shows during the promotion period. These expect a datetime format, though only midnight is allowed. So for example, you can setpromotionStart
to '20180601 000000' andpromotionEnd
to '20180701 000000' for a June-only promotion.- You can clear these fields by setting the special value: '00000101 000000'.
language
- Provides a language for your promotion by inputting a language code. This defaults to English.
For details on the rest of the fields, check out the PromotionFeedItem
docs.
Here's an example code snippet showing how to create a promotion extension:
Java
PromotionFeedItem promotionFeedItem = new PromotionFeedItem(); promotionFeedItem.setLanguage("en"); promotionFeedItem.setPromotionTarget("Wool Socks"); promotionFeedItem.setPercentOff(10_000_000L); promotionFeedItem.setPromotionCode("WinterSocksDeal"); UrlList finalUrlsList = new UrlList(); finalUrlsList.setUrls(new String[] {"http://www.example.com/socks"}); promotionFeedItem.setFinalUrls(finalUrlsList); CampaignExtensionSetting campaignExtensionSetting = new CampaignExtensionSetting(); campaignExtensionSetting.setCampaignId(campaignId); campaignExtensionSetting.setExtensionType(FeedType.PROMOTION); ExtensionSetting extensionSetting = new ExtensionSetting(); extensionSetting.setExtensions(new ExtensionFeedItem[] {promotionFeedItem}); campaignExtensionSetting.setExtensionSetting(extensionSetting);
C#
PromotionFeedItem promotionFeedItem = new PromotionFeedItem(); promotionFeedItem.language = "en"; promotionFeedItem.promotionTarget = "Wool Socks"; promotionFeedItem.percentOff = 10_000_000L; promotionFeedItem.promotionCode = "WinterSocksDeal"; UrlList finalUrlsList = new UrlList(); finalUrlsList.urls = new String[] { "http://www.example.com/socks" }; promotionFeedItem.finalUrls = finalUrlsList; CampaignExtensionSetting campaignExtensionSetting = new CampaignExtensionSetting(); campaignExtensionSetting.campaignId = campaignId; campaignExtensionSetting.extensionType = FeedType.PROMOTION; ExtensionSetting extensionSetting = new ExtensionSetting(); extensionSetting.extensions = new ExtensionFeedItem[] { promotionFeedItem }; campaignExtensionSetting.extensionSetting = extensionSetting;
Python
promotion_feed_item = { 'xsi_type': 'PromotionFeedItem', 'language': 'en', 'promotionTarget': 'Wool Socks', 'percentOff': 10000000, 'promotionCode': 'WinterSocksDeal', 'finalUrls': { 'urls': ['http://www.example.com/socks'] } } campaign_extension_setting = { 'campaignId': campaign_id, 'extensionType': 'PROMOTION', 'extensionSetting': { 'extensions': [promotion_feed_item] } }
PHP
$promotionFeedItem = new PromotionFeedItem(); $promotionFeedItem->setLanguage('en'); $promotionFeedItem->setPromotionTarget('Wool Socks'); $promotionFeedItem->setPercentOff(10000000); $promotionFeedItem->setPromotionCode('WinterSocksDeal'); $finalUrlsList = new UrlList(); $finalUrlsList->setUrls(['http://www.example.com/socks']); $promotionFeedItem->setFinalUrls($finalUrlsList); $campaignExtensionSetting = new CampaignExtensionSetting(); $campaignExtensionSetting->setCampaignId($campaignId); $campaignExtensionSetting->setExtensionType(FeedType::PROMOTION); $extensionSetting = new ExtensionSetting(); $extensionSetting->setExtensions([$promotionFeedItem]); $campaignExtensionSetting->setExtensionSetting($extensionSetting);
Perl
my $promotion_feed_item = Google::Ads::AdWords::v201809::PromotionFeedItem->new({ language => 'en', promotionTarget => 'Wool Socks', percentOff => 10000000, promotionCode => 'WinterSocksDeal', finalUrls => Google::Ads::AdWords::v201809::UrlList->new({ urls => ['http://www.example.com/socks']})}); my $campaign_extension_setting = Google::Ads::AdWords::v201809::CampaignExtensionSetting->new({ campaignId => $campaign_id, extensionType => 'PROMOTION', extensionSetting => Google::Ads::AdWords::v201809::ExtensionSetting->new({ extensions => [$promotion_feed_item]})});
Ruby
promotion_feed_item = { :xsi_type => 'PromotionFeedItem', :language => 'en', :promotion_target => 'Wool Socks', :percent_off => 10_000_000, :promotion_code => 'WinterSocksDeal', :final_urls => { :urls => ['http://www.example.com/socks'] } } campaign_extension_setting = { :campaign_id => campaign_id, :extension_type => 'PROMOTION', :extension_setting => { :extensions => [promotion_feed_item] } }
Updating ad extensions
Suppose you decided to change your restaurant's happy hours on Saturday to 5pm to 10pm.
The first step is to retrieve the list of existing settings:
Java
CampaignExtensionSettingServiceInterface campaignExtensionSettingService = adWordsServices.get(session, CampaignExtensionSettingServiceInterface.class); Selector selector = new SelectorBuilder() .fields( CampaignExtensionSettingField.CampaignId, CampaignExtensionSettingField.ExtensionType, CampaignExtensionSettingField.Extensions) .equals(CampaignExtensionSettingField.CampaignId, Long.toString(campaignId)) .equals(CampaignExtensionSettingField.ExtensionType, FeedType.SITELINK.getValue()) .build(); CampaignExtensionSettingPage page = campaignExtensionSettingService.get(selector);
C#
CampaignExtensionSettingService campaignExtensionSettingService = (CampaignExtensionSettingService) user.GetService( AdWordsService.v201809.CampaignExtensionSettingService); Selector selector = new Selector() { fields = new string[] { CampaignExtensionSetting.Fields.CampaignId, CampaignExtensionSetting.Fields.ExtensionType, ExtensionSetting.Fields.Extensions }, predicates = new Predicate[] { Predicate.Equals(CampaignExtensionSetting.Fields.CampaignId, campaignId), Predicate.Equals(CampaignExtensionSetting.Fields.ExtensionType, FeedType.SITELINK.ToString()), }, paging = Paging.Default }; CampaignExtensionSettingPage page = campaignExtensionSettingService.get(selector);
Python
campaign_extension_setting_service = client.GetService( 'CampaignExtensionSettingService', 'v201809') selector = { 'fields': ['CampaignId', 'ExtensionType', 'Extensions'], 'predicates': [ { 'operator': 'EQUALS', 'field': 'CampaignId', 'values': [campaign_id] }, { 'operator': 'EQUALS', 'field': 'ExtensionType', 'values': ['SITELINK'] } ] } page = campaign_extension_setting_service.get(selector)
PHP
$campaignExtensionSettingService = $adWordsServices->get( $session, CampaignExtensionSettingService::class ); $selector = new Selector(); $selector->setFields(['CampaignId', 'ExtensionType', 'Extensions']); $selector->setPredicates( [ new Predicate( 'CampaignId', PredicateOperator::EQUALS, [$campaignId] ), new Predicate( 'ExtensionType', PredicateOperator::EQUALS, [FeedType::SITELINK] ) ] ); $page = $campaignExtensionSettingService->get($selector);
Perl
my $page = $client->CampaignExtensionSettingService()->get({ selector => Google::Ads::AdWords::v201809::Selector->new({ fields => ["CampaignId", "ExtensionType", "Extensions"], predicates => [ Google::Ads::AdWords::v201809::Predicate->new({ field => 'CampaignId', operator => 'EQUALS', values => [$campaign_id]} ), Google::Ads::AdWords::v201809::Predicate->new({ field => 'ExtensionType', operator => 'EQUALS', values => ['SITELINK']})]})});
Ruby
campaign_extension_setting_srv = adwords.service( :CampaignExtensionSettingService, API_VERSION) selector = { :fields => ['CampaignId', 'ExtensionType', 'Extensions'], :predicates => [ { :field => 'CampaignId', :operator => 'EQUALS', :values => [campaign_id] }, { :field => 'ExtensionType', :operator => 'EQUALS', :values => ['SITELINK'] } ] } page = campaign_extension_setting_srv.get(selector)
Next, update the desired sitelink:
Java
CampaignExtensionSetting campaignExtensionSetting = page.getEntries(0); for (ExtensionFeedItem extensionFeedItem : campaignExtensionSetting.getExtensionSetting().getExtensions()) { SitelinkFeedItem sitelinkFeedItem = (SitelinkFeedItem) extensionFeedItem; if ("Happy hours".equals(sitelinkFeedItem.getSitelinkText())) { for (FeedItemSchedule feedItemSchedule : sitelinkFeedItem.getScheduling().getFeedItemSchedules()) { if (DayOfWeek.FRIDAY.equals(feedItemSchedule.getDayOfWeek())) { feedItemSchedule.setStartHour(17); feedItemSchedule.setStartMinute(MinuteOfHour.ZERO); feedItemSchedule.setEndHour(22); feedItemSchedule.setEndMinute(MinuteOfHour.ZERO); } } } }
C#
CampaignExtensionSetting campaignExtensionSetting = page.entries[0]; foreach (ExtensionFeedItem extensionFeedItem in campaignExtensionSetting.extensionSetting.extensions) { SitelinkFeedItem sitelinkFeedItem = (SitelinkFeedItem) extensionFeedItem; if (sitelinkFeedItem.sitelinkText == "Happy hours") { foreach (FeedItemSchedule feedItemSchedule in sitelinkFeedItem.scheduling) { if (feedItemSchedule.dayOfWeek == DayOfWeek.FRIDAY) { feedItemSchedule.startHour = 17; feedItemSchedule.startMinute = MinuteOfHour.ZERO; feedItemSchedule.endHour = 22; feedItemSchedule.endMinute = MinuteOfHour.ZERO; } } } }
Python
campaign_extension_setting = page['entries'][0] extensions = campaign_extension_setting['extensionSetting']['extensions'] for extension_feed_item in extensions: if 'Happy hours' == extension_feed_item['sitelinkText']: schedules = extension_feed_item['scheduling']['feedItemSchedules'] for feed_item_schedule in schedules: if feed_item_schedule['dayOfWeek'] == 'FRIDAY': feed_item_schedule['startHour'] = 17 feed_item_schedule['startMinute'] = 'ZERO' feed_item_schedule['endHour'] = 22 feed_item_schedule['endMinute'] = 'ZERO'
PHP
$campaignExtensionSetting = $page->getEntries()[0]; foreach ($campaignExtensionSetting->getExtensionSetting() ->getExtensions() as $sitelinkFeedItem) { if ('Happy hours' === $sitelinkFeedItem->getSitelinkText()) { foreach ($sitelinkFeedItem->getScheduling() ->getFeedItemSchedules() as $feedItemSchedule) { if (DayOfWeek::FRIDAY === $feedItemSchedule->getDayOfWeek()) { $feedItemSchedule->setStartHour(17); $feedItemSchedule->setStartMinute(MinuteOfHour::ZERO); $feedItemSchedule->setEndHour(22); $feedItemSchedule->setEndMinute(MinuteOfHour::ZERO); } } } }
Perl
my $campaign_extension_setting = $page->get_entries()->[0]; for my $sitelink_feed_item ( @{$campaign_extension_setting->get_extensionSetting()->get_extensions()}) { if ($sitelink_feed_item->get_sitelinkText() eq 'Happy hours') { for my $feed_item_schedule ( @{$sitelink_feed_item->get_scheduling()->get_feedItemSchedules()}) { if ($feed_item_schedule->get_dayOfWeek() eq 'FRIDAY') { $feed_item_schedule->set_startHour('17'); $feed_item_schedule->set_startMinute('ZERO'); $feed_item_schedule->set_endHour('22'); $feed_item_schedule->set_endMinute('ZERO'); } } } }
Ruby
campaign_extension_setting = page[:entries].first extensions = campaign_extension_setting[:extension_setting][:extensions] extensions.each do |sitelink_feed_item| if sitelink_feed_item[:sitelink_text] == 'Happy hours' schedules = sitelink_feed_item[:scheduling][:feed_item_schedules] schedules.each do |feed_item_schedule| if(feed_item_schedule[:day_of_week] == 'FRIDAY') feed_item_schedule[:start_hour] = 17 feed_item_schedule[:start_minute] = 'ZERO' feed_item_schedule[:end_hour] = 22 feed_item_schedule[:end_minute] = 'ZERO' end end end end
Finally, send the modified campaignExtensionSetting
to the server.
Java
CampaignExtensionSettingOperation operation = new CampaignExtensionSettingOperation(); operation.setOperator(Operator.SET); operation.setOperand(campaignExtensionSetting);
C#
CampaignExtensionSettingOperation operation = new CampaignExtensionSettingOperation(); operation.@operator = Operator.SET; operation.operand = campaignExtensionSetting;
Python
operations = [{ 'operator': 'SET', 'operand': campaign_extension_setting }]
PHP
$operation = new CampaignExtensionSettingOperation(); $operation->setOperator(Operator::SET); $operation->setOperand($campaignExtensionSetting);
Perl
my $operation = Google::Ads::AdWords::v201809::CampaignExtensionSettingOperation->new({ operator => 'ADD', operand => $campaign_extension_setting });
Ruby
operation = { :operator => 'SET', :operand => campaign_extension_setting }
To prevent the new settings from overwriting the old settings, remember to send back all feed items, even if you're modifying just one item.
Removing ad extensions
Behind the scenes, the extension setting services are still using feeds to control your ad extensions. When you create a new extension setting, the service creates feed items for you in the appropriate feed and associates them with the given campaign, ad group, or account, depending on which service you used.
Similarly, when you remove an ExtensionFeedItem
from an extension setting or
remove the extension setting altogether, the service removes the association
between the feed items and the attached entity, but it does not remove the
feed items because they may be associated with another entity.
There are two ways to remove the association between a feed item and an entity:
- You can remove the entire extension setting with a
REMOVE
operator. This will remove the association between the entity and all feed items in the extension setting. - You can remove individual
ExtensionFeedItem
s within the extension setting, which you can do by specifying a new set ofExtensionFeedItem
s that does not contain the one you want to remove.
In both cases, the underlying feed items are not removed. Therefore, if the feed items are no longer associated with any other entities, you should consider deleting the feed items, which will free up space and allow you to generate new extensions in the future. Alternatively, you can reuse the feed items in other extension settings.
If you don't either remove or reuse feed items created from the extension setting services when you remove the extensions, these feed items will accrue over time and eventually you may reach the limit on the number of feed items you can have in your account.
Deleting feed items
If you want to delete the underlying feed items after you disassociate them from
an entity, you can just grab the feedId
and
feedItemId
from the extension you delete, and delete the corresponding
FeedItem
.
Java
CampaignExtensionSettingServiceInterface campaignExtensionSettingService = adWordsServices.get(session, CampaignExtensionSettingServiceInterface.class); CampaignExtensionSettingOperation extensionSettingOperation = new CampaignExtensionSettingOperation(); extensionSettingOperation.setOperator(Operator.REMOVE); extensionSettingOperation.setOperand(campaignExtensionSetting); campaignExtensionSettingService.mutate( new CampaignExtensionSettingOperation[] {extensionSettingOperation}); FeedItemServiceInterface feedItemService = adWordsServices.get(session, FeedItemServiceInterface.class); List<FeedItemOperation> feedItemOperations = new ArrayList<>(); for (ExtensionFeedItem extensionFeedItem : campaignExtensionSetting.getExtensionSetting().getExtensions()) { FeedItemOperation feedItemOperation = new FeedItemOperation(); feedItemOperation.setOperator(Operator.REMOVE); FeedItem feedItem = new FeedItem(); feedItem.setFeedId(extensionFeedItem.getFeedId()); feedItem.setFeedItemId(extensionFeedItem.getFeedItemId()); feedItemOperation.setOperand(feedItem); feedItemOperations.add(feedItemOperation); } feedItemService.mutate( feedItemOperations.toArray(new FeedItemOperation[feedItemOperations.size()]));
C#
CampaignExtensionSettingService campaignExtensionSettingService = (CampaignExtensionSettingService) user.GetService( AdWordsService.v201809.CampaignExtensionSettingService); CampaignExtensionSettingOperation extensionSettingOperation = new CampaignExtensionSettingOperation(); extensionSettingOperation.@operator = Operator.REMOVE; extensionSettingOperation.operand = campaignExtensionSetting; campaignExtensionSettingService.mutate( new CampaignExtensionSettingOperation[] { extensionSettingOperation }); FeedItemService feedItemService = (FeedItemService) user.GetService( AdWordsService.v201809.FeedItemService); List<FeedItemOperation> feedItemOperations = new List<FeedItemOperation>(); foreach (ExtensionFeedItem extensionFeedItem in campaignExtensionSetting.extensionSetting.extensions) { FeedItemOperation feedItemOperation = new FeedItemOperation(); feedItemOperation.@operator = Operator.REMOVE; FeedItem feedItem = new FeedItem(); feedItem.feedId = extensionFeedItem.feedId; feedItem.feedItemId = extensionFeedItem.feedItemId; feedItemOperation.operand = feedItem; feedItemOperations.Add(feedItemOperation); } feedItemService.mutate(feedItemOperations.ToArray());
Python
campaign_extension_setting_service = client.GetService( 'CampaignExtensionSettingService', 'v201809') feed_item_service = client.GetService('FeedItemService', 'v201809') operations = [{ 'operator': 'REMOVE', 'operand': campaign_extension_setting }] campaign_extension_setting_service.mutate(operations) extensions = campaign_extension_setting['extensionSetting']['extensions'] operations = [{ 'operator': 'REMOVE', 'operand': { 'feedId': extension_feed_item['feedId'], 'feedItemId': extension_feed_item['feedItemId'] } } for extension_feed_item in extensions] feed_item_service.mutate(operations) if __name__ == '__main__': # Initialize client object. adwords_client = adwords.AdWordsClient.LoadFromStorage() main(adwords_client, CAMPAIGN_ID_1, CAMPAIGN_ID_2)
PHP
$campaignExtensionSettingService = $adWordsServices->get( $session, CampaignExtensionSettingService::class ); $extensionSettingOperation = new CampaignExtensionSettingOperation(); $extensionSettingOperation->setOperator(Operator::REMOVE); $extensionSettingOperation->setOperand($campaignExtensionSetting); $campaignExtensionSettingService->mutate([$extensionSettingOperation]); $feedItemService = $adWordsServices->get($session, FeedItemService::class); $feedItemOperations = []; foreach ($campaignExtensionSetting->getExtensionSetting() ->getExtensions() as $extensionFeedItem) { $feedItemOperation = new FeedItemOperation(); $feedItemOperation->setOperator(Operator::REMOVE); $feedItem = new FeedItem(); $feedItem->setFeedId($extensionFeedItem->getFeedId()); $feedItem->setFeedItemId($extensionFeedItem->getFeedItemId()); $feedItemOperation->setOperand($feedItem); $feedItemOperations[] = $feedItemOperation; } $feedItemService->mutate($feedItemOperations);
Perl
my $extension_setting_operation = Google::Ads::AdWords::v201809::CampaignExtensionSettingOperation->new({ operator => 'REMOVE', operand => $campaign_extension_setting }); $client->CampaignExtensionSettingService() ->mutate({operations => [$extension_setting_operation]}); my @feed_item_operations = (); for my $extension_feed_item ( @{$campaign_extension_setting->get_extensionSetting()->get_extensions()}) { my $feed_item_operation = Google::Ads::AdWords::v201809::FeedItemOperation->new({ operator => 'REMOVE', operand => Google::Ads::AdWords::v201809::FeedItem->new({ feedId => $extension_feed_item->get_feedId(), feedItemId => $extension_feed_item->get_feedItemId()})}); push @feed_item_operations, $feed_item_operation; } $client->FeedItemService()->mutate({operations => \@feed_item_operations});
Ruby
campaign_extension_setting_srv = adwords.service( :CampaignExtensionSettingService, API_VERSION) extension_setting_operation = { :operator => 'REMOVE', :operand => campaign_extension_setting } campaign_extension_setting_srv.mutate([extension_setting_operation]) feed_item_srv = adwords.service(:FeedItemService, API_VERSION) extensions = campaign_extension_setting[:extension_setting][:extensions] feed_item_operations = extensions.map do |extension_feed_item| { :operator => 'REMOVE', :operand => { :feed_id => extension_feed_item[:feed_id], :feed_item_id => extension_feed_item[:feed_item_id] } } end feed_item_srv.mutate(feed_item_operations)
The first REMOVE
, on the CampaignExtensionSettingService
, removes the
association between that extension and the campaign. The second REMOVE
, on the
FeedItemService
, removes the underlying feed items, freeing up space
so that you can use new extensions in the future.
Reusing feed items
You can associate the same feed item with multiple entities. For example, if you want the same sitelinks to appear on multiple campaigns, you can associate each campaign with the same set of feed items.
Similarly, after removing an ad extension from one
entity, you can associate the underlying feed item with a different entity by
capturing the feedItemId
from the response.
For example, if you have the old feedItemId
from a previously removed
extension setting stored in a variable storedFeedItemId
, you can reuse it
by populating only the feedItemId
on the SitelinkFeedItem
:
Java
SitelinkFeedItem sitelinkFeedItem = new SitelinkFeedItem(); sitelinkFeedItem.setFeedItemId(storedFeedItemId); CampaignExtensionSetting campaignExtensionSetting = new CampaignExtensionSetting(); campaignExtensionSetting.setCampaignId(campaignId); campaignExtensionSetting.setExtensionType(FeedType.SITELINK); ExtensionSetting extensionSetting = new ExtensionSetting(); extensionSetting.setExtensions(new ExtensionFeedItem[] {sitelinkFeedItem}); campaignExtensionSetting.setExtensionSetting(extensionSetting);
C#
SitelinkFeedItem sitelinkFeedItem = new SitelinkFeedItem(); sitelinkFeedItem.feedItemId = storedFeedItemId; CampaignExtensionSetting campaignExtensionSetting = new CampaignExtensionSetting(); campaignExtensionSetting.campaignId = campaignId; campaignExtensionSetting.extensionType = FeedType.SITELINK; ExtensionSetting extensionSetting = new ExtensionSetting(); extensionSetting.extensions = new ExtensionFeedItem[] { sitelinkFeedItem }; campaignExtensionSetting.extensionSetting = extensionSetting;
Python
site_link_feed_item = { 'xsi_type': 'SitelinkFeedItem', 'feedItemId': stored_feed_item_id } campaign_extension_setting = { 'campaignId': campaign_id, 'extensionType': 'SITELINK', 'extensionSetting': { 'extensions': [site_link_feed_item] } }
PHP
$sitelinkFeedItem = new SitelinkFeedItem(); $sitelinkFeedItem->setFeedItemId($storedFeedItemId); $campaignExtensionSetting = new CampaignExtensionSetting(); $campaignExtensionSetting->setCampaignId($campaignId); $campaignExtensionSetting->setExtensionType(FeedType::SITELINK); $extensionSetting = new ExtensionSetting(); $extensionSetting->setExtensions([$sitelinkFeedItem]); $campaignExtensionSetting->setExtensionSetting($extensionSetting);
Perl
my $sitelink_feed_item = Google::Ads::AdWords::v201809::SitelinkFeedItem->new( { feedItemId => $stored_feed_item_id }); my $campaign_extension_setting = Google::Ads::AdWords::v201809::CampaignExtensionSetting->new({ campaignId => $campaign_id, extensionType => 'SITELINK', extensionSetting => Google::Ads::AdWords::v201809::ExtensionSetting->new({ extensions => [$sitelink_feed_item]})});
Ruby
sitelink_feed_item = { :xsi_type => 'SitelinkFeedItem', :feed_item_id => stored_feed_item_id } campaign_extension_setting = { :campaign_id => campaign_id, :extension_type => 'SITELINK', :extension_setting => { :extensions => [sitelink_feed_item] } }
Targeting options for extensions
In addition to using an ExtensionSetting
to target an extension at the customer, campaign, or ad group levels,
you can also set targeting options on an individual
ExtensionFeedItem
by setting the campaignTargeting
, adGroupTargeting
, keywordTargeting
, or geoTargeting
attributes.
These targeting options will be combined with the ExtensionSetting
properties
to select which extension feed items will be used for a given impression.
For example, let's say you create a SitelinkFeedItem
with the following targeting options:
adGroupTargeting.TargetingAdGroupId
=12345
keywordTargeting.id
=7890
In addition, you set the AdGroupExtensionSetting
's platform restriction to MOBILE
.
When serving impressions for this ad group, Google Ads only serves sitelinks
from the SitelinkFeedItem
if the impression attributes satisfy the targeting
options on both AdGroupExtensionSetting
and SitelinkFeedItem
objects.
Case | Impression attributes | Result |
---|---|---|
1 |
|
The SitelinkFeedItem will not be used because the platform
(desktop) does not satisfy the targeting options on
AdGroupExtensionSetting . |
2 |
|
The SitelinkFeedItem will not be used because the keyword
(7890 ) does not satisfy targeting options on
SitelinkFeedItem . |
3 |
|
The SitelinkFeedItem will be used because the attributes
satisfy the targeting options on both AdGroupExtensionSetting
and SitelinkFeedItem . |
Track ad extension performance
Use the Placeholder report or
Placeholder Feed Item report
to track the performance of your ad extensions. To identify your ad extensions
use the FeedItemId
column.
Migrate ad extensions to extension setting services
The rest of this guide covers the pros and cons of extension setting services, to help you decide whether to start using them, or stay with feed services. It also describes how to migrate to the new services.
Extension setting services provide a simplified layer over the existing feed-based ad extensions. The new services:
- Support concrete types for all supported ad extensions.
- Provide a simplified API that allows you to manage ad extensions for a campaign or ad group.
Should I migrate?
Extension setting services cover all ad extension features currently available in the Google Ads UI. Most users will benefit from spending some time to rewrite their services and migrate their data to use the simplified extension setting services. The following sections will help you decide whether or not to migrate to the extension setting services.
When are extension setting services preferred?
If you simply need to add ad extensions to a campaign or ad group, set its device preference, or manage its schedule, then we recommend using extension setting services. An added benefit when using extension setting services is that unlike feed services, we maintain your feed's schema and data, so you won't have to keep up with the underlying feed structure.
When are legacy feed services preferred?
We recommend using the legacy feed services if you need to use one or more of the features listed below:
- Location extensions: Extension setting services do not include support for location extensions.
- Custom fields or matching functions: Extension setting services don't support custom fields in feeds, or writing custom matching functions.
- Multiple feeds: Extension setting services only support one feed per extension type that is managed by the system.
Migration steps
If you've only used feeds created in the Google Ads UI, you can use extension setting services immediately.
However, if you've created custom feeds with the API, you'll need to first perform the following steps:
- Retrieve feed items in your custom feeds.
- Identify feed items you want to keep.
- Delete the
CustomerFeed
,CampaignFeed
andAdGroupFeed
s that use the feed items from the custom feeds. - Create
CustomerExtensionSetting
,CampaignExtensionSetting
andAdGroupExtensionSetting
s that use the newExtensionFeedItem
s. - (Optional) Delete feed items that are no longer in use.
The sections below focus on upgrading ad extensions at the campaign level, but the same process applies at the ad group level.
Retrieve feed items in your custom feeds
To retrieve feed items in your custom feeds, you must first identify all custom feeds you've created using the AdWords API, as follows:
Java
FeedServiceInterface feedService = adWordsServices.get(session, FeedServiceInterface.class); String query = "SELECT Id, Name, Attributes WHERE Origin = 'USER' AND FeedStatus = 'ENABLED'"; List<Feed> feeds = new ArrayList<>(); int offset = 0; FeedPage feedPage; do { String pageQuery = String.format(query + " LIMIT %d, %d", offset, PAGE_SIZE); feedPage = feedService.query(pageQuery); if (feedPage.getEntries() != null) { feeds.addAll(Arrays.asList(feedPage.getEntries())); } offset += PAGE_SIZE; } while (offset < feedPage.getTotalNumEntries()); return feeds;
C#
using (FeedService feedService = (FeedService) user.GetService(AdWordsService.v201809.FeedService)) { FeedPage page = feedService.query("SELECT Id, Name, Attributes where " + "Origin='USER' and FeedStatus='ENABLED'"); return page.entries; }
Python
feed_service = client.GetService('FeedService', 'v201809') feeds = [] more_pages = True selector = { 'fields': ['Id', 'Name', 'Attributes'], 'predicates': [ { 'field': 'Origin', 'operator': 'EQUALS', 'values': ['USER'] }, { 'field': 'FeedStatus', 'operator': 'EQUALS', 'values': ['ENABLED'] } ], 'paging': { 'startIndex': 0, 'numberResults': PAGE_SIZE } } while more_pages: page = feed_service.get(selector) if 'entries' in page: feeds.extend(page['entries']) selector['paging']['startIndex'] += PAGE_SIZE more_pages = selector['paging']['startIndex'] < int(page['totalNumEntries']) return feeds
PHP
$feedService = $adWordsServices->get($session, FeedService::class); // Create paging controls. $totalNumEntries = 0; $offset = 0; $query = 'SELECT Id, Name, Attributes WHERE Origin="USER" AND ' . 'FeedStatus="ENABLED"'; $feeds = []; do { $pageQuery = sprintf('%s LIMIT %d,%d', $query, $offset, self::PAGE_LIMIT); // Make the query request. $page = $feedService->query($pageQuery); if ($page->getEntries() !== null) { $totalNumEntries = $page->getTotalNumEntries(); foreach ($page->getEntries() as $feed) { $feeds[] = $feed; } } // Advance the paging offset. $offset += self::PAGE_LIMIT; } while ($offset < $totalNumEntries); return $feeds;
Perl
my ($client) = @_; my $query = "SELECT Id, Name, Attributes WHERE Origin = 'USER' AND " . "FeedStatus = 'ENABLED'"; # Paginate through results automatically, and retrieve the feeds. my @feeds = Google::Ads::AdWords::Utilities::PageProcessor->new({ client => $client, service => $client->FeedService(), query => $query, page_size => PAGE_SIZE })->get_entries(); return \@feeds;
Ruby
def get_feeds(adwords) feed_srv = adwords.service(:FeedService, API_VERSION) query = "SELECT Id, Name, Attributes " + "WHERE Origin = 'USER' AND FeedStatus = 'ENABLED'" feeds = [] offset = 0 begin page_query = (query + " LIMIT %d, %d") % [offset, PAGE_SIZE] page = feed_srv.query(page_query) unless page[:entries].nil? feeds += page[:entries] end offset += PAGE_SIZE end while page[:total_num_entries] > offset return feeds end
VB.NET
Using feedService As FeedService = DirectCast( user.GetService( AdWordsService.v201809.FeedService), FeedService) Dim page As FeedPage = feedService.query("SELECT Id, Name, Attributes where " & "Origin='USER' and FeedStatus='ENABLED'") Return page.entries End Using
Next, retrieve feed items in these feeds. The example uses sitelinks, but the approach is similar for the other ad extensions.
Java
// Get the FeedItemService. FeedItemServiceInterface feedItemService = adWordsServices.get(session, FeedItemServiceInterface.class); String query = String.format( "SELECT FeedItemId, AttributeValues WHERE Status = 'ENABLED' AND FeedId = %d", feed.getId()); List<FeedItem> feedItems = new ArrayList<>(); int offset = 0; FeedItemPage feedItemPage; do { String pageQuery = String.format(query + " LIMIT %d, %d", offset, PAGE_SIZE); feedItemPage = feedItemService.query(pageQuery); if (feedItemPage.getEntries() != null) { feedItems.addAll(Arrays.asList(feedItemPage.getEntries())); } offset += PAGE_SIZE; } while (offset < feedItemPage.getTotalNumEntries()); return feedItems;
C#
using (FeedItemService feedItemService = (FeedItemService) user.GetService(AdWordsService.v201809.FeedItemService)) { FeedItemPage page = feedItemService.query(string.Format( "Select FeedItemId, " + "AttributeValues where Status = 'ENABLED' and FeedId = '{0}'", feedId)); return page.entries; }
Python
feed_item_service = client.GetService('FeedItemService', 'v201809') feed_items = [] more_pages = True selector = { 'fields': ['FeedItemId', 'AttributeValues'], 'predicates': [ { 'field': 'Status', 'operator': 'EQUALS', 'values': ['ENABLED'] }, { 'field': 'FeedId', 'operator': 'EQUALS', 'values': [feed['id']] } ], 'paging': { 'startIndex': 0, 'numberResults': PAGE_SIZE } } while more_pages: page = feed_item_service.get(selector) if 'entries' in page: feed_items.extend(page['entries']) selector['paging']['startIndex'] += PAGE_SIZE more_pages = selector['paging']['startIndex'] < int(page['totalNumEntries']) return feed_items
PHP
$feedItemService = $adWordsServices->get($session, FeedItemService::class); // Create paging controls. $totalNumEntries = 0; $offset = 0; $query = sprintf( 'SELECT FeedItemId, AttributeValues WHERE Status = ' . '"ENABLED" AND FeedId = %d', $feedId ); $feedItems = []; do { $pageQuery = sprintf('%s LIMIT %d,%d', $query, $offset, self::PAGE_LIMIT); // Make the query request. $page = $feedItemService->query($pageQuery); if ($page->getEntries() !== null) { $totalNumEntries = $page->getTotalNumEntries(); foreach ($page->getEntries() as $feedItem) { $feedItems[] = $feedItem; } } // Advance the paging offset. $offset += self::PAGE_LIMIT; } while ($offset < $totalNumEntries); return $feedItems;
Perl
my ($client, $feed) = @_; my $query = sprintf "SELECT FeedItemId, AttributeValues " . "WHERE Status = 'ENABLED' AND FeedId = %d", $feed->get_id(); # Paginate through results automatically, and retrieve the feed items. my @feed_items = Google::Ads::AdWords::Utilities::PageProcessor->new({ client => $client, service => $client->FeedItemService(), query => $query, page_size => PAGE_SIZE })->get_entries(); return \@feed_items;
Ruby
def get_feed_items(adwords, feed) feed_item_srv = adwords.service(:FeedItemService, API_VERSION) query = ("SELECT FeedItemId, AttributeValues " + "WHERE Status = 'ENABLED' AND FeedId = %d") % feed[:id] feed_items = [] offset = 0 begin page_query = (query + " LIMIT %d, %d") % [offset, PAGE_SIZE] page = feed_item_srv.query(page_query) unless page[:entries].nil? feed_items += page[:entries] end offset += PAGE_SIZE end while page[:total_num_entries] > offset return feed_items end
VB.NET
Using FeedItemService As FeedItemService = DirectCast( user.GetService( AdWordsService.v201809.FeedItemService), FeedItemService) Dim page As FeedItemPage = FeedItemService.query(String.Format("SELECT FeedItemId, AttributeValues " & "WHERE Status = 'ENABLED'" & " AND FeedId = '{0}'", feedId)) Return page.entries End Using
For ease of handling, load the values into a locally defined class:
Java
private static class SiteLinkFromFeed { private String text; private String url; private String[] finalUrls; private String[] finalMobileUrls; private String trackingUrlTemplate; private String line2; private String line3; }
C#
private class SiteLinkFromFeed { /// <summary> /// Gets or sets the feed ID. /// </summary> public long FeedId { get; set; } /// <summary> /// Gets or sets the feed item ID. /// </summary> public long FeedItemId { get; set; } /// <summary> /// Gets or sets the sitelink text. /// </summary> public string Text { get; set; } /// <summary> /// Gets or sets the sitelink URL. /// </summary> public string Url { get; set; } /// <summary> /// Gets or sets the sitelink final URLs. /// </summary> public string[] FinalUrls { get; set; } /// <summary> /// Gets or sets the sitelink final Mobile URLs. /// </summary> public string[] FinalMobileUrls { get; set; } /// <summary> /// Gets or sets the sitelink tracking URL template. /// </summary> public string TrackingUrlTemplate { get; set; } /// <summary> /// Gets or sets the sitelink line2 description. /// </summary> public string Line2 { get; set; } /// <summary> /// Gets or sets the sitelink line3 description. /// </summary> public string Line3 { get; set; } }
Python
Not applicablePHP
// @codingStandardsIgnoreStart class SitelinkFromFeed { // @codingStandardsIgnoreEnd private $feedId; private $feedItemId; private $text; private $url; private $finalUrls; private $finalMobileUrls; private $trackingUrlTemplate; private $line2; private $line3; private $scheduling; public function __construct($feedId = null, $feedItemId = null) { $this->feedId = $feedId; $this->feedItemId = $feedItemId; } public function getFeedId() { return $this->feedId; } public function getFeedItemId() { return $this->feedItemId; } public function getText() { return $this->text; } public function getUrl() { return $this->url; } public function getFinalUrls() { return $this->finalUrls; } public function getFinalMobileUrls() { return $this->finalMobileUrls; } public function getTrackingUrlTemplate() { return $this->trackingUrlTemplate; } public function getLine2() { return $this->line2; } public function getLine3() { return $this->line3; } public function setFeedId($feedId) { $this->feedId = $feedId; } public function setFeedItemId($feedItemId) { $this->feedItemId = $feedItemId; } public function setText($text) { $this->text = $text; } public function setUrl($url) { $this->url = $url; } public function setFinalUrls(array $finalUrls) { $this->finalUrls = $finalUrls; } public function setFinalMobileUrls(array $finalMobileUrls) { $this->finalMobileUrls = $finalMobileUrls; } public function setTrackingUrlTemplate($trackingUrlTemplate) { $this->trackingUrlTemplate = $trackingUrlTemplate; } public function setLine2($line2) { $this->line2 = $line2; } public function setLine3($line3) { $this->line3 = $line3; } }
Perl
Not applicableRuby
Not applicableVB.NET
''' <summary> ''' A sitelink object read from a feed. ''' </summary> Private Class SiteLinkFromFeed ''' <summary> ''' The feed ID. ''' </summary> Private feedIdField As Long ''' <summary> ''' The feed item ID. ''' </summary> Private feedItemIdField As Long ''' <summary> ''' The sitelink text. ''' </summary> Private textField As String ''' <summary> ''' The sitelink URL. ''' </summary> Private urlField As String ''' <summary> ''' The sitelink final URLs. ''' </summary> Private finalUrlsField As String() ''' <summary> ''' The sitelink final Mobile URLs. ''' </summary> Private finalMobileUrlsField As String() ''' <summary> ''' The sitelink tracking URL template. ''' </summary> Private trackingUrlTemplateField As String ''' <summary> ''' The sitelink line2 details. ''' </summary> Private line2Field As String ''' <summary> ''' The sitelink line3 details. ''' </summary> Private line3Field As String ''' <summary> ''' Gets or sets the feed ID. ''' </summary> Public Property FeedId As Long Get Return feedIdField End Get Set(ByVal value As Long) feedIdField = value End Set End Property ''' <summary> ''' Gets or sets the feed item ID. ''' </summary> Public Property FeedItemId As Long Get Return feedItemIdField End Get Set(ByVal value As Long) feedItemIdField = value End Set End Property ''' <summary> ''' Gets or sets the sitelink text. ''' </summary> Public Property Text As String Get Return textField End Get Set(ByVal value As String) textField = value End Set End Property ''' <summary> ''' Gets or sets the sitelink URL. ''' </summary> Public Property Url As String Get Return urlField End Get Set(ByVal value As String) urlField = value End Set End Property ''' <summary> ''' Gets or sets the sitelink final URLs. ''' </summary> Public Property FinalUrls As String() Get Return finalUrlsField End Get Set(ByVal value As String()) finalUrlsField = value End Set End Property ''' <summary> ''' Gets or sets the sitelink final Mobile URLs. ''' </summary> Public Property FinalMobileUrls As String() Get Return finalMobileUrlsField End Get Set(ByVal value As String()) finalMobileUrlsField = value End Set End Property ''' <summary> ''' Gets or sets the tracking URL template. ''' </summary> Public Property TrackingUrlTemplate As String Get Return trackingUrlTemplateField End Get Set(ByVal value As String) trackingUrlTemplateField = value End Set End Property ''' <summary> ''' Gets or sets the sitelink line2 details. ''' </summary> Public Property Line2 As String Get Return line2Field End Get Set(ByVal value As String) line2Field = value End Set End Property ''' <summary> ''' Gets or sets the sitelink line3 details. ''' </summary> Public Property Line3 As String Get Return line3Field End Get Set(ByVal value As String) line3Field = value End Set End Property End Class
You should also define a few constants to help better parse the
FeedMapping
s.
You can find these placeholder values on the
feed placeholder page.
Java
// See the Placeholder reference page for a list of all the placeholder types and fields. // https://developers.google.com/adwords/api/docs/appendix/placeholders private static final int PLACEHOLDER_SITELINKS = 1; // See the Placeholder reference page for a list of all the placeholder types and fields. // https://developers.google.com/adwords/api/docs/appendix/placeholders private static final int PLACEHOLDER_FIELD_SITELINK_LINK_TEXT = 1; private static final int PLACEHOLDER_FIELD_SITELINK_URL = 2; private static final int PLACEHOLDER_FIELD_LINE_2_TEXT = 3; private static final int PLACEHOLDER_FIELD_LINE_3_TEXT = 4; private static final int PLACEHOLDER_FIELD_FINAL_URLS = 5; private static final int PLACEHOLDER_FIELD_FINAL_MOBILE_URLS = 6; private static final int PLACEHOLDER_FIELD_TRACKING_URL_TEMPLATE = 7;
C#
/// <summary> /// The placeholder type for sitelinks. See /// https://developers.google.com/adwords/api/docs/appendix/placeholders for /// the list of all supported placeholder types. /// </summary> private const int PLACEHOLDER_TYPE_SITELINKS = 1; /// <summary> /// Holds the placeholder field IDs for sitelinks. See /// https://developers.google.com/adwords/api/docs/appendix/placeholders for /// the list of all supported placeholder types. /// </summary> private 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; };
Python
# The placeholder type for sitelinks. For the list of all supported placeholder # types, see: # https://developers.google.com/adwords/api/docs/appendix/placeholders PLACEHOLDER_TYPE_SITELINKS = 1 # The placeholder field IDs for sitelinks. For the list of all supported # placeholder types, see: # https://developers.google.com/adwords/api/docs/appendix/placeholders SITE_LINK_FIELDS = { 'TEXT': 1, 'URL': 2, 'LINE2': 3, 'LINE3': 4, 'FINAL_URLS': 5, 'FINAL_MOBILE_URLS': 6, 'TRACKING_URL_TEMPLATE': 7 }
PHP
// The placeholder type for sitelinks. See // https://developers.google.com/adwords/api/docs/appendix/placeholders // for the list of all supported placeholder types. const PLACEHOLDER_TYPE_SITELINKS = 1; // Placeholder field IDs for sitelinks. See // https://developers.google.com/adwords/api/docs/appendix/placeholders // for the list of all supported placeholder types. const PLACEHOLDER_FIELD_TEXT = 1; const PLACEHOLDER_FIELD_URL = 2; const PLACEHOLDER_FIELD_LINE2 = 3; const PLACEHOLDER_FIELD_LINE3 = 4; const PLACEHOLDER_FIELD_FINAL_URLS = 5; const PLACEHOLDER_FIELD_FINAL_MOBILE_URLS = 6; const PLACEHOLDER_FIELD_TRACKING_URL_TEMPLATE = 7;
Perl
# See the Placeholder reference page for a list of all the placeholder types and # fields. # https://developers.google.com/adwords/api/docs/appendix/placeholders use constant PLACEHOLDER_SITELINKS => 1; use constant PLACEHOLDER_FIELD_SITELINK_LINK_TEXT => 1; use constant PLACEHOLDER_FIELD_SITELINK_URL => 2; use constant PLACEHOLDER_FIELD_SITELINK_FINAL_URLS => 5; use constant PLACEHOLDER_FIELD_SITELINK_FINAL_MOBILE_URLS => 6; use constant PLACEHOLDER_FIELD_SITELINK_TRACKING_TEMPLATE => 7; use constant PLACEHOLDER_FIELD_SITELINK_LINE_1_TEXT => 3; use constant PLACEHOLDER_FIELD_SITELINK_LINE_2_TEXT => 4;
Ruby
# See the Placeholder reference page for a liste of all placeholder types # and fields. # https://developers.google.com/adwords/api/docs/appendix/placeholders PLACEHOLDER_SITELINKS = 1 PLACEHOLDER_FIELD_SITELINK_LINK_TEXT = 1 PLACEHOLDER_FIELD_SITELINK_URL = 2 PLACEHOLDER_FIELD_LINE_2_TEXT = 3 PLACEHOLDER_FIELD_LINE_3_TEXT = 4 PLACEHOLDER_FIELD_FINAL_URLS = 5 PLACEHOLDER_FIELD_FINAL_MOBILE_URLS = 6 PLACEHOLDER_FIELD_TRACKING_URL_TEMPLATE = 7
VB.NET
''' <summary> ''' Holds the placeholder field IDs for sitelinks. See ''' https://developers.google.com/adwords/api/docs/appendix/placeholders for ''' the list of all supported placeholder types. ''' </summary> Private Class SiteLinkFields Public Const TEXT As Long = 1 Public Const URL As Long = 2 Public Const LINE2 As Long = 3 Public Const LINE3 As Long = 4 Public Const FINAL_URLS As Long = 5 Public Const FINAL_MOBILE_URLS As Long = 6 Public Const TRACKING_URL_TEMPLATE As Long = 7 End Class
To convert a FeedItem
into a SitelinksFromFeed
object, you must retrieve the
FeedMapping
for the feed, and then map each attribute into the corresponding
object properties.
You can retrieve the FeedMapping
as follows:
Java
private static Multimap<Long, Integer> getFeedMapping(AdWordsServicesInterface adWordsServices, AdWordsSession session, Feed feed, long placeholderType) throws RemoteException { // Get the FeedMappingService. FeedMappingServiceInterface feedMappingService = adWordsServices.get(session, FeedMappingServiceInterface.class); String query = String.format( "SELECT FeedMappingId, AttributeFieldMappings WHERE FeedId = %d and PlaceholderType = %d " + "AND Status = 'ENABLED'", feed.getId(), placeholderType); Multimap<Long, Integer> attributeMappings = HashMultimap.create(); int offset = 0; FeedMappingPage feedMappingPage; do { String pageQuery = String.format(query + " LIMIT %d, %d", offset, PAGE_SIZE); feedMappingPage = feedMappingService.query(pageQuery); if (feedMappingPage.getEntries() != null) { // Normally, a feed attribute is mapped only to one field. However, you may map it to more // than one field if needed. for (FeedMapping feedMapping : feedMappingPage.getEntries()) { for (AttributeFieldMapping attributeMapping : feedMapping.getAttributeFieldMappings()) { attributeMappings.put(attributeMapping.getFeedAttributeId(), attributeMapping.getFieldId()); } } } offset += PAGE_SIZE; } while (offset < feedMappingPage.getTotalNumEntries()); return attributeMappings; }
C#
private Dictionary<long, HashSet<long>> GetFeedMapping(AdWordsUser user, long feedId, long placeHolderType) { using (FeedMappingService feedMappingService = (FeedMappingService) user.GetService(AdWordsService.v201809.FeedMappingService)) { FeedMappingPage page = feedMappingService.query(string.Format( "SELECT FeedMappingId, " + "AttributeFieldMappings where FeedId='{0}' and PlaceholderType={1} and " + "Status='ENABLED'", feedId, placeHolderType)); Dictionary<long, HashSet<long>> attributeMappings = new Dictionary<long, HashSet<long>>(); if (page.entries != null) { // Normally, a feed attribute is mapped only to one field. However, // you may map it to more than one field if needed. foreach (FeedMapping feedMapping in page.entries) { foreach (AttributeFieldMapping attributeMapping in feedMapping .attributeFieldMappings) { if (!attributeMappings.ContainsKey(attributeMapping.feedAttributeId)) { attributeMappings[attributeMapping.feedAttributeId] = new HashSet<long>(); } attributeMappings[attributeMapping.feedAttributeId] .Add(attributeMapping.fieldId); } } } return attributeMappings; } }
Python
def GetFeedMapping(client, feed, placeholder_type): """Gets the Feed Mapping for a given Feed. Args: client: an AdWordsClient instance. feed: the Feed we are retrieving the Feed Mapping for. placeholder_type: the Placeholder Type we are looking for. Returns: A dictionary containing the Feed Mapping. """ feed_mapping_service = client.GetService('FeedMappingService', 'v201809') attribute_mappings = {} more_pages = True selector = { 'fields': ['FeedMappingId', 'AttributeFieldMappings'], 'predicates': [ { 'field': 'FeedId', 'operator': 'EQUALS', 'values': [feed['id']] }, { 'field': 'PlaceholderType', 'operator': 'EQUALS', 'values': [placeholder_type] } ], 'paging': { 'startIndex': 0, 'numberResults': PAGE_SIZE } } while more_pages: page = feed_mapping_service.get(selector) if 'entries' in page: # Normally, a feed attribute is mapped only to one field. However, you may # map it to more than one field if needed. for feed_mapping in page['entries']: for attribute_mapping in feed_mapping['attributeFieldMappings']: # Since attribute mappings can have multiple values for each key, # we use a list to store the values. if attribute_mapping['feedAttributeId'] in attribute_mappings: attribute_mappings[attribute_mapping['feedAttributeId']].append( attribute_mapping['fieldId']) else: attribute_mappings[attribute_mapping['feedAttributeId']] = [ attribute_mapping['fieldId']] selector['paging']['startIndex'] += PAGE_SIZE more_pages = selector['paging']['startIndex'] < int(page['totalNumEntries']) return attribute_mappings
PHP
private static function getAttributeFieldMappings( AdWordsServices $adWordsServices, AdWordsSession $session, $feedId, $placeholderTypeId ) { $feedMappingService = $adWordsServices->get($session, FeedMappingService::class); $page = $feedMappingService->query( sprintf( 'SELECT FeedMappingId, AttributeFieldMappings WHERE FeedId="%d" ' . 'AND PlaceholderType="%d" AND Status="ENABLED"', $feedId, $placeholderTypeId ) ); $attributeMappings = []; if ($page->getEntries() !== null) { // Normally, a feed attribute is mapped only to one field. However, // you may map it to more than one field if needed. foreach ($page->getEntries() as $feedMapping) { foreach ($feedMapping->getAttributeFieldMappings() as $attributeMapping) { if (array_key_exists( $attributeMapping->getFeedAttributeId(), $attributeMappings ) === false) { $attributeMappings[$attributeMapping->getFeedAttributeId()] = []; } $attributeMappings[$attributeMapping->getFeedAttributeId()][] = $attributeMapping->getFieldId(); } } } return $attributeMappings; }
Perl
sub get_feed_mapping_attributes() { my ($client, $feed, $placeholder_type) = @_; my $query = sprintf "SELECT FeedMappingId, AttributeFieldMappings " . "WHERE FeedId = %d and PlaceholderType = %d " . "AND Status = 'ENABLED'", $feed->get_id(), $placeholder_type; # Paginate through results. # The contents of the subroutine will be executed for each feed mapping. # The attribute mappings hash is being passed as an argument to the # subroutine in order to populate it. my %attribute_mappings; Google::Ads::AdWords::Utilities::PageProcessor->new({ client => $client, service => $client->FeedMappingService(), query => $query, page_size => PAGE_SIZE } )->process_entries( # Normally, a feed attribute is mapped only to one field. However, you may # map it to more than one field if needed. sub { my ($feed_mapping) = @_; my @attributes = @{$feed_mapping->get_attributeFieldMappings()}; foreach my $attribute_mapping (@attributes) { my $attribute_id = $attribute_mapping->get_feedAttributeId(); if (!$attribute_mappings{$attribute_id}) { $attribute_mappings{$attribute_id} = []; } push $attribute_mappings{$attribute_id}, $attribute_mapping->get_fieldId(); } }, ); return \%attribute_mappings; }
Ruby
def get_feed_mapping(adwords, feed, placeholder_type) feed_mapping_srv = adwords.service(:FeedMappingService, API_VERSION) query = ("SELECT FeedMappingId, AttributeFieldMappings " + "WHERE FeedId = %d AND PlaceholderType = %d AND Status = 'ENABLED'") % [feed[:id], placeholder_type] attribute_mappings = {} offset = 0 begin page_query = (query + " LIMIT %d, %d") % [offset, PAGE_SIZE] page = feed_mapping_srv.query(page_query) unless page[:entries].nil? # Normally, a feed attribute is mapped only to one field. However, you # may map it to more than one field if needed. page[:entries].each do |feed_mapping| feed_mapping[:attribute_field_mappings].each do |attribute_mapping| # Since attribute_mappings can have multiple values for each key, # we set up an array to store the values. if attribute_mappings.has_key?(attribute_mapping[:feed_attribute_id]) attribute_mappings[attribute_mapping[:feed_attribute_id]] << attribute_mapping[:field_id] else attribute_mappings[attribute_mapping[:feed_attribute_id]] = [attribute_mapping[:field_id]] end end end end offset += PAGE_SIZE end while page[:total_num_entries] > offset return attribute_mappings end
VB.NET
''' <summary> ''' Gets the feed mapping for a feed. ''' </summary> ''' <param name="user">The user that owns the feed.</param> ''' <param name="feedId">The feed ID.</param> ''' <param name="placeHolderType">Type of the place holder for which feed ''' mappings should be retrieved.</param> ''' <returns>A dictionary, with key as the feed attribute ID, and value as ''' the set of all fields which the attribute has a mapping to.</returns> Private Function GetFeedMapping(ByVal user As AdWordsUser, ByVal feedId As Long, ByVal placeHolderType As Long) _ As Dictionary(Of Long, HashSet(Of Long)) Using feedMappingService As FeedMappingService = DirectCast( user.GetService( AdWordsService.v201809.FeedMappingService), FeedMappingService) Dim page As FeedMappingPage = feedMappingService.query( String.Format( "SELECT FeedMappingId, AttributeFieldMappings where FeedId='{0}' and " & "PlaceholderType={1} and Status='ENABLED'", feedId, placeHolderType)) Dim attributeMappings As New Dictionary(Of Long, HashSet(Of Long))() If Not (page.entries Is Nothing) Then ' Normally, a feed attribute is mapped only to one field. However, ' you may map it to more than one field if needed. For Each feedMapping As FeedMapping In page.entries For Each attributeMapping As AttributeFieldMapping In _ feedMapping.attributeFieldMappings If Not attributeMappings.ContainsKey(attributeMapping.feedAttributeId) _ Then attributeMappings(attributeMapping.feedAttributeId) = New HashSet(Of Long)() End If attributeMappings(attributeMapping.feedAttributeId).Add( attributeMapping.fieldId) Next Next End If Return attributeMappings End Using End Function
Now retrieve all of the FeedItems
for the Feed
and use the information from the FeedMapping
to populate the properties of helper objects:
Java
private static Map<Long, SiteLinkFromFeed> getSiteLinksFromFeed( AdWordsServicesInterface adWordsServices, AdWordsSession session, Feed feed) throws RemoteException { // Retrieve the feed's attribute mapping. Multimap<Long, Integer> feedMappings = getFeedMapping(adWordsServices, session, feed, PLACEHOLDER_SITELINKS); Map<Long, SiteLinkFromFeed> feedItems = Maps.newHashMap(); for (FeedItem feedItem : getFeedItems(adWordsServices, session, feed)) { SiteLinkFromFeed siteLinkFromFeed = new SiteLinkFromFeed(); for (FeedItemAttributeValue attributeValue : feedItem.getAttributeValues()) { // Skip this attribute if it hasn't been mapped to a field. if (!feedMappings.containsKey(attributeValue.getFeedAttributeId())) { continue; } for (Integer fieldId : feedMappings.get(attributeValue.getFeedAttributeId())) { switch (fieldId) { case PLACEHOLDER_FIELD_SITELINK_LINK_TEXT: siteLinkFromFeed.text = attributeValue.getStringValue(); break; case PLACEHOLDER_FIELD_SITELINK_URL: siteLinkFromFeed.url = attributeValue.getStringValue(); break; case PLACEHOLDER_FIELD_FINAL_URLS: siteLinkFromFeed.finalUrls = attributeValue.getStringValues(); break; case PLACEHOLDER_FIELD_FINAL_MOBILE_URLS: siteLinkFromFeed.finalMobileUrls = attributeValue.getStringValues(); break; case PLACEHOLDER_FIELD_TRACKING_URL_TEMPLATE: siteLinkFromFeed.trackingUrlTemplate = attributeValue.getStringValue(); break; case PLACEHOLDER_FIELD_LINE_2_TEXT: siteLinkFromFeed.line2 = attributeValue.getStringValue(); break; case PLACEHOLDER_FIELD_LINE_3_TEXT: siteLinkFromFeed.line3 = attributeValue.getStringValue(); break; default: // Ignore attributes that do not map to a predefined placeholder field. break; } } } feedItems.put(feedItem.getFeedItemId(), siteLinkFromFeed); } return feedItems; }
C#
private Dictionary<long, SiteLinkFromFeed> GetSiteLinksFromFeed(AdWordsUser user, long feedId) { Dictionary<long, SiteLinkFromFeed> siteLinks = new Dictionary<long, SiteLinkFromFeed>(); // Retrieve all the feed items from the feed. FeedItem[] feedItems = GetFeedItems(user, feedId); // Retrieve the feed's attribute mapping. Dictionary<long, HashSet<long>> feedMappings = GetFeedMapping(user, feedId, PLACEHOLDER_TYPE_SITELINKS); if (feedItems != null) { foreach (FeedItem feedItem in feedItems) { SiteLinkFromFeed sitelinkFromFeed = new SiteLinkFromFeed() { FeedId = feedItem.feedId, FeedItemId = feedItem.feedItemId }; foreach (FeedItemAttributeValue attributeValue in feedItem.attributeValues) { // This attribute hasn't been mapped to a field. if (!feedMappings.ContainsKey(attributeValue.feedAttributeId)) { continue; } // Get the list of all the fields to which this attribute has been mapped. foreach (long fieldId in feedMappings[attributeValue.feedAttributeId]) { // Read the appropriate value depending on the ID of the mapped // field. switch (fieldId) { 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.Line3 = attributeValue.stringValue; break; } } } siteLinks.Add(feedItem.feedItemId, sitelinkFromFeed); } } return siteLinks; }
Python
def GetSitelinksFromFeed(client, feed): """Gets the sitelinks from a feed. Args: client: an AdWordsClient instance. feed: the feed used to retrieve sitelinks. Returns: A dictionary mapping the feed item ID to SiteLinkFromFeed. """ # Retrieve the feed's attribute mapping. feed_mappings = GetFeedMapping(client, feed, PLACEHOLDER_TYPE_SITELINKS) feed_items = {} for feed_item in GetFeedItems(client, feed): site_link_from_feed = {} for attribute_value in feed_item['attributeValues']: if attribute_value['feedAttributeId'] in feed_mappings: for field_id in feed_mappings[attribute_value['feedAttributeId']]: if field_id == SITE_LINK_FIELDS['TEXT']: site_link_from_feed['text'] = attribute_value['stringValue'] elif field_id == SITE_LINK_FIELDS['URL']: site_link_from_feed['url'] = attribute_value['stringValue'] elif field_id == SITE_LINK_FIELDS['FINAL_URLS']: site_link_from_feed['finalUrls'] = attribute_value['stringValues'] elif field_id == SITE_LINK_FIELDS['FINAL_MOBILE_URLS']: site_link_from_feed['finalMobileUrls'] = attribute_value[ 'stringValues'] elif field_id == SITE_LINK_FIELDS['TRACKING_URL_TEMPLATE']: site_link_from_feed['trackingUrlTemplate'] = attribute_value[ 'stringValue'] elif field_id == SITE_LINK_FIELDS['LINE2']: site_link_from_feed['line2'] = attribute_value['stringValue'] elif field_id == SITE_LINK_FIELDS['LINE3']: site_link_from_feed['line3'] = attribute_value['stringValue'] else: print('No applicable Site Link Field found for Id: %s' % field_id) feed_items[feed_item['feedItemId']] = site_link_from_feed return feed_items
PHP
private static function getSitelinksFromFeed( AdWordsServices $adWordsServices, AdWordsSession $session, $feedId ) { printf("Processing feed ID %d...\n", $feedId); $sitelinks = []; // Retrieve all the feed items from the feed. $feedItems = self::getFeedItems($adWordsServices, $session, $feedId); if ($feedItems !== null) { // Retrieve the feed's attribute mapping. $attributeFieldMappings = self::getAttributeFieldMappings( $adWordsServices, $session, $feedId, self::PLACEHOLDER_TYPE_SITELINKS ); foreach ($feedItems as $feedItem) { $sitelinkFromFeed = new SitelinkFromFeed( $feedItem->getFeedId(), $feedItem->getFeedItemId() ); foreach ($feedItem->getAttributeValues() as $attributeValue) { // This attribute hasn't been mapped to a field. if (array_key_exists( $attributeValue->getFeedAttributeId(), $attributeFieldMappings ) === false) { continue; } // Get the list of all the fields to which this attribute has been // mapped. foreach ($attributeFieldMappings[$attributeValue->getFeedAttributeId()] as $fieldId) { // Read the appropriate value depending on the ID of the mapped // field. switch ($fieldId) { case self::PLACEHOLDER_FIELD_TEXT: $sitelinkFromFeed->setText($attributeValue->getStringValue()); break; case self::PLACEHOLDER_FIELD_URL: $sitelinkFromFeed->setUrl($attributeValue->getStringValue()); break; case self::PLACEHOLDER_FIELD_FINAL_URLS: $sitelinkFromFeed->setFinalUrls( $attributeValue->getStringValues() ); break; case self::PLACEHOLDER_FIELD_FINAL_MOBILE_URLS: $sitelinkFromFeed->setFinalMobileUrls( $attributeValue->getStringValues() ); break; case self::PLACEHOLDER_FIELD_TRACKING_URL_TEMPLATE: $sitelinkFromFeed->setTrackingUrlTemplate( $attributeValue->getStringValue() ); break; case self::PLACEHOLDER_FIELD_LINE2: $sitelinkFromFeed->setLine2($attributeValue->getStringValue()); break; case self::PLACEHOLDER_FIELD_LINE3: $sitelinkFromFeed->setLine3($attributeValue->getStringValue()); break; } } } $sitelinks[$feedItem->getFeedItemId()] = $sitelinkFromFeed; } } return $sitelinks; }
Perl
sub get_sitelinks_from_feed() { my ($client, $feed) = @_; my $feed_attribute_mappings = get_feed_mapping_attributes($client, $feed, PLACEHOLDER_SITELINKS); my $feed_items_by_id = {}; foreach my $feed_item (@{get_feed_items($client, $feed)}) { my $attributes = {}; foreach my $attribute_value (@{$feed_item->get_attributeValues()}) { my $field_ids = $feed_attribute_mappings->{$attribute_value->get_feedAttributeId()}; if ($field_ids) { foreach my $field_id (@{$field_ids}) { if ($field_id == PLACEHOLDER_FIELD_SITELINK_LINK_TEXT) { $attributes->{'text'} = $attribute_value->get_stringValue(); } elsif ($field_id == PLACEHOLDER_FIELD_SITELINK_URL) { $attributes->{'url'} = $attribute_value->get_stringValue(); } elsif ($field_id == PLACEHOLDER_FIELD_SITELINK_FINAL_URLS) { $attributes->{'final_urls'} = $attribute_value->get_stringValues(); } elsif ($field_id == PLACEHOLDER_FIELD_SITELINK_FINAL_MOBILE_URLS) { $attributes->{'final_mobile_urls'} = $attribute_value->get_stringValue(); } elsif ($field_id == PLACEHOLDER_FIELD_SITELINK_TRACKING_TEMPLATE) { $attributes->{'tracking_url_template'} = $attribute_value->get_stringValue(); } elsif ($field_id == PLACEHOLDER_FIELD_SITELINK_LINE_1_TEXT) { $attributes->{'line_1'} = $attribute_value->get_stringValue(); } elsif ($field_id == PLACEHOLDER_FIELD_SITELINK_LINE_2_TEXT) { $attributes->{'line_2'} = $attribute_value->get_stringValue(); } } } } $feed_items_by_id->{$feed_item->get_feedItemId()} = $attributes; } return $feed_items_by_id; }
Ruby
def get_site_links_from_feed(adwords, feed) # Retrieve the feed's attribute mapping. feed_mappings = get_feed_mapping(adwords, feed, PLACEHOLDER_SITELINKS) feed_items = {} get_feed_items(adwords, feed).each do |feed_item| site_link_from_feed = {} feed_item[:attribute_values].each do |attribute_value| # Skip this attribute if it hasn't been mapped to a field. next unless feed_mappings.has_key?( attribute_value[:feed_attribute_id]) feed_mappings[attribute_value[:feed_attribute_id]].each do |field_id| case field_id when PLACEHOLDER_FIELD_SITELINK_LINK_TEXT site_link_from_feed[:text] = attribute_value[:string_value] when PLACEHOLDER_FIELD_SITELINK_URL site_link_from_feed[:url] = attribute_value[:string_value] when PLACEHOLDER_FIELD_FINAL_URLS site_link_from_feed[:final_urls] = attribute_value[:string_values] when PLACEHOLDER_FIELD_FINAL_MOBILE_URLS site_link_from_feed[:final_mobile_urls] = attribute_value[:string_values] when PLACEHOLDER_FIELD_TRACKING_URL_TEMPLATE site_link_from_feed[:tracking_url_template] = attribute_value[:string_value] when PLACEHOLDER_FIELD_LINE_2_TEXT site_link_from_feed[:line2] = attribute_value[:string_value] when PLACEHOLDER_FIELD_LINE_3_TEXT site_link_from_feed[:line3] = attribute_value[:string_value] end end end feed_items[feed_item[:feed_item_id]] = site_link_from_feed end return feed_items end
VB.NET
''' <summary> ''' Gets the site links from a feed. ''' </summary> ''' <param name="user">The user that owns the feed.</param> ''' <param name="feedId">The feed ID.</param> ''' <returns>A dictionary of sitelinks from the feed, with key as the feed ''' item ID, and value as the sitelink.</returns> Private Function GetSiteLinksFromFeed(ByVal user As AdWordsUser, ByVal feedId As Long) As _ Dictionary(Of Long, SiteLinkFromFeed) Dim siteLinks As New Dictionary(Of Long, SiteLinkFromFeed)() ' Retrieve all the feed items from the feed. Dim feedItems As FeedItem() = GetFeedItems(user, feedId) ' Retrieve the feed's attribute mapping. Dim feedMappings As Dictionary(Of Long, HashSet(Of Long)) = GetFeedMapping(user, feedId, PLACEHOLDER_TYPE_SITELINKS) If Not feedItems Is Nothing Then For Each feedItem As FeedItem In feedItems Dim sitelinkFromFeed As New SiteLinkFromFeed() sitelinkFromFeed.FeedId = feedItem.feedId sitelinkFromFeed.FeedItemId = feedItem.feedItemId For Each attributeValue As FeedItemAttributeValue In feedItem.attributeValues ' This attribute hasn't been mapped to a field. If Not feedMappings.ContainsKey(attributeValue.feedAttributeId) Then Continue For End If ' Get the list of all the fields to which this attribute has been mapped. For Each fieldId As Long In feedMappings(attributeValue.feedAttributeId) ' Read the appropriate value depending on the ID of the mapped ' field. Select Case fieldId Case SiteLinkFields.TEXT sitelinkFromFeed.Text = attributeValue.stringValue Case SiteLinkFields.URL sitelinkFromFeed.Url = attributeValue.stringValue Case SiteLinkFields.FINAL_URLS sitelinkFromFeed.FinalUrls = attributeValue.stringValues Case SiteLinkFields.FINAL_MOBILE_URLS sitelinkFromFeed.FinalMobileUrls = attributeValue.stringValues Case SiteLinkFields.TRACKING_URL_TEMPLATE sitelinkFromFeed.TrackingUrlTemplate = attributeValue.stringValue Case SiteLinkFields.LINE2 sitelinkFromFeed.Line2 = attributeValue.stringValue Case SiteLinkFields.LINE3 sitelinkFromFeed.Line3 = attributeValue.stringValue End Select Next Next siteLinks.Add(feedItem.feedItemId, sitelinkFromFeed) Next End If Return siteLinks End Function
Identify feed items you want to keep
Identify the list of feed items associated with a campaign by retrieving the
CampaignFeed
associated with the campaign and parsing its
matchingFunction
.
Since matching functions allow you to write a general-purpose expression
tree, writing a parser for a general case is complex, and we won't cover
it in this guide. We'll instead pick the simplest case, where a few
feed items from a single feed have been associated with a campaign.
This matching function takes the following form:
FEEDITEM_ID IN (FEEDITEM_ID_1, FEEDITEM_ID_2…)
Java
/** * Returns the list of feed item IDs that are used by a campaign through a given campaign feed. */ private static Set<Long> getFeedItemIdsForCampaign(CampaignFeed campaignFeed) throws RemoteException { Set<Long> feedItemIds = Sets.newHashSet(); FunctionOperator functionOperator = campaignFeed.getMatchingFunction().getOperator(); if (FunctionOperator.IN.equals(functionOperator)) { // Check if matchingFunction is of the form IN(FEED_ITEM_ID,{xxx,xxx}). // Extract feed items if applicable. feedItemIds.addAll(getFeedItemIdsFromArgument(campaignFeed.getMatchingFunction())); } else if (FunctionOperator.AND.equals(functionOperator)) { // Check if matchingFunction is of the form IN(FEED_ITEM_ID,{xxx,xxx}). // Extract feed items if applicable. Arrays.stream(campaignFeed.getMatchingFunction().getLhsOperand()) .filter(FunctionOperand.class::isInstance) .map(argument -> (FunctionOperand) argument) .filter(operand -> FunctionOperator.IN.equals(operand.getValue().getOperator())) .forEach(operand -> feedItemIds.addAll(getFeedItemIdsFromArgument(operand.getValue()))); } else { // There are no other matching functions involving feed item IDs. } return feedItemIds; } /** * Gets the set of feed item IDs from the function if it is of the form: * <code>IN(FEED_ITEM_ID,{xxx,xxx})</code>. Otherwise, returns an empty set. */ private static Set<Long> getFeedItemIdsFromArgument(Function function) { if (function.getLhsOperand().length == 1 && function.getLhsOperand(0) instanceof RequestContextOperand) { RequestContextOperand requestContextOperand = (RequestContextOperand) function.getLhsOperand(0); if (RequestContextOperandContextType.FEED_ITEM_ID.equals( requestContextOperand.getContextType()) && FunctionOperator.IN.equals(function.getOperator())) { return Arrays.stream(function.getRhsOperand()) .filter(ConstantOperand.class::isInstance) .map(argument -> ((ConstantOperand) argument).getLongValue()) .collect(Collectors.toSet()); } } return new HashSet<>(); }
C#
/// <summary> /// Gets the list of feed items that are used by a campaign through a given /// campaign feed. /// </summary> /// <param name="campaignFeed">The campaign feed.</param> /// <returns>The list of feed items.</returns> private List<long> GetFeedItemsForCampaign(CampaignFeed campaignFeed) { List<long> feedItems = new List<long>(); switch (campaignFeed.matchingFunction.@operator) { case FunctionOperator.IN: // Check if matchingFunction is of the form IN(FEED_ITEM_ID,{xxx,xxx}). // Extract feedItems if applicable. feedItems.AddRange(GetFeedItemsFromArgument(campaignFeed.matchingFunction)); break; case FunctionOperator.AND: // Check each condition. foreach (FunctionArgumentOperand argument in campaignFeed.matchingFunction .lhsOperand) { // Check if matchingFunction is of the form IN(FEED_ITEM_ID,{xxx,xxx}). // Extract feedItems if applicable. if (argument is FunctionOperand) { FunctionOperand operand = (argument as FunctionOperand); if (operand.value.@operator == FunctionOperator.IN) { feedItems.AddRange(GetFeedItemsFromArgument(operand.value)); } } } break; default: // There are no other matching functions involving feeditem ids. break; } return feedItems; } private List<long> GetFeedItemsFromArgument(Function function) { List<long> feedItems = new List<long>(); if (function.lhsOperand.Length == 1) { RequestContextOperand requestContextOperand = function.lhsOperand[0] as RequestContextOperand; if (requestContextOperand != null && requestContextOperand.contextType == RequestContextOperandContextType.FEED_ITEM_ID) { foreach (ConstantOperand argument in function.rhsOperand) { feedItems.Add(argument.longValue); } } } return feedItems; }
Python
def GetFeedItemIdsForCampaign(campaign_feed): """Gets the Feed Item Ids used by a campaign through a given Campaign Feed. Args: campaign_feed: the Campaign Feed we are retrieving Feed Item Ids from. Returns: A list of Feed Item IDs. """ feed_item_ids = set() try: lhs_operand = campaign_feed['matchingFunction']['lhsOperand'] except KeyError: lhs_operand = None if (lhs_operand and lhs_operand[0]['FunctionArgumentOperand.Type'] == 'RequestContextOperand'): request_context_operand = lhs_operand[0] if (request_context_operand['contextType'] == 'FEED_ITEM_ID' and campaign_feed['matchingFunction']['operator'] == 'IN'): for argument in campaign_feed['matchingFunction']['rhsOperand']: if argument['xsi_type'] == 'ConstantOperand': feed_item_ids.add(argument['longValue']) return feed_item_ids
PHP
/** * Gets feed item IDs from the specified campaign feed. */ private static function getFeedItemIdsForCampaignFeed($campaignFeed) { $feedItemIds = []; if ($campaignFeed->getMatchingFunction()->getOperator() === FunctionOperator::IN) { // Check if matchingFunction is of the form IN(FEED_ITEM_ID,{xxx,xxx}). // Extract feed items if applicable. $feedItemIds = array_merge( $feedItemIds, self::getFeedItemIdsFromArgument($campaignFeed->getMatchingFunction()) ); } elseif ($campaignFeed->getMatchingFunction()->getOperator() === FunctionOperator::AND_VALUE) { foreach ($campaignFeed->getMatchingFunction()->getLhsOperand() as $argument) { // Check if matchingFunction is of the form IN(FEED_ITEM_ID,{xxx,xxx}). // Extract feed items if applicable. if ($argument instanceof FunctionOperand) { if ($argument->getValue()->getOperator() === FunctionOperator::IN) { $feedItemIds = array_merge( $feedItemIds, self::getFeedItemIdsFromArgument($argument->getValue()) ); } } } } return $feedItemIds; } /** * Gets feed item IDs from the specified function argument. */ private static function getFeedItemIdsFromArgument($function) { $feedItemIds = []; if (count($function->getLhsOperand()) === 1 && $function->getLhsOperand()[0] instanceof RequestContextOperand && $function->getLhsOperand()[0]->getContextType() === RequestContextOperandContextType::FEED_ITEM_ID && $function->getOperator() === FunctionOperator::IN) { foreach ($function->getRhsOperand() as $argument) { $feedItemIds[] = $argument->getLongValue(); } } return $feedItemIds; }
Perl
sub get_feed_item_ids_for_campaign() { my ($client, $campaign_feed) = @_; my @feed_item_ids = (); my $matching_function = $campaign_feed->get_matchingFunction(); my $operator = $matching_function->get_operator(); if ($operator eq 'IN') { # Check if matchingFunction is of the form IN(FEED_ITEM_ID,{xxx,xxx}). push @feed_item_ids, @{get_feed_items_from_argument($campaign_feed->get_matchingFunction())}; } elsif ($operator eq 'AND') { foreach my $argument (@{$matching_function->get_lhsOperand()}) { # Check if matchingFunction is of the form IN(FEED_ITEM_ID,{xxx,xxx}). if ( $argument->isa("Google::Ads::AdWords::v201809::FunctionOperand") && $argument->get_value()->get_operator() eq 'IN') { push @feed_item_ids, @{get_feed_items_from_argument($argument->get_value())}; } } } return \@feed_item_ids; } # Returns an array of feed item ids for a specified Function. sub get_feed_items_from_argument() { my ($function) = @_; my @feed_item_ids = (); my $lhs_operand = $function->get_lhsOperand(); my $lhs_operand_size = @{$lhs_operand}; if ( $lhs_operand_size == 1 && $lhs_operand->[0] ->isa("Google::Ads::AdWords::v201809::RequestContextOperand") && $lhs_operand->get_contextType eq 'FEED_ITEM_ID') { foreach my $argument (@{$function->get_rhsOperand()}) { push @feed_item_ids, $argument->get_longValue(); } } return \@feed_item_ids; }
Ruby
def get_feed_item_ids_for_campaign(campaign_feed) feed_item_ids = Set.new if !campaign_feed[:matching_function][:lhs_operand].empty? && campaign_feed[:matching_function][:lhs_operand].first[:xsi_type] == 'RequestContextOperand' request_context_operand = campaign_feed[:matching_function][:lhs_operand].first if request_context_operand[:context_type] == 'FEED_ITEM_ID' && campaign_feed[:matching_function][:operator] == 'IN' campaign_feed[:matching_function][:rhs_operand].each do |argument| if argument[:xsi_type] == 'ConstantOperand' feed_item_ids.add(argument[:long_value]) end end end end return feed_item_ids end
VB.NET
''' <summary> ''' Gets the list of feed items that are used by a campaign through a given ''' campaign feed. ''' </summary> ''' <param name="campaignFeed">The campaign feed.</param> ''' <returns>The list of feed items.</returns> Private Function GetFeedItemsForCampaign(ByVal campaignFeed As CampaignFeed) _ As List(Of Long) Dim feedItems As New List(Of Long)() Select Case campaignFeed.matchingFunction.operator Case FunctionOperator.IN ' Check if matchingFunction is of the form IN(FEED_ITEM_ID,{xxx,xxx}). ' Extract feedItems if applicable. feedItems.AddRange(GetFeedItemsFromArgument(campaignFeed.matchingFunction)) Case FunctionOperator.AND ' Check each condition. For Each argument As FunctionArgumentOperand In _ campaignFeed.matchingFunction.lhsOperand ' Check if matchingFunction is of the form IN(FEED_ITEM_ID,{xxx,xxx}). ' Extract feedItems if applicable. If TypeOf argument Is FunctionOperand Then Dim operand As FunctionOperand = CType(argument, FunctionOperand) If operand.value.operator = FunctionOperator.IN Then feedItems.AddRange(GetFeedItemsFromArgument(operand.value)) End If End If Next Case Else ' There are no other matching functions involving feeditem ids. End Select Return feedItems End Function Private Function GetFeedItemsFromArgument(ByVal func As [Function]) As List(Of Long) Dim feedItems As New List(Of Long)() If func.lhsOperand.Length = 1 Then Dim requestContextOperand As RequestContextOperand = CType(func.lhsOperand(0), RequestContextOperand) If Not (requestContextOperand Is Nothing) AndAlso (requestContextOperand.contextType = RequestContextOperandContextType.FEED_ITEM_ID) Then For Each argument As ConstantOperand In func.rhsOperand feedItems.Add(argument.longValue) Next End If End If Return feedItems End Function
Delete existing CampaignFeed
Before you add extension settings to a campaign, you must delete
the campaign's existing CampaignFeed
. This is required since AdWords
supports only one CampaignFeed
per extension type for a campaign. Deleting
your manually-created CampaignFeed
allows the
CampaignExtensionSettingService
to create a new system-managed CampaignFeed
when you add extension settings.
Java
private static CampaignFeed deleteCampaignFeed(AdWordsServicesInterface adWordsServices, AdWordsSession session, CampaignFeed campaignFeed) throws RemoteException { // Get the CampaignFeedService. CampaignFeedServiceInterface campaignFeedService = adWordsServices.get(session, CampaignFeedServiceInterface.class); CampaignFeedOperation operation = new CampaignFeedOperation(); operation.setOperand(campaignFeed); operation.setOperator(Operator.REMOVE); return campaignFeedService.mutate(new CampaignFeedOperation[] {operation}).getValue(0); }
C#
private CampaignFeed DeleteCampaignFeed(AdWordsUser user, CampaignFeed campaignFeed) { using (CampaignFeedService campaignFeedService = (CampaignFeedService) user.GetService(AdWordsService.v201809.CampaignFeedService)) { CampaignFeedOperation operation = new CampaignFeedOperation() { operand = campaignFeed, @operator = Operator.REMOVE }; CampaignFeed retval = campaignFeedService.mutate(new CampaignFeedOperation[] { operation }).value[0]; return retval; } }
Python
def DeleteCampaignFeed(client, campaign_feed): """Deletes a campaign feed. Args: client: an AdWordsClient instance. campaign_feed: the campaign feed to delete. """ campaign_feed_service = client.GetService('CampaignFeedService', 'v201809') operation = { 'operand': campaign_feed, 'operator': 'REMOVE' } campaign_feed_service.mutate([operation])
PHP
private static function deleteCampaignFeed( AdWordsServices $adWordsServices, AdWordsSession $session, $campaignFeed ) { $campaignFeedService = $adWordsServices->get($session, CampaignFeedService::class); printf( "Deleting association of feed ID %d and campaign ID %d...\n", $campaignFeed->getFeedId(), $campaignFeed->getCampaignId() ); $operation = new CampaignFeedOperation(); $operation->setOperand($campaignFeed); $operation->setOperator(Operator::REMOVE); return $campaignFeedService->mutate([$operation]); }
Perl
sub delete_campaign_feed() { my ($client, $campaign_feed) = @_; my $result = $client->CampaignFeedService()->mutate({ operations => [ Google::Ads::AdWords::v201809::CampaignFeedOperation->new({ operand => $campaign_feed, operator => 'REMOVE' })]}); printf "Deleted campaign feed for campaign ID %d and feed ID %d.\n", $campaign_feed->get_campaignId(), $campaign_feed->get_feedId(); return $result->get_value(0); }
Ruby
def delete_campaign_feed(adwords, campaign_feed) campaign_feed_srv = adwords.service(:CampaignFeedService, API_VERSION) operation = { :operand => campaign_feed, :operator => 'REMOVE' } campaign_feed_srv.mutate([operation]) end
VB.NET
''' <summary> ''' Deletes a campaign feed. ''' </summary> ''' <param name="user">The AdWords user.</param> ''' <param name="campaignFeed">The campaign feed.</param> ''' <returns></returns> Private Function DeleteCampaignFeed(ByVal user As AdWordsUser, ByVal campaignFeed As CampaignFeed) As CampaignFeed Using campaignFeedService As CampaignFeedService = DirectCast( user.GetService( AdWordsService.v201809.CampaignFeedService), CampaignFeedService) Dim operation As New CampaignFeedOperation() operation.operand = campaignFeed operation.operator = [Operator].REMOVE Return campaignFeedService.mutate(New CampaignFeedOperation() {operation}).value(0) End Using End Function
Add extension settings
You can now create extension settings corresponding to the old feed items:
Java
private static void createExtensionSetting(AdWordsServicesInterface adWordsServices, AdWordsSession session, Map<Long, SiteLinkFromFeed> feedItems, CampaignFeed campaignFeed, Set<Long> feedItemIds, ExtensionSettingPlatform platformRestrictions) throws RemoteException { // Get the CampaignExtensionSettingService. CampaignExtensionSettingServiceInterface campaignExtensionSettingService = adWordsServices.get(session, CampaignExtensionSettingServiceInterface.class); CampaignExtensionSetting campaignExtensionSetting = new CampaignExtensionSetting(); campaignExtensionSetting.setCampaignId(campaignFeed.getCampaignId()); campaignExtensionSetting.setExtensionType(FeedType.SITELINK); ExtensionSetting extensionSetting = new ExtensionSetting(); List<ExtensionFeedItem> extensionFeedItems = new ArrayList<>(); for (Long feedItemId : feedItemIds) { SiteLinkFromFeed siteLinkFromFeed = feedItems.get(feedItemId); SitelinkFeedItem siteLinkFeedItem = new SitelinkFeedItem(); siteLinkFeedItem.setSitelinkText(siteLinkFromFeed.text); if (siteLinkFromFeed.finalUrls != null && siteLinkFromFeed.finalUrls.length > 0) { siteLinkFeedItem.setSitelinkFinalUrls(new UrlList(siteLinkFromFeed.finalUrls)); if (siteLinkFromFeed.finalMobileUrls != null && siteLinkFromFeed.finalMobileUrls.length > 0) { siteLinkFeedItem.setSitelinkFinalMobileUrls( new UrlList(siteLinkFromFeed.finalMobileUrls)); } siteLinkFeedItem.setSitelinkTrackingUrlTemplate(siteLinkFromFeed.trackingUrlTemplate); } else { siteLinkFeedItem.setSitelinkUrl(siteLinkFromFeed.url); } siteLinkFeedItem.setSitelinkLine2(siteLinkFromFeed.line2); siteLinkFeedItem.setSitelinkLine3(siteLinkFromFeed.line3); extensionFeedItems.add(siteLinkFeedItem); } extensionSetting.setExtensions( extensionFeedItems.toArray(new ExtensionFeedItem[extensionFeedItems.size()])); extensionSetting.setPlatformRestrictions(platformRestrictions); campaignExtensionSetting.setExtensionSetting(extensionSetting); CampaignExtensionSettingOperation operation = new CampaignExtensionSettingOperation(); operation.setOperand(campaignExtensionSetting); operation.setOperator(Operator.ADD); campaignExtensionSettingService.mutate(new CampaignExtensionSettingOperation[] {operation}); }
C#
private static void CreateExtensionSetting(AdWordsUser user, Dictionary<long, SiteLinkFromFeed> feedItems, long campaignId, List<long> feedItemIds, ExtensionSettingPlatform platformRestrictions) { CampaignExtensionSetting extensionSetting = new CampaignExtensionSetting() { campaignId = 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 = new UrlList() { urls = feedItem.FinalUrls }, sitelinkFinalMobileUrls = new UrlList() { urls = feedItem.FinalMobileUrls }, sitelinkTrackingUrlTemplate = feedItem.TrackingUrlTemplate, sitelinkLine2 = feedItem.Line2, sitelinkLine3 = feedItem.Line3 }; extensionFeedItems.Add(newFeedItem); } extensionSetting.extensionSetting.extensions = extensionFeedItems.ToArray(); extensionSetting.extensionSetting.platformRestrictions = platformRestrictions; extensionSetting.extensionType = FeedType.SITELINK; using (CampaignExtensionSettingService campaignExtensionSettingService = (CampaignExtensionSettingService) user.GetService(AdWordsService.v201809 .CampaignExtensionSettingService)) { CampaignExtensionSettingOperation operation = new CampaignExtensionSettingOperation() { operand = extensionSetting, @operator = Operator.ADD }; campaignExtensionSettingService.mutate(new CampaignExtensionSettingOperation[] { operation }); } return; }
Python
def CreateExtensionSetting(client, feed_items, campaign_feed, feed_item_ids, platform_restrictions=None): """Creates the extension setting for a list of Feed Items. Args: client: an AdWordsClient instance. feed_items: the list of all Feed Items. campaign_feed: the original Campaign Feed. feed_item_ids: the Ids of the feed items for which extension settings should be created. platform_restrictions: an optional Platform Restriction for the Feed items. """ campaign_extension_setting_service = client.GetService( 'CampaignExtensionSettingService', 'v201809') extension_feed_items = [{ CreateSitelinkFeedItem(feed_items, feed_item_id) } for feed_item_id in feed_item_ids] extension_setting = { 'extensions': extension_feed_items } if platform_restrictions: extension_setting['platformRestrictions'] = platform_restrictions campaign_extension_setting = { 'campaignId': campaign_feed['campaignId'], 'extensionType': 'SITELINK', 'extensionSetting': extension_setting } operation = { 'operand': campaign_extension_setting, 'operator': 'ADD' } campaign_extension_setting_service.mutate([operation])
PHP
private static function createExtensionSetting( AdWordsServices $adWordsServices, AdWordsSession $session, array $sitelinksFromFeed, $campaignId, array $feedItemIds, $platformRestrictions ) { $campaignExtensionSettingService = $adWordsServices->get($session, CampaignExtensionSettingService::class); $extensionSetting = new CampaignExtensionSetting(); $extensionSetting->setCampaignId($campaignId); $extensionSetting->setExtensionType(FeedType::SITELINK); $extensionSetting->setExtensionSetting(new ExtensionSetting()); $extensionFeedItems = []; foreach ($feedItemIds as $feedItemId) { $sitelink = $sitelinksFromFeed[$feedItemId]; $newFeedItem = new SitelinkFeedItem(); $newFeedItem->setSitelinkText($sitelink->getText()); $newFeedItem->setSitelinkUrl($sitelink->getUrl()); $newFeedItem->setSitelinkLine2($sitelink->getLine2()); $newFeedItem->setSitelinkLine3($sitelink->getLine3()); $newFeedItem->setSitelinkFinalUrls($sitelink->getFinalUrls()); $newFeedItem->setSitelinkFinalMobileUrls($sitelink->getFinalMobileUrls()); $newFeedItem->setSitelinkTrackingUrlTemplate( $sitelink->getTrackingUrlTemplate() ); $extensionFeedItems[] = $newFeedItem; } $extensionSetting->getExtensionSetting()->setExtensions( $extensionFeedItems ); $extensionSetting->getExtensionSetting()->setPlatformRestrictions( $platformRestrictions ); $operation = new CampaignExtensionSettingOperation(); $operation->setOperand($extensionSetting); $operation->setOperator(Operator::ADD); printf( "Adding %d sitelinks for campaign ID %d...\n", count($feedItemIds), $campaignId ); return $campaignExtensionSettingService->mutate([$operation]); }
Perl
sub create_extension_setting() { my ($client, $feed_items, $campaign_feed, $feed_item_ids, $platform_restriction) = @_; my $campaign_extension_setting = Google::Ads::AdWords::v201809::CampaignExtensionSetting->new({ campaignId => $campaign_feed->get_campaignId(), extensionType => 'SITELINK' }); my @extension_feed_items = (); foreach my $feed_item_id (@{$feed_item_ids}) { my $item_attributes = $feed_items->{$feed_item_id}; my $sitelink_feed_item = Google::Ads::AdWords::v201809::SitelinkFeedItem->new({ sitelinkText => $item_attributes->{'text'}, sitelinkLine2 => $item_attributes->{'line_1'}, sitelinkLine3 => $item_attributes->{'line_2'}}); if ($item_attributes->{'final_urls'}) { $sitelink_feed_item->set_sitelinkFinalUrls( Google::Ads::AdWords::v201809::UrlList->new( {urls => $item_attributes->{'final_urls'}})); if ($item_attributes->{'final_mobile_urls'}) { $sitelink_feed_item->set_sitelinkFinalMobileUrls( Google::Ads::AdWords::v201809::UrlList->new( {urls => $item_attributes->{'final_mobile_urls'}})); } if ($item_attributes->{'tracking_url_template'}) { $sitelink_feed_item->set_trackingUrlTemplate( $item_attributes->{'tracking_url_template'}); } } else { $sitelink_feed_item->set_sitelinkUrl($item_attributes->{'url'}); } push @extension_feed_items, $sitelink_feed_item; } $campaign_extension_setting->set_extensionSetting( Google::Ads::AdWords::v201809::ExtensionSetting->new({ extensions => \@extension_feed_items, platformRestrictions => $platform_restriction })); my $result = $client->CampaignExtensionSettingService()->mutate({ operations => [ Google::Ads::AdWords::v201809::CampaignExtensionSettingOperation->new({ operand => $campaign_extension_setting, operator => 'ADD' })]}); printf "Created extension setting for campaign ID %d.\n", $campaign_feed->get_campaignId(); return $result->get_value(0); }
Ruby
def create_extension_setting( adwords, feed_items, campaign_feed, feed_item_ids, platform_restrictions) campaign_extension_setting_srv = adwords.service( :CampaignExtensionSettingService, API_VERSION) extension_feed_items = feed_item_ids.map do |feed_item_id| site_link_from_feed = feed_items[:feed_item_id] site_link_feed_item = { :sitelink_text => site_link_from_feed[:text], :sitelink_line2 => site_link_from_feed[:line2], :sitelink_line3 => site_link_from_feed[:line3] } if !site_link_from_feed.final_urls.nil? && site_link_from_feed[:final_urls].length > 0 site_link_feed_item[:sitelink_final_urls] = { :urls => site_link_from_feed[:final_urls] } unless site_link_from_feed[:final_mobile_urls].nil? site_link_feed_item[:sitelink_final_mobile_urls] = { :urls => site_link_from_feed[:final_mobile_urls] } end site_link_feed_item[:sitelink_tracking_url_template] = site_link_from_feed[:tracking_url_template] else site_link_feed_item[:sitelink_url] = site_link_from_feed[:url] end site_link_feed_item end extension_setting = { :extensions => extension_feed_items } unless platform_restrictions.nil? extension_setting[:platform_restrictions] = platform_restrictions end campaign_extension_setting = { :campaign_id => campaign_feed[:campaign_id], :extension_type => 'SITELINK', :extension_setting => extension_setting } operation = { :operand => campaign_extension_setting, :operator => 'ADD' } campaign_extension_setting_srv.mutate([operation]) end
VB.NET
''' <summary> ''' Creates the extension setting fo a list of feed items. ''' </summary> ''' <param name="user">The user for which extension settings are created. ''' </param> ''' <param name="feedItems">The list of all feed items.</param> ''' <param name="campaignId">ID of the campaign to which extension settings ''' are added.</param> ''' <param name="feedItemIds">IDs of the feed items for which extension ''' settings should be created.</param> ''' <param name="platformRestrictions">The platform restrictions for the ''' extension setting.</param> Private Sub CreateExtensionSetting(ByVal user As AdWordsUser, ByVal feedItems As _ Dictionary(Of Long, SiteLinkFromFeed), ByVal campaignId As Long, ByVal feedItemIds As List(Of Long), ByVal platformRestrictions As ExtensionSettingPlatform) Dim extensionSetting As New CampaignExtensionSetting() extensionSetting.campaignId = campaignId extensionSetting.extensionType = FeedType.SITELINK extensionSetting.extensionSetting = New ExtensionSetting() Dim extensionFeedItems As New List(Of ExtensionFeedItem)() For Each feedItemId As Long In feedItemIds Dim feedItem As SiteLinkFromFeed = feedItems(feedItemId) Dim newFeedItem As New SitelinkFeedItem() newFeedItem.sitelinkText = feedItem.Text newFeedItem.sitelinkUrl = feedItem.Url newFeedItem.sitelinkFinalUrls = New UrlList() newFeedItem.sitelinkFinalUrls.urls = feedItem.FinalUrls newFeedItem.sitelinkFinalMobileUrls = New UrlList() newFeedItem.sitelinkFinalMobileUrls.urls = feedItem.FinalMobileUrls newFeedItem.sitelinkTrackingUrlTemplate = feedItem.TrackingUrlTemplate newFeedItem.sitelinkLine2 = feedItem.Line2 newFeedItem.sitelinkLine3 = feedItem.Line3 extensionFeedItems.Add(newFeedItem) Next extensionSetting.extensionSetting.extensions = extensionFeedItems.ToArray() extensionSetting.extensionSetting.platformRestrictions = platformRestrictions extensionSetting.extensionType = FeedType.SITELINK Using campaignExtensionSettingService As CampaignExtensionSettingService = DirectCast(user.GetService(AdWordsService.v201809.CampaignExtensionSettingService), CampaignExtensionSettingService) Dim operation As New CampaignExtensionSettingOperation() operation.operand = extensionSetting operation.operator = [Operator].ADD campaignExtensionSettingService.mutate( New CampaignExtensionSettingOperation() {operation}) Return End Using End Sub
Keep in mind that this process does not de-duplicate the extension settings; you may want to enhance this code to exclude duplicate items.
Delete old FeedItems
Finally, delete the old FeedItems
:
Java
private static void deleteOldFeedItems( AdWordsServicesInterface adWordsServices, AdWordsSession session, Set<Long> feedItemIds, Feed feed) throws RemoteException { // Get the FeedItemService. FeedItemServiceInterface feedItemService = adWordsServices.get(session, FeedItemServiceInterface.class); if (feedItemIds.isEmpty()) { return; } List<FeedItemOperation> operations = new ArrayList<>(); for (Long feedItemId : feedItemIds) { FeedItemOperation operation = new FeedItemOperation(); FeedItem feedItem = new FeedItem(); feedItem.setFeedId(feed.getId()); feedItem.setFeedItemId(feedItemId); operation.setOperand(feedItem); operation.setOperator(Operator.REMOVE); operations.add(operation); } feedItemService.mutate(operations.toArray(new FeedItemOperation[operations.size()])); }
C#
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); } using (FeedItemService feedItemService = (FeedItemService) user.GetService(AdWordsService.v201809.FeedItemService)) { feedItemService.mutate(operations.ToArray()); return; } }
Python
def DeleteOldFeedItems(client, feed_item_ids, feed): """Deletes the old feed items for which extension settings have been created. Args: client: an AdWordsClient instance. feed_item_ids: a list of Feed Item Ids. feed: the Feed containing the given Feed Item Ids. """ if not feed_item_ids: return feed_item_service = client.GetService('FeedItemService', 'v201809') operations = [{ 'operator': 'REMOVE', 'operand': { 'feedId': feed['id'], 'feedItemId': feed_item_id } } for feed_item_id in feed_item_ids] feed_item_service.mutate(operations)
PHP
private static function deleteOldFeedItems( AdWordsServices $adWordsServices, AdWordsSession $session, $feedItemIds, $feedId ) { if (count($feedItemIds) === 0) { return; } $feedItemService = $adWordsServices->get($session, FeedItemService::class); $operations = []; foreach ($feedItemIds as $feedItemId) { $feedItem = new FeedItem(); $feedItem->setFeedId($feedId); $feedItem->setFeedItemId($feedItemId); $operation = new FeedItemOperation(); $operation->setOperand($feedItem); $operation->setOperator(Operator::REMOVE); $operations[] = $operation; } printf( "Deleting %d old feed items from feed ID %d...\n", count($feedItemIds), $feedId ); return $feedItemService->mutate($operations); }
Perl
sub delete_old_feed_items() { my ($client, $feed_item_ids, $feed) = @_; if (!@{$feed_item_ids}) { printf "No old feed items to delete for feed ID %d.\n", $feed->get_id(); return; } my @operations = (); foreach my $feed_item_id (@{$feed_item_ids}) { push @operations, Google::Ads::AdWords::v201809::FeedItemOperation->new({ operator => 'REMOVE', operand => Google::Ads::AdWords::v201809::FeedItem->new({ feedId => $feed->get_id(), feedItemId => $feed_item_id })}); } my $result = $client->FeedItemService()->mutate({operations => \@operations}); my $number_of_operations = @{$result->get_value()}; printf "Deleted %d old feed items from feed ID %d.\n", $number_of_operations, $feed->get_id(); }
Ruby
def delete_old_feed_items(adwords, feed_item_ids, feed) return if feed_item_ids.empty? feed_item_srv = adwords.service(:FeedItemService, API_VERSION) operations = feed_item_ids.map do |feed_item_id| { :operator => 'REMOVE', :operand => { :feed_id => feed[:id], :feed_item_id => feed_item_id } } end feed_item_srv.mutate(operations) end
VB.NET
''' <summary> ''' Deletes the old feed items for which extension settings have been ''' created. ''' </summary> ''' <param name="user">The user that owns the feed items.</param> ''' <param name="feedItemIds">IDs of the feed items to be removed.</param> ''' <param name="feedId">ID of the feed that holds the feed items.</param> Private Sub DeleteOldFeedItems(ByVal user As AdWordsUser, ByVal feedItemIds As List(Of Long), ByVal feedId As Long) If feedItemIds.Count = 0 Then Return End If Dim operations As New List(Of FeedItemOperation)() For Each feedItemId As Long In feedItemIds Dim operation As New FeedItemOperation() operation.operator = [Operator].REMOVE operation.operand = New FeedItem() operation.operand.feedItemId = feedItemId operation.operand.feedId = feedId operations.Add(operation) Next Using feedItemService As FeedItemService = DirectCast( user.GetService( AdWordsService.v201809.FeedItemService), FeedItemService) feedItemService.mutate(operations.ToArray()) Return End Using End Sub
This is an optional step, but we recommend deleting unused feed items to keep the number of active feed items under system limits.
Putting it all together: The main loop
The main loop of this program corresponds to the sequence of steps discussed earlier:
Java
// Get all of the feeds for the session's account. List<Feed> feeds = getFeeds(adWordsServices, session); for (Feed feed : feeds) { // Retrieve all the sitelinks from the current feed. Map<Long, SiteLinkFromFeed> feedItems = getSiteLinksFromFeed(adWordsServices, session, feed); // Get all the instances where a sitelink from this feed has been added to a campaign. List<CampaignFeed> campaignFeeds = getCampaignFeeds(adWordsServices, session, feed, PLACEHOLDER_SITELINKS); Set<Long> allFeedItemsToDelete = Sets.newHashSet(); for (CampaignFeed campaignFeed : campaignFeeds) { // Retrieve the sitelinks that have been associated with this campaign. Set<Long> feedItemIds = getFeedItemIdsForCampaign(campaignFeed); ExtensionSettingPlatform platformRestrictions = getPlatformRestictionsForCampaign(campaignFeed); if (feedItemIds.isEmpty()) { System.out.printf("Migration skipped for campaign feed with campaign ID %d " + "and feed ID %d because no mapped feed item IDs were found in the " + "campaign feed's matching function.%n", campaignFeed.getCampaignId(), campaignFeed.getFeedId()); } else { // Delete the campaign feed that associates the sitelinks from the feed to the campaign. deleteCampaignFeed(adWordsServices, session, campaignFeed); // Create extension settings instead of sitelinks. createExtensionSetting(adWordsServices, session, feedItems, campaignFeed, feedItemIds, platformRestrictions); // Mark the sitelinks from the feed for deletion. allFeedItemsToDelete.addAll(feedItemIds); } } // Delete all the sitelinks from the feed. deleteOldFeedItems(adWordsServices, session, allFeedItemsToDelete, feed); }
C#
// Get all the feeds from the user account. Feed[] feeds = GetFeeds(user); foreach (Feed feed in feeds) { // Retrieve all the sitelinks from the current feed. Dictionary<long, SiteLinkFromFeed> feedItems = GetSiteLinksFromFeed(user, feed.id); // Get all the instances where a sitelink from this feed has been added // to a campaign. CampaignFeed[] campaignFeeds = GetCampaignFeeds(user, feed, PLACEHOLDER_TYPE_SITELINKS); if (campaignFeeds != null) { HashSet<long> allFeedItemsToDelete = new HashSet<long>(); foreach (CampaignFeed campaignFeed in campaignFeeds) { // Retrieve the sitelinks that have been associated with this // campaign. List<long> feedItemIds = GetFeedItemsForCampaign(campaignFeed); ExtensionSettingPlatform platformRestrictions = GetPlatformRestrictionsForCampaign(campaignFeed); if (feedItemIds.Count == 0) { Console.WriteLine( "Migration skipped for campaign feed with campaign ID {0} and " + "feed ID {1} because no mapped feed item IDs were found in the " + "campaign feed's matching function.", campaignFeed.campaignId, campaignFeed.feedId); } else { // Delete the campaign feed that associates the sitelinks from the // feed to the campaign. DeleteCampaignFeed(user, campaignFeed); // Create extension settings instead of sitelinks. CreateExtensionSetting(user, feedItems, campaignFeed.campaignId, feedItemIds, platformRestrictions); // Mark the sitelinks from the feed for deletion. allFeedItemsToDelete.UnionWith(feedItemIds); } } // Delete all the sitelinks from the feed. DeleteOldFeedItems(user, new List<long>(allFeedItemsToDelete), feed.id); } }
Python
# Get all of the feeds for the current user. feeds = GetFeeds(client) for feed in feeds: # Retrieve all the sitelinks from the current feed. feed_items = GetSitelinksFromFeed(client, feed) # Get all the instances where a sitelink from this feed has been added to a # campaign. campaign_feeds = GetCampaignFeeds(client, feed, PLACEHOLDER_TYPE_SITELINKS) all_feed_items_to_delete = [] for campaign_feed in campaign_feeds: # Retrieve the sitelinks that have been associated with this Campaign. feed_item_ids = GetFeedItemIdsForCampaign(campaign_feed) if feed_item_ids == 0: print('Migration skipped for campaign feed with campaign ID %d ' 'and feed ID %d because no mapped feed item IDs were found in ' 'the campaign feed\'s matching function.' % (campaign_feed['campaign_id'], campaign_feed['feed_id'])) continue platform_restrictions = GetPlatformRestrictions(campaign_feed) # Delete the campaign feed that associates the sitelinks from the feed to # the Campaign. DeleteCampaignFeed(client, campaign_feed) # Create extension settings instead of sitelinks. CreateExtensionSetting(client, feed_items, campaign_feed, feed_item_ids, platform_restrictions) # Mark the sitelinks from the feed for deletion. all_feed_items_to_delete.extend(feed_item_ids) # Delete all the sitelinks from the feed. DeleteOldFeedItems(client, all_feed_items_to_delete, feed)
PHP
$feeds = self::getFeeds($adWordsServices, $session); foreach ($feeds as $feed) { // Retrieve all the sitelinks from the current feed. $sitelinksFromFeed = self::getSitelinksFromFeed( $adWordsServices, $session, $feed->getId() ); printf( "Loaded %d sitelinks for feed ID %d.\n", count($sitelinksFromFeed), $feed->getId() ); // Get all the instances where a sitelink from this feed has been added // to a campaign. $campaignFeeds = self::getCampaignFeeds( $adWordsServices, $session, $feed->getId(), self::PLACEHOLDER_TYPE_SITELINKS ); printf( "Loaded %d sitelink to campaign mappings for feed ID %d.\n", count($campaignFeeds), $feed->getId() ); if ($campaignFeeds !== null) { $allFeedItemsToDelete = []; foreach ($campaignFeeds as $campaignFeed) { // Retrieve the sitelinks that have been associated with this // campaign. $feedItemIds = self::getFeedItemIdsForCampaignFeed($campaignFeed); $platformRestrictions = self::getPlatformRestrictionsForCampaignFeed($campaignFeed); if ($feedItemIds === null) { printf( "Skipping feed ID %d for campaign %d -- matching function is " . "missing or too complex for this script.\n", $campaignFeed->getFeedId(), $campaignFeed->getCampaignId() ); continue; } // Delete the campaign feed that associates the sitelinks from the // feed to the campaign. self::deleteCampaignFeed($adWordsServices, $session, $campaignFeed); // Mark the sitelinks from the feed for deletion. $allFeedItemsToDelete = array_merge($allFeedItemsToDelete, $feedItemIds); // Create extension settings instead of sitelinks. self::createExtensionSetting( $adWordsServices, $session, $sitelinksFromFeed, $campaignFeed->getCampaignId(), $feedItemIds, $platformRestrictions ); } // Delete all the sitelinks from the feed. $allFeedItemsToDelete = array_unique($allFeedItemsToDelete); self::deleteOldFeedItems( $adWordsServices, $session, $allFeedItemsToDelete, $feed->getId() ); } }
Perl
my ($client) = @_; # Get all of the feeds for the client's account. my $feeds = get_feeds($client); foreach my $feed (@{$feeds}) { # Retrieve all the sitelinks from the current feed. my $feed_items = get_sitelinks_from_feed($client, $feed); # Get all the instances where a sitelink from this feed has been added to # a campaign. my $campaign_feeds = get_campaign_feeds($client, $feed, PLACEHOLDER_SITELINKS); my @all_feed_items_to_delete = (); foreach my $campaign_feed (@{$campaign_feeds}) { # Retrieve the sitelinks that have been associated with this campaign. my $feed_item_ids = get_feed_item_ids_for_campaign($client, $campaign_feed); my $platform_restriction = get_platform_restrictions_for_campaign($campaign_feed); if (@{$feed_item_ids}) { # Delete the campaign feed that associates the sitelinks from the feed # to the campaign. delete_campaign_feed($client, $campaign_feed); # Create extension settings instead of sitelinks. create_extension_setting($client, $feed_items, $campaign_feed, $feed_item_ids, $platform_restriction); # Mark the sitelinks from the feed for deletion. push @all_feed_items_to_delete, @{$feed_item_ids}; } else { printf "Migration skipped for campaign feed with campaign ID %d " . "and feed ID %d because no mapped feed item IDs were found in " . "the campaign feed's matching function.\n", $campaign_feed->get_campaignId(), $campaign_feed->get_feedId(); } } # Delete all the sitelinks from the feed. delete_old_feed_items($client, \@all_feed_items_to_delete, $feed); printf "Finished processing feed ID %d.\n", $feed->get_id(); }
Ruby
# Get all of the feeds for the current user. feeds = get_feeds(adwords) feeds.each do |feed| # Retrieve all the sitelinks from the current feed. feed_items = get_site_links_from_feed(adwords, feed) # Get all the instances where a sitelink from this feed has been added # to a campaign. campaign_feeds = get_campaign_feeds(adwords, feed, PLACEHOLDER_SITELINKS) all_feed_items_to_delete = campaign_feeds.map do |campaign_feed| # Retrieve the sitelinks that have been associated with this campaign. feed_item_ids = get_feed_item_ids_for_campaign(campaign_feed) if feed_item_ids.empty? puts(("Migration skipped for campaign feed with campaign ID %d " + "and feed ID %d because no mapped feed item IDs were found in " + "the campaign feed's matching function.") % [campaign_feed[:campaign_id], campaign_feed[:feed_id]]) next end platform_restrictions = get_platform_restrictions(campaign_feed) # Delete the campaign feed that associates the sitelinks from the # feed to the campaign. delete_campaign_feed(adwords, campaign_feed) # Create extension settings instead of sitelinks. create_extension_setting(adwords, feed_items, campaign_feed, feed_item_ids, platform_restrictions) # Mark the sitelinks from the feed for deletion. feed_item_ids end.flatten.to_set.reject {|id| id.nil?} # Delete all the sitelinks from the feed. delete_old_feed_items(adwords, all_feed_items_to_delete, feed) end
VB.NET
' Get all the feeds from the user account. Dim feeds As Feed() = GetFeeds(user) For Each feed As Feed In feeds ' Retrieve all the sitelinks from the current feed. Dim feedItems As Dictionary(Of Long, SiteLinkFromFeed) = GetSiteLinksFromFeed(user, feed.id) ' Get all the instances where a sitelink from this feed has been added ' to a campaign. Dim campaignFeeds As CampaignFeed() = GetCampaignFeeds(user, feed, PLACEHOLDER_TYPE_SITELINKS) If Not campaignFeeds Is Nothing Then Dim allFeedItemsToDelete As New HashSet(Of Long)() For Each campaignFeed As CampaignFeed In campaignFeeds ' Retrieve the sitelinks that have been associated with this ' campaign. Dim feedItemIds As List(Of Long) = GetFeedItemsForCampaign(campaignFeed) Dim platformRestrictions As ExtensionSettingPlatform = GetPlatformRestrictionsForCampaign(campaignFeed) If feedItemIds.Count = 0 Then Console.WriteLine( "Migration skipped for campaign feed with campaign ID {0} " & "and feed ID {1} because no mapped feed item IDs were found in " & "the campaign feed's matching function.", campaignFeed.campaignId, campaignFeed.feedId) Else ' Delete the campaign feed that associates the sitelinks from the ' feed to the campaign. DeleteCampaignFeed(user, campaignFeed) ' Create extension settings instead of sitelinks. CreateExtensionSetting(user, feedItems, campaignFeed.campaignId, feedItemIds, platformRestrictions) ' Mark the sitelinks from the feed for deletion. allFeedItemsToDelete.UnionWith(feedItemIds) End If Next ' Delete all the sitelinks from the feed. DeleteOldFeedItems(user, New List(Of Long)(allFeedItemsToDelete), feed.id) End If Next
Code examples
Refer to the following code examples in our client libraries to learn more about extension setting services.