google-adwords-api 0.14.1 → 0.14.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (184) hide show
  1. checksums.yaml +8 -8
  2. data/ChangeLog +3 -0
  3. data/examples/v201406/optimization/estimate_keyword_traffic.rb +30 -12
  4. data/examples/v201409/basic_operations/add_keywords.rb +3 -1
  5. data/examples/v201409/{advanced_operations → extensions}/add_google_my_business_location_extensions.rb +1 -1
  6. data/examples/v201409/extensions/add_site_links.rb +167 -0
  7. data/examples/v201409/{advanced_operations/add_site_links.rb → extensions/add_site_links_using_feeds.rb} +0 -0
  8. data/examples/v201409/migration/migrate_to_extension_settings.rb +365 -0
  9. data/examples/v201409/optimization/estimate_keyword_traffic.rb +30 -13
  10. data/examples/v201502/account_management/create_account.rb +92 -0
  11. data/examples/v201502/account_management/get_account_changes.rb +143 -0
  12. data/examples/v201502/account_management/get_account_hierarchy.rb +98 -0
  13. data/examples/v201502/advanced_operations/add_ad_customizer.rb +277 -0
  14. data/examples/v201502/advanced_operations/add_ad_group_bid_modifier.rb +105 -0
  15. data/examples/v201502/advanced_operations/add_click_to_download_ad.rb +137 -0
  16. data/examples/v201502/advanced_operations/add_text_ad_with_upgraded_urls.rb +137 -0
  17. data/examples/v201502/advanced_operations/create_and_attach_shared_keyword_set.rb +137 -0
  18. data/examples/v201502/advanced_operations/find_and_remove_criteria_from_shared_set.rb +171 -0
  19. data/examples/v201502/advanced_operations/get_ad_group_bid_modifiers.rb +106 -0
  20. data/examples/v201502/advanced_operations/upload_offline_conversions.rb +117 -0
  21. data/examples/v201502/advanced_operations/use_shared_bidding_strategy.rb +152 -0
  22. data/examples/v201502/basic_operations/add_ad_groups.rb +144 -0
  23. data/examples/v201502/basic_operations/add_campaigns.rb +143 -0
  24. data/examples/v201502/basic_operations/add_keywords.rb +118 -0
  25. data/examples/v201502/basic_operations/add_text_ads.rb +113 -0
  26. data/examples/v201502/basic_operations/get_ad_groups.rb +106 -0
  27. data/examples/v201502/basic_operations/get_campaigns.rb +101 -0
  28. data/examples/v201502/basic_operations/get_campaigns_with_awql.rb +93 -0
  29. data/examples/v201502/basic_operations/get_keywords.rb +112 -0
  30. data/examples/v201502/basic_operations/get_text_ads.rb +114 -0
  31. data/examples/v201502/basic_operations/pause_ad.rb +92 -0
  32. data/examples/v201502/basic_operations/remove_ad.rb +93 -0
  33. data/examples/v201502/basic_operations/remove_ad_group.rb +89 -0
  34. data/examples/v201502/basic_operations/remove_campaign.rb +91 -0
  35. data/examples/v201502/basic_operations/remove_keyword.rb +98 -0
  36. data/examples/v201502/basic_operations/update_ad_group.rb +89 -0
  37. data/examples/v201502/basic_operations/update_campaign.rb +90 -0
  38. data/examples/v201502/basic_operations/update_keyword.rb +110 -0
  39. data/examples/v201502/campaign_management/add_campaign_labels.rb +86 -0
  40. data/examples/v201502/campaign_management/add_experiment.rb +166 -0
  41. data/examples/v201502/campaign_management/add_keywords_in_bulk.rb +158 -0
  42. data/examples/v201502/campaign_management/add_location_extension.rb +125 -0
  43. data/examples/v201502/campaign_management/get_all_disapproved_ads.rb +101 -0
  44. data/examples/v201502/campaign_management/get_all_disapproved_ads_with_awql.rb +93 -0
  45. data/examples/v201502/campaign_management/get_campaigns_by_label.rb +112 -0
  46. data/examples/v201502/campaign_management/promote_experiment.rb +85 -0
  47. data/examples/v201502/campaign_management/set_ad_parameters.rb +122 -0
  48. data/examples/v201502/campaign_management/set_criterion_bid_modifier.rb +108 -0
  49. data/examples/v201502/campaign_management/validate_text_ad.rb +114 -0
  50. data/examples/v201502/error_handling/handle_captcha_challenge.rb +93 -0
  51. data/examples/v201502/error_handling/handle_partial_failures.rb +134 -0
  52. data/examples/v201502/error_handling/handle_policy_violation_error.rb +145 -0
  53. data/examples/v201502/error_handling/handle_two_factor_authorization_error.rb +88 -0
  54. data/examples/v201502/extensions/add_google_my_business_location_extensions.rb +183 -0
  55. data/examples/v201502/extensions/add_site_links.rb +167 -0
  56. data/examples/v201502/extensions/add_site_links_using_feeds.rb +306 -0
  57. data/examples/v201502/migration/migrate_to_extension_settings.rb +365 -0
  58. data/examples/v201502/migration/upgrade_ad_url.rb +97 -0
  59. data/examples/v201502/misc/create_ad_words_session_without_properties_file.rb +94 -0
  60. data/examples/v201502/misc/get_all_images_and_videos.rb +108 -0
  61. data/examples/v201502/misc/setup_oauth2.rb +88 -0
  62. data/examples/v201502/misc/upload_image.rb +97 -0
  63. data/examples/v201502/misc/use_oauth2_jwt.rb +97 -0
  64. data/examples/v201502/optimization/estimate_keyword_traffic.rb +155 -0
  65. data/examples/v201502/optimization/get_keyword_bid_simulations.rb +99 -0
  66. data/examples/v201502/optimization/get_keyword_ideas.rb +130 -0
  67. data/examples/v201502/remarketing/add_audience.rb +122 -0
  68. data/examples/v201502/remarketing/add_conversion_tracker.rb +105 -0
  69. data/examples/v201502/remarketing/add_rule_based_user_lists.rb +171 -0
  70. data/examples/v201502/reporting/download_criteria_report.rb +87 -0
  71. data/examples/v201502/reporting/download_criteria_report_with_awql.rb +86 -0
  72. data/examples/v201502/reporting/get_report_fields.rb +79 -0
  73. data/examples/v201502/reporting/parallel_report_download.rb +168 -0
  74. data/examples/v201502/shopping_campaigns/add_product_partition_tree.rb +269 -0
  75. data/examples/v201502/shopping_campaigns/add_product_scope.rb +133 -0
  76. data/examples/v201502/shopping_campaigns/add_shopping_campaign.rb +133 -0
  77. data/examples/v201502/shopping_campaigns/get_product_category_taxonomy.rb +117 -0
  78. data/examples/v201502/targeting/add_campaign_targeting_criteria.rb +173 -0
  79. data/examples/v201502/targeting/add_demographic_targeting_criteria.rb +116 -0
  80. data/examples/v201502/targeting/get_campaign_targeting_criteria.rb +110 -0
  81. data/examples/v201502/targeting/get_targetable_languages_and_carriers.rb +94 -0
  82. data/examples/v201502/targeting/lookup_location.rb +112 -0
  83. data/lib/adwords_api/api_config.rb +98 -4
  84. data/lib/adwords_api/v201409/ad_customizer_feed_service.rb +38 -0
  85. data/lib/adwords_api/v201409/ad_customizer_feed_service_registry.rb +46 -0
  86. data/lib/adwords_api/v201409/ad_group_extension_setting_service.rb +42 -0
  87. data/lib/adwords_api/v201409/ad_group_extension_setting_service_registry.rb +46 -0
  88. data/lib/adwords_api/v201409/campaign_extension_setting_service.rb +42 -0
  89. data/lib/adwords_api/v201409/campaign_extension_setting_service_registry.rb +46 -0
  90. data/lib/adwords_api/v201409/customer_extension_setting_service.rb +42 -0
  91. data/lib/adwords_api/v201409/customer_extension_setting_service_registry.rb +46 -0
  92. data/lib/adwords_api/v201502/account_label_service.rb +38 -0
  93. data/lib/adwords_api/v201502/account_label_service_registry.rb +46 -0
  94. data/lib/adwords_api/v201502/ad_customizer_feed_service.rb +38 -0
  95. data/lib/adwords_api/v201502/ad_customizer_feed_service_registry.rb +46 -0
  96. data/lib/adwords_api/v201502/ad_group_ad_service.rb +50 -0
  97. data/lib/adwords_api/v201502/ad_group_ad_service_registry.rb +46 -0
  98. data/lib/adwords_api/v201502/ad_group_bid_modifier_service.rb +42 -0
  99. data/lib/adwords_api/v201502/ad_group_bid_modifier_service_registry.rb +46 -0
  100. data/lib/adwords_api/v201502/ad_group_criterion_service.rb +46 -0
  101. data/lib/adwords_api/v201502/ad_group_criterion_service_registry.rb +46 -0
  102. data/lib/adwords_api/v201502/ad_group_extension_setting_service.rb +42 -0
  103. data/lib/adwords_api/v201502/ad_group_extension_setting_service_registry.rb +46 -0
  104. data/lib/adwords_api/v201502/ad_group_feed_service.rb +42 -0
  105. data/lib/adwords_api/v201502/ad_group_feed_service_registry.rb +46 -0
  106. data/lib/adwords_api/v201502/ad_group_service.rb +46 -0
  107. data/lib/adwords_api/v201502/ad_group_service_registry.rb +46 -0
  108. data/lib/adwords_api/v201502/ad_param_service.rb +38 -0
  109. data/lib/adwords_api/v201502/ad_param_service_registry.rb +46 -0
  110. data/lib/adwords_api/v201502/adwords_user_list_service.rb +38 -0
  111. data/lib/adwords_api/v201502/adwords_user_list_service_registry.rb +46 -0
  112. data/lib/adwords_api/v201502/bidding_strategy_service.rb +42 -0
  113. data/lib/adwords_api/v201502/bidding_strategy_service_registry.rb +46 -0
  114. data/lib/adwords_api/v201502/budget_order_service.rb +42 -0
  115. data/lib/adwords_api/v201502/budget_order_service_registry.rb +46 -0
  116. data/lib/adwords_api/v201502/budget_service.rb +42 -0
  117. data/lib/adwords_api/v201502/budget_service_registry.rb +46 -0
  118. data/lib/adwords_api/v201502/campaign_criterion_service.rb +42 -0
  119. data/lib/adwords_api/v201502/campaign_criterion_service_registry.rb +46 -0
  120. data/lib/adwords_api/v201502/campaign_extension_setting_service.rb +42 -0
  121. data/lib/adwords_api/v201502/campaign_extension_setting_service_registry.rb +46 -0
  122. data/lib/adwords_api/v201502/campaign_feed_service.rb +42 -0
  123. data/lib/adwords_api/v201502/campaign_feed_service_registry.rb +46 -0
  124. data/lib/adwords_api/v201502/campaign_service.rb +46 -0
  125. data/lib/adwords_api/v201502/campaign_service_registry.rb +46 -0
  126. data/lib/adwords_api/v201502/campaign_shared_set_service.rb +38 -0
  127. data/lib/adwords_api/v201502/campaign_shared_set_service_registry.rb +46 -0
  128. data/lib/adwords_api/v201502/constant_data_service.rb +66 -0
  129. data/lib/adwords_api/v201502/constant_data_service_registry.rb +46 -0
  130. data/lib/adwords_api/v201502/conversion_tracker_service.rb +42 -0
  131. data/lib/adwords_api/v201502/conversion_tracker_service_registry.rb +46 -0
  132. data/lib/adwords_api/v201502/customer_extension_setting_service.rb +42 -0
  133. data/lib/adwords_api/v201502/customer_extension_setting_service_registry.rb +46 -0
  134. data/lib/adwords_api/v201502/customer_feed_service.rb +42 -0
  135. data/lib/adwords_api/v201502/customer_feed_service_registry.rb +46 -0
  136. data/lib/adwords_api/v201502/customer_service.rb +38 -0
  137. data/lib/adwords_api/v201502/customer_service_registry.rb +46 -0
  138. data/lib/adwords_api/v201502/customer_sync_service.rb +34 -0
  139. data/lib/adwords_api/v201502/customer_sync_service_registry.rb +47 -0
  140. data/lib/adwords_api/v201502/data_service.rb +54 -0
  141. data/lib/adwords_api/v201502/data_service_registry.rb +46 -0
  142. data/lib/adwords_api/v201502/experiment_service.rb +38 -0
  143. data/lib/adwords_api/v201502/experiment_service_registry.rb +46 -0
  144. data/lib/adwords_api/v201502/feed_item_service.rb +42 -0
  145. data/lib/adwords_api/v201502/feed_item_service_registry.rb +46 -0
  146. data/lib/adwords_api/v201502/feed_mapping_service.rb +42 -0
  147. data/lib/adwords_api/v201502/feed_mapping_service_registry.rb +46 -0
  148. data/lib/adwords_api/v201502/feed_service.rb +42 -0
  149. data/lib/adwords_api/v201502/feed_service_registry.rb +46 -0
  150. data/lib/adwords_api/v201502/geo_location_service.rb +34 -0
  151. data/lib/adwords_api/v201502/geo_location_service_registry.rb +46 -0
  152. data/lib/adwords_api/v201502/label_service.rb +42 -0
  153. data/lib/adwords_api/v201502/label_service_registry.rb +46 -0
  154. data/lib/adwords_api/v201502/location_criterion_service.rb +38 -0
  155. data/lib/adwords_api/v201502/location_criterion_service_registry.rb +46 -0
  156. data/lib/adwords_api/v201502/managed_customer_service.rb +54 -0
  157. data/lib/adwords_api/v201502/managed_customer_service_registry.rb +46 -0
  158. data/lib/adwords_api/v201502/media_service.rb +42 -0
  159. data/lib/adwords_api/v201502/media_service_registry.rb +46 -0
  160. data/lib/adwords_api/v201502/mutate_job_service.rb +42 -0
  161. data/lib/adwords_api/v201502/mutate_job_service_registry.rb +46 -0
  162. data/lib/adwords_api/v201502/offline_conversion_feed_service.rb +34 -0
  163. data/lib/adwords_api/v201502/offline_conversion_feed_service_registry.rb +46 -0
  164. data/lib/adwords_api/v201502/report_definition_service.rb +34 -0
  165. data/lib/adwords_api/v201502/report_definition_service_registry.rb +46 -0
  166. data/lib/adwords_api/v201502/shared_criterion_service.rb +38 -0
  167. data/lib/adwords_api/v201502/shared_criterion_service_registry.rb +46 -0
  168. data/lib/adwords_api/v201502/shared_set_service.rb +38 -0
  169. data/lib/adwords_api/v201502/shared_set_service_registry.rb +46 -0
  170. data/lib/adwords_api/v201502/targeting_idea_service.rb +34 -0
  171. data/lib/adwords_api/v201502/targeting_idea_service_registry.rb +46 -0
  172. data/lib/adwords_api/v201502/traffic_estimator_service.rb +34 -0
  173. data/lib/adwords_api/v201502/traffic_estimator_service_registry.rb +46 -0
  174. data/lib/adwords_api/version.rb +1 -1
  175. data/test/adwords_api/test_adwords_api.rb +1 -12
  176. data/test/templates/v201406/basic_operations_get_campaigns.def +1 -1
  177. data/test/templates/v201406/misc_use_oauth2_jwt.def +1 -1
  178. data/test/templates/v201409/basic_operations_get_campaigns.def +1 -1
  179. data/test/templates/v201409/misc_use_oauth2_jwt.def +1 -1
  180. data/test/templates/v201502/basic_operations_get_campaigns.def +114 -0
  181. data/test/templates/v201502/misc_use_oauth2_jwt.def +131 -0
  182. metadata +173 -8
  183. data/examples/v201406/advanced_operations/update_site_links.rb +0 -194
  184. data/examples/v201409/advanced_operations/update_site_links.rb +0 -194
