google-adwords-api 0.14.1 → 0.14.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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