checksums.yaml CHANGED
@@ -1,15 +1,15 @@
1
1
  ---
2
2
  !binary "U0hBMQ==":
3
3
  metadata.gz: !binary |-
4
- OTUyMDFjMzdlOGJkYmQxMjlkNzkwMjczNmM0Y2QwY2Q3YjA2MWMwNw==
4
+ YTA0OTUyODk0YzVjYmQxODJjNmE4OTRhNWM4Zjc5ZmQ1ZWIzNDVmMQ==
5
5
  data.tar.gz: !binary |-
6
- ODI5YmY2Mzc3YjYyNjk0ZDQwMzI5NjA4YWRmMTZhODc5OGIyZDAyZA==
6
+ MjQxMzZiODY5MzFkNTQ2MDAzNmM3ZGJmMmE5MWNmYjQ1YzFhMDVlMg==
7
7
  SHA512:
8
8
  metadata.gz: !binary |-
9
- NjEzMTUwZjQyNmJlMWFiMGJhYzZjZWU0MGRmYTkzMjJiMGMwZmViZjQxMDJk
10
- NWJiYmVkZmU1ZjcyZjhhYjNhY2ZkY2UxMTJkNzUwNWEyYjIyOTE3YWQzMTRk
11
- YjBhZTU5MjA2ZTMzNTEwZDkxNGY0NDA0NjVkMWRmZDUwNmQ0NzI=
9
+ NmQ5MDQzZDgxYmQwOGY3NGEwY2FiZTU4ODA5ZGQ5ZGMyZDBiZjI1ZWNjOTE5
10
+ ZTYyZTc5NTIwMmIxM2MwYzNjNjVmMmQ0M2Q4Y2YzZTg2NjA3YmY5OWIzZDlm
11
+ MjE0ZTk2N2UzMmViYTc0YTM4MTg5NWEzNmEwMDdmNjkxYTBmZjE=
12
12
  data.tar.gz: !binary |-
13
- NGMwZTdhZjA1MWY1ZDA3ZGM3N2ZmZjc2NTE2OWVmZjFmYzdkNDkyZWMwZTYw
14
- YTY1ZDFkMzZlMDk3M2E0NWNmNjFhZDk5Y2M5M2YxNzEzY2ZjN2Q5YTlmMDk2
15
- YThiNTMwYjg4MzhhOTViNWZkMDY0YjRlZTRkMjcwMTI0ZGI1NjM=
13
+ Y2UxMjAyOGM3YmMwNmRiMjVjOWY5OGExMDAyM2YyMzUzMDNlYWZiYTJmODY3
14
+ MTczNTdhNzQwZTY1Yjk3YTQwYzZjNWNiMWUzMzYwOWI2NjE5MWQ4NzQ0MzBm
15
+ ZmM1YTIxOTg2ZjkxZTA1YWQ2ODEzYzE4MTk4YTIyNjRmYjdiYjA=
data/ChangeLog CHANGED
@@ -1,3 +1,6 @@
1
+ 0.14.2:
2
+ - Support and examples for v201502.
3
+
1
4
  0.14.1:
2
5
  - Corrected the comments and settings regarding target_all in add_ad_groups
3
6
  examples.
@@ -84,27 +84,45 @@ def estimate_keyword_traffic()
84
84
  keyword = keyword_requests[index][:keyword]
85
85
 
86
86
  # Find the mean of the min and max values.
87
- mean_avg_cpc = (estimate[:min][:average_cpc][:micro_amount] +
88
- estimate[:max][:average_cpc][:micro_amount]) / 2
89
- mean_avg_position = (estimate[:min][:average_position] +
90
- estimate[:max][:average_position]) / 2
91
- mean_clicks = (estimate[:min][:clicks_per_day] +
92
- estimate[:max][:clicks_per_day]) / 2
93
- mean_total_cost = (estimate[:min][:total_cost][:micro_amount] +
94
- estimate[:max][:total_cost][:micro_amount]) / 2
87
+ mean_avg_cpc = calculate_mean(
88
+ estimate[:min][:average_cpc][:micro_amount],
89
+ estimate[:max][:average_cpc][:micro_amount]
90
+ )
91
+ mean_avg_position = calculate_mean(
92
+ estimate[:min][:average_position],
93
+ estimate[:max][:average_position])
94
+ )
95
+ mean_clicks = calculate_mean(
96
+ estimate[:min][:clicks_per_day],
97
+ estimate[:max][:clicks_per_day]
98
+ )
99
+ mean_total_cost = calculate_mean(
100
+ estimate[:min][:total_cost][:micro_amount],
101
+ estimate[:max][:total_cost][:micro_amount]
102
+ )
95
103
 
96
104
  puts "Results for the keyword with text '%s' and match type %s:" %
97
105
  [keyword[:text], keyword[:match_type]]
98
- puts "\tEstimated average CPC: %d" % mean_avg_cpc
99
- puts "\tEstimated ad position: %.2f" % mean_avg_position
100
- puts "\tEstimated daily clicks: %d" % mean_clicks
101
- puts "\tEstimated daily cost: %d" % mean_total_cost
106
+ puts "\tEstimated average CPC: %s" % format_mean(mean_avg_cpc)
107
+ puts "\tEstimated ad position: %s" % format_mean(mean_avg_position)
108
+ puts "\tEstimated daily clicks: %s" % format_mean(mean_clicks)
109
+ puts "\tEstimated daily cost: %s" % format_mean(mean_total_cost)
102
110
  end
103
111
  else
104
112
  puts 'No traffic estimates were returned.'
105
113
  end
106
114
  end
107
115
 
116
+ def format_mean(mean)
117
+ return "nil" if mean.nil?
118
+ return "%.2f" % mean
119
+ end
120
+
121
+ def calculate_mean(min_money, max_money)
122
+ return nil if min_money.nil? || max_money.nil?
123
+ return (min_money.to_f + max_money.to_f) / 2.0
124
+ end
125
+
108
126
  if __FILE__ == $0
109
127
  API_VERSION = :v201406
110
128
 
@@ -51,7 +51,9 @@ def add_keywords(ad_group_id)
51
51
  },
52
52
  # Optional fields:
53
53
  :user_status => 'PAUSED',
54
- :final_urls => ['http://example.com/mars']
54
+ :final_urls => {
55
+ :urls => ['http://example.com/mars']
56
+ }
55
57
  },
56
58
  {:xsi_type => 'BiddableAdGroupCriterion',
57
59
  :ad_group_id => ad_group_id,
@@ -81,7 +81,7 @@ def add_gmb_location_extensions(gmb_email_address, gmb_access_token,
81
81
  :matching_function => {
82
82
  :operator => 'IDENTITY',
83
83
  :lhsOperand => {
84
- :xsi_type => 'FunctionArgumentOperand',
84
+ :xsi_type => 'ConstantOperand',
85
85
  :type => 'BOOLEAN',
86
86
  :boolean_value => true
87
87
  }
@@ -0,0 +1,167 @@
1
+ #!/usr/bin/env ruby
2
+ # Encoding: utf-8
3
+ #
4
+ # Author:: api.mcloonan@gmail.com (Michael Cloonan)
5
+ #
6
+ # Copyright:: Copyright 2015, Google Inc. All Rights Reserved.
7
+ #
8
+ # License:: Licensed under the Apache License, Version 2.0 (the "License");
9
+ # you may not use this file except in compliance with the License.
10
+ # You may obtain a copy of the License at
11
+ #
12
+ # http://www.apache.org/licenses/LICENSE-2.0
13
+ #
14
+ # Unless required by applicable law or agreed to in writing, software
15
+ # distributed under the License is distributed on an "AS IS" BASIS,
16
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
17
+ # implied.
18
+ # See the License for the specific language governing permissions and
19
+ # limitations under the License.
20
+ #
21
+ # This example adds a sitelinks feed and associates it with a campaign.
22
+ #
23
+ # Tags: CampaignExtensionSettingService.mutate
24
+
25
+ require 'adwords_api'
26
+ require 'date'
27
+
28
+ def add_site_links(campaign_id)
29
+ # AdwordsApi::Api will read a config file from ENV['HOME']/adwords_api.yml
30
+ # when called without parameters.
31
+ adwords = AdwordsApi::Api.new
32
+
33
+ # To enable logging of SOAP requests, set the log_level value to 'DEBUG' in
34
+ # the configuration file or provide your own logger:
35
+ # adwords.logger = Logger.new('adwords_xml.log')
36
+
37
+ customer_srv = adwords.service(:CustomerService, API_VERSION)
38
+ customer = customer_srv.get()
39
+ customer_time_zone = customer[:date_time_zone]
40
+
41
+ campaign_extension_setting_srv =
42
+ adwords.service(:CampaignExtensionSettingService, API_VERSION)
43
+
44
+ sitelink_1 = {
45
+ :xsi_type => "SitelinkFeedItem",
46
+ :sitelink_text => "Store Hours",
47
+ :sitelink_url => "http://www.example.com/storehours"
48
+ }
49
+
50
+ sitelink_2 = {
51
+ :xsi_type => "SitelinkFeedItem",
52
+ :sitelink_text => "Thanksgiving Specials",
53
+ :sitelink_url => "http://www.example.com/thanksgiving",
54
+ :start_time => DateTime.new(Date.today.year, 11, 20, 0, 0, 0).
55
+ strftime("%Y%m%d %H%M%S ") + customer_time_zone,
56
+ :end_time => DateTime.new(Date.today.year, 11, 27, 23, 59, 59).
57
+ strftime("%Y%m%d %H%M%S ") + customer_time_zone
58
+ }
59
+
60
+ sitelink_3 = {
61
+ :xsi_type => "SitelinkFeedItem",
62
+ :sitelink_text => "Wifi available",
63
+ :sitelink_url => "http://www.example.com/mobile/wifi",
64
+ :device_preference => {:device_preference => 30001}
65
+ }
66
+
67
+ sitelink_4 = {
68
+ :xsi_type => "SitelinkFeedItem",
69
+ :sitelink_text => "Happy hours",
70
+ :sitelink_url => "http://www.example.com/happyhours",
71
+ :scheduling => {
72
+ :feed_item_schedules => [
73
+ {
74
+ :day_of_week => 'MONDAY',
75
+ :start_hour => 18,
76
+ :start_minute => 'ZERO',
77
+ :end_hour => 21,
78
+ :end_minute => 'ZERO'
79
+ },
80
+ {
81
+ :day_of_week => 'TUESDAY',
82
+ :start_hour => 18,
83
+ :start_minute => 'ZERO',
84
+ :end_hour => 21,
85
+ :end_minute => 'ZERO'
86
+ },
87
+ {
88
+ :day_of_week => 'WEDNESDAY',
89
+ :start_hour => 18,
90
+ :start_minute => 'ZERO',
91
+ :end_hour => 21,
92
+ :end_minute => 'ZERO'
93
+ },
94
+ {
95
+ :day_of_week => 'THURSDAY',
96
+ :start_hour => 18,
97
+ :start_minute => 'ZERO',
98
+ :end_hour => 21,
99
+ :end_minute => 'ZERO'
100
+ },
101
+ {
102
+ :day_of_week => 'FRIDAY',
103
+ :start_hour => 18,
104
+ :start_minute => 'ZERO',
105
+ :end_hour => 21,
106
+ :end_minute => 'ZERO'
107
+ }
108
+ ]
109
+ }
110
+ }
111
+
112
+ campaign_extension_setting = {
113
+ :campaign_id => campaign_id,
114
+ :extension_type => 'SITELINK',
115
+ :extension_setting => {
116
+ :extensions => [sitelink_1, sitelink_2, sitelink_3, sitelink_4]
117
+ }
118
+ }
119
+
120
+ operation = {
121
+ :operand => campaign_extension_setting,
122
+ :operator => 'ADD'
123
+ }
124
+
125
+ response = campaign_extension_setting_srv.mutate([operation])
126
+ if response and response[:value]
127
+ new_extension_setting = response[:value].first
128
+ puts "Extension setting wiht type = %s was added to campaign ID %d" %
129
+ [new_extension_setting[:extension_type][:value],
130
+ new_extension_setting[:campaign_id]]
131
+ elsif
132
+ puts "No extension settings were created."
133
+ end
134
+ end
135
+
136
+ if __FILE__ == $0
137
+ API_VERSION = :v201409
138
+
139
+ begin
140
+ # Campaign ID to add site link to.
141
+ campaign_id = 'INSERT_CAMPAIGN_ID_HERE'.to_i
142
+ add_site_links(campaign_id)
143
+
144
+ # Authorization error.
145
+ rescue AdsCommon::Errors::OAuth2VerificationRequired => e
146
+ puts "Authorization credentials are not valid. Edit adwords_api.yml for " +
147
+ "OAuth2 client ID and secret and run misc/setup_oauth2.rb example " +
148
+ "to retrieve and store OAuth2 tokens."
149
+ puts "See this wiki page for more details:\n\n " +
150
+ 'http://code.google.com/p/google-api-ads-ruby/wiki/OAuth2'
151
+
152
+ # HTTP errors.
153
+ rescue AdsCommon::Errors::HttpError => e
154
+ puts "HTTP Error: %s" % e
155
+
156
+ # API errors.
157
+ rescue AdwordsApi::Errors::ApiException => e
158
+ puts "Message: %s" % e.message
159
+ puts 'Errors:'
160
+ e.errors.each_with_index do |error, index|
161
+ puts "\tError [%d]:" % (index + 1)
162
+ error.each do |field, value|
163
+ puts "\t\t%s: %s" % [field, value]
164
+ end
165
+ end
166
+ end
167
+ end
@@ -0,0 +1,365 @@
1
+ #!/usr/bin/env ruby
2
+ # Encoding: utf-8
3
+ #
4
+ # Author:: api.mcloonan@gmail.com (Michael Cloonan)
5
+ #
6
+ # Copyright:: Copyright 2015, Google Inc. All Rights Reserved.
7
+ #
8
+ # License:: Licensed under the Apache License, Version 2.0 (the "License");
9
+ # you may not use this file except in compliance with the License.
10
+ # You may obtain a copy of the License at
11
+ #
12
+ # http://www.apache.org/licenses/LICENSE-2.0
13
+ #
14
+ # Unless required by applicable law or agreed to in writing, software
15
+ # distributed under the License is distributed on an "AS IS" BASIS,
16
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
17
+ # implied.
18
+ # See the License for the specific language governing permissions and
19
+ # limitations under the License.
20
+ #
21
+ # This example migrates your feed based sitelinks at campaign level to use
22
+ # extension settings. To learn more about extensionsettings, see
23
+ # https://developers.google.com/adwords/api/docs/guides/extension-settings.
24
+ # To learn more about migrating Feed based extensions to extension settings,
25
+ # see
26
+ # https://developers.google.com/adwords/api/docs/guides/migrate-to-extension-settings.
27
+ #
28
+ # Tags: FeedService.query, FeedMappingService.query, FeedItemService.query
29
+ # Tags: CampaignExtensionSettingService.mutate, CampaignFeedService.query
30
+ # Tags: CampaignFeedService.mutate
31
+
32
+ require 'adwords_api'
33
+ require 'set'
34
+
35
+ def migrate_to_extension_settings()
36
+ # AdwordsApi::Api will read a config file from ENV['HOME']/adwords_api.yml
37
+ # when called without parameters.
38
+ adwords = AdwordsApi::Api.new
39
+
40
+ # To enable logging of SOAP requests, set the log_level value to 'DEBUG' in
41
+ # the configuration file or provide your own logger:
42
+ # adwords.logger = Logger.new('adwords_xml.log')
43
+
44
+ # Get all of the feeds for the current user.
45
+ feeds = get_feeds(adwords)
46
+
47
+ feeds.each do |feed|
48
+ # Retrieve all the sitelinks from the current feed.
49
+ feed_items = get_site_links_from_feed(adwords, feed)
50
+
51
+ # Get all the instances where a sitelink from this feed has been added
52
+ # to a campaign.
53
+ campaign_feeds = get_campaign_feeds(adwords, feed, PLACEHOLDER_SITELINKS)
54
+
55
+ all_feed_items_to_delete = campaign_feeds.map do |campaign_feed|
56
+ # Retrieve the sitelinks that have been associated with this campaign.
57
+ feed_item_ids = get_feed_item_ids_for_campaign(campaign_feed)
58
+
59
+ if feed_item_ids.empty?
60
+ puts("Migration skipped for campaign feed with campaign ID %d " +
61
+ "and feed ID %d because no mapped feed item IDs were found in " +
62
+ "the campaign feed's matching function.") %
63
+ [campaign_feed[:campaign_id], campaign_feed[:feed_id]]
64
+ next
65
+ end
66
+
67
+ # Delete the campaign feed that associates the sitelinks from the
68
+ # feed to the campaign.
69
+ delete_campaign_feed(adwords, campaign_feed)
70
+
71
+ # Create extension settings instead of sitelinks.
72
+ create_extension_setting(adwords, feed_items, campaign_feed,
73
+ feed_item_ids)
74
+
75
+ # Mark the sitelinks from the feed for deletion.
76
+ feed_item_ids
77
+ end.flatten.to_set
78
+
79
+ # Delete all the sitelinks from the feed.
80
+ delete_old_feed_items(adwords, all_feed_items_to_delete, feed)
81
+ end
82
+ end
83
+
84
+ def get_site_links_from_feed(adwords, feed)
85
+ # Retrieve the feed's attribute mapping.
86
+ feed_mappings = get_feed_mapping(adwords, feed, PLACEHOLDER_SITELINKS)
87
+
88
+ feed_items = {}
89
+
90
+ get_feed_items(adwords, feed).each do |feed_item|
91
+ site_link_from_feed = {}
92
+
93
+ feed_item[:attribute_values].each do |attribute_value|
94
+ # Skip this attribute if it hasn't been mapped to a field.
95
+ next unless feed_mappings.has_key?(
96
+ attribute_value[:feed_attribute_id])
97
+
98
+ feed_mappings[attribute_value[:feed_attribute_id]].each do |field_id|
99
+ case field_id
100
+ when PLACEHOLDER_FIELD_SITELINK_LINK_TEXT
101
+ site_link_from_feed[:text] = attribute_value[:string_value]
102
+ when PLACEHOLDER_FIELD_SITELINK_URL
103
+ site_link_from_feed[:url] = attribute_value[:string_value]
104
+ when PLACEHOLDER_FIELD_FINAL_URLS
105
+ site_link_from_feed[:final_urls] = attribute_value[:string_values]
106
+ when PLACEHOLDER_FIELD_FINAL_MOBILE_URLS
107
+ site_link_from_feed[:final_mobile_urls] =
108
+ attribute_value[:string_values]
109
+ when PLACEHOLDER_FIELD_TRACKING_URL_TEMPLATE
110
+ site_link_from_feed[:tracking_url_template] =
111
+ attribute_value[:string_value]
112
+ when PLACEHOLDER_FIELD_LINE_2_TEXT
113
+ site_link_from_feed[:line2] = attribute_value[:string_value]
114
+ when PLACEHOLDER_FIELD_LINE_3_TEXT
115
+ site_link_from_feed[:line3] = attribute_value[:string_value]
116
+ end
117
+ end
118
+ end
119
+ site_link_from_feed[:scheduling] = feed_item[:scheduling]
120
+
121
+ feed_items[feed_item[:feed_item_id]] = site_link_from_feed
122
+ end
123
+ return feed_items
124
+ end
125
+
126
+ def get_feed_mapping(adwords, feed, placeholder_type)
127
+ feed_mapping_srv = adwords.service(:FeedMappingService, API_VERSION)
128
+ query = ("SELECT FeedMappingId, AttributeFieldMappings " +
129
+ "WHERE FeedId = %d AND PlaceholderType = %d AND Status = 'ENABLED'") %
130
+ [feed[:id], placeholder_type]
131
+
132
+ attribute_mappings = {}
133
+ offset = 0
134
+
135
+ begin
136
+ page_query = (query + " LIMIT %d, %d") % [offset, PAGE_SIZE]
137
+ page = feed_mapping_srv.query(page_query)
138
+
139
+ unless page[:entries].nil?
140
+ # Normally, a feed attribute is mapped only to one field. However, you
141
+ # may map it to more than one field if needed.
142
+ page[:entries].each do |feed_mapping|
143
+ feed_mapping[:attribute_field_mappings].each do |attribute_mapping|
144
+ # Since attribute_mappings can have multiple values for each key,
145
+ # we set up an array to store the values.
146
+ if attribute_mappings.has_key?(attribute_mapping[:feed_attribute_id])
147
+ attribute_mappings[attribute_mapping[:feed_attribute_id]] <<
148
+ attribute_mapping[:field_id]
149
+ else
150
+ attribute_mappings[attribute_mapping[:feed_attribute_id]] =
151
+ [attribute_mapping[:field_id]]
152
+ end
153
+ end
154
+ end
155
+ end
156
+ offset += PAGE_SIZE
157
+ end while page[:total_num_entries] > offset
158
+
159
+ return attribute_mappings
160
+ end
161
+
162
+ def get_feeds(adwords)
163
+ feed_srv = adwords.service(:FeedService, API_VERSION)
164
+ query = "SELECT Id, Name, Attributes " +
165
+ "WHERE Origin = 'USER' AND FeedStatus = 'ENABLED'"
166
+
167
+ feeds = []
168
+ offset = 0
169
+
170
+ begin
171
+ page_query = (query + " LIMIT %d, %d") % [offset, PAGE_SIZE]
172
+ page = feed_srv.query(page_query)
173
+
174
+ unless page[:entries].nil?
175
+ feeds += page[:entries]
176
+ end
177
+ offset += PAGE_SIZE
178
+ end while page[:total_num_entries] > offset
179
+
180
+ return feeds
181
+ end
182
+
183
+ def get_feed_items(adwords, feed)
184
+ feed_item_srv = adwords.service(:FeedItemService, API_VERSION)
185
+ query = ("SELECT FeedItemId, AttributeValues, Scheduling " +
186
+ "WHERE Status = 'ENABLED' AND FeedId = %d") % feed[:id]
187
+
188
+ feed_items = []
189
+ offset = 0
190
+
191
+ begin
192
+ page_query = (query + " LIMIT %d, %d") % [offset, PAGE_SIZE]
193
+ page = feed_item_srv.query(page_query)
194
+
195
+ unless page[:entries].nil?
196
+ feed_items += page[:entries]
197
+ end
198
+ offset += PAGE_SIZE
199
+ end while page[:total_num_entries] > offset
200
+
201
+ return feed_items
202
+ end
203
+
204
+ def delete_old_feed_items(adwords, feed_item_ids, feed)
205
+ return if feed_item_ids.empty?
206
+
207
+ feed_item_srv = adwords.service(:FeedItemService, API_VERSION)
208
+
209
+ operations = feed_item_ids.map do |feed_item_id|
210
+ {
211
+ :operator => 'REMOVE',
212
+ :operand => {
213
+ :feed_id => feed[:id],
214
+ :feed_item_id => feed_item_id
215
+ }
216
+ }
217
+ end
218
+
219
+ feed_item_srv.mutate(operations)
220
+ end
221
+
222
+ def create_extension_setting(adwords, feed_items, campaign_feed, feed_item_ids)
223
+ campaign_extension_setting_srv = adwords.service(
224
+ :CampaignExtensionSettingService, API_VERSION)
225
+
226
+ extension_feed_items = feed_item_ids.map do |feed_item_id|
227
+ site_link_from_feed = feed_items[:feed_item_id]
228
+ site_link_feed_item = {
229
+ :sitelink_text => site_link_from_feed[:text],
230
+ :sitelink_line2 => site_link_from_feed[:line2],
231
+ :sitelink_line3 => site_link_from_feed[:line3],
232
+ :scheduling => site_link_from_feed[:scheduling]
233
+ }
234
+ if !site_link_from_feed.final_urls.nil? &&
235
+ site_link_from_feed[:final_urls].length > 0
236
+ site_link_feed_item[:sitelink_final_urls] = {
237
+ :urls => site_link_from_feed[:final_urls]
238
+ }
239
+ unless site_link_from_feed[:final_mobile_urls].nil?
240
+ site_link_feed_item[:sitelink_final_mobile_urls] = {
241
+ :urls => site_link_from_feed[:final_mobile_urls]
242
+ }
243
+ end
244
+ site_link_feed_item[:sitelink_tracking_url_template] =
245
+ site_link_from_feed[:tracking_url_template]
246
+ else
247
+ site_link_feed_item[:sitelink_url] = site_link_from_feed[:url]
248
+ end
249
+
250
+ site_link_feed_item
251
+ end
252
+
253
+ extension_setting = {
254
+ :extensions => extension_feed_items
255
+ }
256
+
257
+ campaign_extension_setting = {
258
+ :campaign_id => campaign_feed[:campaign_id],
259
+ :extension_type => 'SITELINK',
260
+ :extension_setting => extension_setting
261
+ }
262
+
263
+ operation = {
264
+ :operand => campaign_extension_setting,
265
+ :operator => 'ADD'
266
+ }
267
+
268
+ campaign_extension_setting_srv.mutate([operation])
269
+ end
270
+
271
+ def delete_campaign_feed(adwords, campaign_feed)
272
+ campaign_feed_srv = adwords.service(:CampaignFeedService, API_VERSION)
273
+
274
+ operation = {
275
+ :operand => campaign_feed,
276
+ :operator => 'REMOVE'
277
+ }
278
+
279
+ campaign_feed_srv.mutate([operation])
280
+ end
281
+
282
+ def get_feed_item_ids_for_campaign(campaign_feed)
283
+ feed_item_ids = Set.new
284
+ if !campaign_feed[:matching_function][:lhs_operand].empty? &&
285
+ campaign_feed[:matching_function][:lhs_operand].first[:xsi_type] ==
286
+ 'RequestContextOperand'
287
+ request_context_operand =
288
+ campaign_feed[:matching_function][:lhs_operand].first
289
+ if request_context_operand[:context_type] == 'FEED_ITEM_ID' &&
290
+ campaign_feed[:matching_function][:operator] == 'IN'
291
+ campaign_feed[:matching_function][:rhs_operand].each do |argument|
292
+ if argument[:xsi_type] == 'ConstantOperand'
293
+ feed_item_ids.add(argument[:long_value])
294
+ end
295
+ end
296
+ end
297
+ end
298
+ return feed_item_ids
299
+ end
300
+
301
+ def get_campaign_feeds(adwords, feed, placeholder_type)
302
+ campaign_feed_srv = adwords.service(:CampaignFeedService, API_VERSION)
303
+ query = ("SELECT CampaignId, MatchingFunction, PlaceholderTypes " +
304
+ "WHERE Status = 'ENABLED' AND FeedId = %d " +
305
+ "AND PlaceholderTypes CONTAINS_ANY [%d]") % [feed[:id], placeholder_type]
306
+
307
+ campaign_feeds = []
308
+ offset = 0
309
+
310
+ begin
311
+ page_query = (query + " LIMIT %d, %d") % [offset, PAGE_SIZE]
312
+ page = campaign_feed_srv.query(page_query)
313
+
314
+ unless page[:entries].nil?
315
+ campaign_feeds += page[:entries]
316
+ end
317
+ offset += PAGE_SIZE
318
+ end while page[:total_num_entries] > offset
319
+
320
+ return campaign_feeds
321
+ end
322
+
323
+ if __FILE__ == $0
324
+ API_VERSION = :v201409
325
+ PAGE_SIZE = 500
326
+
327
+ # See the Placeholder reference page for a liste of all placeholder types
328
+ # and fields.
329
+ # https://developers.google.com/adwords/api/docs/appendix/placeholders
330
+ PLACEHOLDER_SITELINKS = 1
331
+ PLACEHOLDER_FIELD_SITELINK_LINK_TEXT = 1
332
+ PLACEHOLDER_FIELD_SITELINK_URL = 2
333
+ PLACEHOLDER_FIELD_LINE_2_TEXT = 3
334
+ PLACEHOLDER_FIELD_LINE_3_TEXT = 4
335
+ PLACEHOLDER_FIELD_FINAL_URLS = 5
336
+ PLACEHOLDER_FIELD_FINAL_MOBILE_URLS = 6
337
+ PLACEHOLDER_FIELD_TRACKING_URL_TEMPLATE = 7
338
+
339
+ begin
340
+ migrate_to_extension_settings()
341
+
342
+ # Authorization error.
343
+ rescue AdsCommon::Errors::OAuth2VerificationRequired => e
344
+ puts "Authorization credentials are not valid. Edit adwords_api.yml for " +
345
+ "OAuth2 client ID and secret and run misc/setup_oauth2.rb example " +
346
+ "to retrieve and store OAuth2 tokens."
347
+ puts "See this wiki page for more details:\n\n " +
348
+ 'http://code.google.com/p/google-api-ads-ruby/wiki/OAuth2'
349
+
350
+ # HTTP errors.
351
+ rescue AdsCommon::Errors::HttpError => e
352
+ puts "HTTP Error: %s" % e
353
+
354
+ # API errors.
355
+ rescue AdwordsApi::Errors::ApiException => e
356
+ puts "Message: %s" % e.message
357
+ puts 'Errors:'
358
+ e.errors.each_with_index do |error, index|
359
+ puts "\tError [%d]:" % (index + 1)
360
+ error.each do |field, value|
361
+ puts "\t\t%s: %s" % [field, value]
362
+ end
363
+ end
364
+ end
365
+ end